summaryrefslogtreecommitdiffstats
path: root/sys/cam/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1999-03-05 23:25:11 +0000
committergibbs <gibbs@FreeBSD.org>1999-03-05 23:25:11 +0000
commit4a87f499af9e8def8981078d2bf249ba6fb8cb05 (patch)
treef349bba965b7dba497fe33e8a0b4557580de76ea /sys/cam/scsi
parent5548cbedbee42e4319658049ec6f659139782ae4 (diff)
downloadFreeBSD-src-4a87f499af9e8def8981078d2bf249ba6fb8cb05.zip
FreeBSD-src-4a87f499af9e8def8981078d2bf249ba6fb8cb05.tar.gz
Implement the control device for the "targ" target mode processor target
emulator so that instances can be dynamically added and removed from the system. Properly reference count peripheral instances so they are cleaned up when destroyed by the control device. Set a timeout for test unit ready commands. Before it was uninitialized and could cause us to drop off the bus when no real timeout had occurred.
Diffstat (limited to 'sys/cam/scsi')
-rw-r--r--sys/cam/scsi/scsi_target.c319
-rw-r--r--sys/cam/scsi/scsi_targetio.h18
2 files changed, 256 insertions, 81 deletions
diff --git a/sys/cam/scsi/scsi_target.c b/sys/cam/scsi/scsi_target.c
index a4f6092..66028f1 100644
--- a/sys/cam/scsi/scsi_target.c
+++ b/sys/cam/scsi/scsi_target.c
@@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_target.c,v 1.7 1999/01/14 05:57:32 gibbs Exp $
+ * $Id: scsi_target.c,v 1.8 1999/02/11 07:08:58 gibbs Exp $
*/
#include <stddef.h> /* For offsetof */
@@ -80,6 +80,9 @@ typedef enum {
#define MIN(a, b) ((a > b) ? b : a)
+#define TARG_CONTROL_UNIT 0xffff00ff
+#define TARG_IS_CONTROL_DEV(unit) ((unit) == TARG_CONTROL_UNIT)
+
/* Offsets into our private CCB area for storing accept information */
#define ccb_type ppriv_field0
#define ccb_descr ppriv_ptr1
@@ -159,6 +162,8 @@ static int targsendccb(struct cam_periph *periph, union ccb *ccb,
static periph_init_t targinit;
static void targasync(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg);
+static int targallocinstance(struct ioc_alloc_unit *alloc_unit);
+static int targfreeinstance(struct ioc_alloc_unit *alloc_unit);
static cam_status targenlun(struct cam_periph *periph);
static cam_status targdislun(struct cam_periph *periph);
static periph_ctor_t targctor;
@@ -191,8 +196,7 @@ static struct extend_array *targperiphs;
static void
targinit(void)
{
- cam_status status;
- struct cam_path *path;
+ dev_t dev;
/*
* Create our extend array for storing the devices we attach to.
@@ -202,37 +206,10 @@ targinit(void)
printf("targ: Failed to alloc extend array!\n");
return;
}
-
- /*
- * Install a global async callback. This callback will
- * receive async callbacks like "new path registered".
- */
- status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
- CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
-
- if (status == CAM_REQ_CMP) {
- struct ccb_setasync csa;
-
- xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
- csa.ccb_h.func_code = XPT_SASYNC_CB;
- csa.event_enable = AC_PATH_REGISTERED;
- csa.callback = targasync;
- csa.callback_arg = NULL;
- xpt_action((union ccb *)&csa);
- status = csa.ccb_h.status;
- xpt_free_path(path);
- }
-
- if (status != CAM_REQ_CMP) {
- printf("targ: Failed to attach master async callback "
- "due to status 0x%x!\n", status);
- } else {
- /* If we were successfull, register our devsw */
- dev_t dev;
- dev = makedev(TARG_CDEV_MAJOR, 0);
- cdevsw_add(&dev,&targ_cdevsw, NULL);
- }
+ /* If we were successfull, register our devsw */
+ dev = makedev(TARG_CDEV_MAJOR, 0);
+ cdevsw_add(&dev,&targ_cdevsw, NULL);
}
static void
@@ -243,42 +220,6 @@ targasync(void *callback_arg, u_int32_t code,
periph = (struct cam_periph *)callback_arg;
switch (code) {
- case AC_PATH_REGISTERED:
- {
- struct ccb_pathinq *cpi;
- struct cam_path *new_path;
- cam_status status;
-
- cpi = (struct ccb_pathinq *)arg;
-
- /* Only attach to controllers that support target mode */
- if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
- break;
-
- /*
- * Allocate a peripheral instance for
- * this target instance.
- */
- status = xpt_create_path(&new_path, NULL,
- xpt_path_path_id(path),
- cpi->initiator_id, /*lun*/0);
- if (status != CAM_REQ_CMP) {
- printf("targasync: Unable to create path "
- "due to status 0x%x\n", status);
- break;
- }
- status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
- "targ", CAM_PERIPH_BIO,
- new_path, targasync,
- AC_PATH_REGISTERED,
- cpi);
- xpt_free_path(new_path);
- if (status != CAM_REQ_CMP
- && status != CAM_REQ_INPROG)
- printf("targasync: Unable to attach to new device "
- "due to status 0x%x\n", status);
- break;
- }
case AC_PATH_DEREGISTERED:
{
/* XXX Implement */
@@ -353,6 +294,8 @@ targenlun(struct cam_periph *periph)
xpt_action((union ccb *)atio);
status = atio->ccb_h.status;
if (status != CAM_REQ_INPROG) {
+ xpt_print_path(periph->path);
+ printf("Queue of atio failed\n");
freedescr(atio->ccb_h.ccb_descr);
free(atio, M_DEVBUF);
break;
@@ -391,6 +334,7 @@ targenlun(struct cam_periph *periph)
xpt_action((union ccb *)inot);
status = inot->ccb_h.status;
if (status != CAM_REQ_INPROG) {
+ printf("Queue of inot failed\n");
free(inot, M_DEVBUF);
break;
}
@@ -425,7 +369,7 @@ targdislun(struct cam_periph *periph)
/* Kill off all ACCECPT and IMMEDIATE CCBs */
while ((atio = softc->accept_tio_list) != NULL) {
-
+
softc->accept_tio_list =
((struct targ_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
@@ -505,6 +449,7 @@ targctor(struct cam_periph *periph, void *arg)
if (softc->inq_data == NULL) {
printf("targctor - Unable to malloc inquiry data\n");
targdtor(periph);
+ return (CAM_RESRC_UNAVAIL);
}
bzero(softc->inq_data, softc->inq_data_len);
softc->inq_data->device = T_PROCESSOR | (SID_QUAL_LU_CONNECTED << 5);
@@ -532,6 +477,8 @@ targdtor(struct cam_periph *periph)
targdislun(periph);
+ cam_extend_release(targperiphs, periph->unit_number);
+
switch (softc->init_level) {
default:
/* FALLTHROUGH */
@@ -550,6 +497,7 @@ static int
targopen(dev_t dev, int flags, int fmt, struct proc *p)
{
struct cam_periph *periph;
+ struct targ_softc *softc;
u_int unit;
cam_status status;
int error;
@@ -557,6 +505,10 @@ targopen(dev_t dev, int flags, int fmt, struct proc *p)
unit = minor(dev);
+ /* An open of the control device always succeeds */
+ if (TARG_IS_CONTROL_DEV(unit))
+ return 0;
+
s = splsoftcam();
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL) {
@@ -567,6 +519,15 @@ targopen(dev_t dev, int flags, int fmt, struct proc *p)
splx(s);
return (error);
}
+
+ softc = (struct targ_softc *)periph->softc;
+ if ((softc->flags & TARG_FLAG_LUN_ENABLED) == 0) {
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ splx(s);
+ cam_periph_unlock(periph);
+ return(ENXIO);
+ }
+ }
splx(s);
status = targenlun(periph);
@@ -598,6 +559,11 @@ targclose(dev_t dev, int flag, int fmt, struct proc *p)
int error;
unit = minor(dev);
+
+ /* A close of the control device always succeeds */
+ if (TARG_IS_CONTROL_DEV(unit))
+ return 0;
+
s = splsoftcam();
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL) {
@@ -612,11 +578,161 @@ targclose(dev_t dev, int flag, int fmt, struct proc *p)
targdislun(periph);
cam_periph_unlock(periph);
+ cam_periph_release(periph);
return (0);
}
static int
+targallocinstance(struct ioc_alloc_unit *alloc_unit)
+{
+ struct ccb_pathinq cpi;
+ struct cam_path *path;
+ struct cam_periph *periph;
+ cam_status status;
+ int free_path_on_return;
+ int error;
+
+ free_path_on_return = 0;
+ status = xpt_create_path(&path, /*periph*/NULL,
+ alloc_unit->path_id,
+ alloc_unit->target_id,
+ alloc_unit->lun_id);
+ free_path_on_return++;
+
+ if (status != CAM_REQ_CMP) {
+ printf("Couldn't Allocate Path %x\n", status);
+ goto fail;
+ }
+
+ xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+ status = cpi.ccb_h.status;
+
+ if (status != CAM_REQ_CMP) {
+ printf("Couldn't CPI %x\n", status);
+ goto fail;
+ }
+
+ /* Can only alloc units on controllers that support target mode */
+ if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
+ printf("Controller does not support target mode%x\n", status);
+ status = CAM_PATH_INVALID;
+ goto fail;
+ }
+
+ /* Ensure that we don't already have an instance for this unit. */
+ if ((periph = cam_periph_find(path, "targ")) != NULL) {
+ printf("Lun already enabled%x\n", status);
+ status = CAM_LUN_ALRDY_ENA;
+ goto fail;
+ }
+
+ /*
+ * Allocate a peripheral instance for
+ * this target instance.
+ */
+ status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
+ "targ", CAM_PERIPH_BIO, path, targasync,
+ 0, &cpi);
+
+fail:
+ if (free_path_on_return != 0)
+ xpt_free_path(path);
+
+ switch (status) {
+ case CAM_REQ_CMP:
+ {
+ struct cam_periph *periph;
+
+ if ((periph = cam_periph_find(path, "targ")) == NULL)
+ panic("targallocinstance: Succeeded but no periph?");
+ error = 0;
+ alloc_unit->unit = periph->unit_number;
+ break;
+ }
+ case CAM_RESRC_UNAVAIL:
+ error = ENOMEM;
+ break;
+ case CAM_LUN_ALRDY_ENA:
+ error = EADDRINUSE;
+ break;
+ default:
+ printf("targallocinstance: Unexpected CAM status %x\n", status);
+ /* FALLTHROUGH */
+ case CAM_PATH_INVALID:
+ error = ENXIO;
+ break;
+ case CAM_PROVIDE_FAIL:
+ error = ENODEV;
+ break;
+ }
+ return (error);
+}
+
+static int
+targfreeinstance(struct ioc_alloc_unit *alloc_unit)
+{
+ struct cam_path *path;
+ struct cam_periph *periph;
+ struct targ_softc *softc;
+ cam_status status;
+ int free_path_on_return;
+ int error;
+
+ periph = NULL;
+ free_path_on_return = 0;
+ status = xpt_create_path(&path, /*periph*/NULL,
+ alloc_unit->path_id,
+ alloc_unit->target_id,
+ alloc_unit->lun_id);
+ free_path_on_return++;
+
+ if (status != CAM_REQ_CMP)
+ goto fail;
+
+ /* Find our instance. */
+ if ((periph = cam_periph_find(path, "targ")) == NULL) {
+ xpt_print_path(path);
+ status = CAM_PATH_INVALID;
+ goto fail;
+ }
+
+ softc = (struct targ_softc *)periph->softc;
+
+ if ((softc->flags & TARG_FLAG_LUN_ENABLED) != 0) {
+ status = CAM_BUSY;
+ goto fail;
+ }
+
+fail:
+ if (free_path_on_return != 0)
+ xpt_free_path(path);
+
+ switch (status) {
+ case CAM_REQ_CMP:
+ if (periph != NULL)
+ cam_periph_invalidate(periph);
+ error = 0;
+ break;
+ case CAM_RESRC_UNAVAIL:
+ error = ENOMEM;
+ break;
+ case CAM_LUN_ALRDY_ENA:
+ error = EADDRINUSE;
+ break;
+ default:
+ printf("targfreeinstance: Unexpected CAM status %x\n", status);
+ /* FALLTHROUGH */
+ case CAM_PATH_INVALID:
+ error = ENODEV;
+ break;
+ }
+ return (error);
+}
+
+static int
targioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
struct cam_periph *periph;
@@ -625,11 +741,26 @@ targioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
int error;
unit = minor(dev);
+ error = 0;
+ if (TARG_IS_CONTROL_DEV(unit)) {
+ switch (cmd) {
+ case TARGCTLIOALLOCUNIT:
+ error = targallocinstance((struct ioc_alloc_unit*)addr);
+ break;
+ case TARGCTLIOFREEUNIT:
+ error = targfreeinstance((struct ioc_alloc_unit*)addr);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+ }
+
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL)
return (ENXIO);
softc = (struct targ_softc *)periph->softc;
- error = 0;
switch (cmd) {
case TARGIOCFETCHEXCEPTION:
*((targ_exception *)addr) = softc->exceptions;
@@ -817,6 +948,11 @@ targpoll(dev_t dev, int poll_events, struct proc *p)
int s;
unit = minor(dev);
+
+ /* ioctl is the only supported operation of the control device */
+ if (TARG_IS_CONTROL_DEV(unit))
+ return EINVAL;
+
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL)
return (ENXIO);
@@ -851,16 +987,21 @@ targpoll(dev_t dev, int poll_events, struct proc *p)
static int
targread(dev_t dev, struct uio *uio, int ioflag)
{
+ u_int unit;
+
+ unit = minor(dev);
+ /* ioctl is the only supported operation of the control device */
+ if (TARG_IS_CONTROL_DEV(unit))
+ return EINVAL;
+
if (uio->uio_iovcnt == 0
|| uio->uio_iov->iov_len == 0) {
/* EOF */
struct cam_periph *periph;
struct targ_softc *softc;
- u_int unit;
int s;
s = splcam();
- unit = minor(dev);
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL)
return (ENXIO);
@@ -876,16 +1017,21 @@ targread(dev_t dev, struct uio *uio, int ioflag)
static int
targwrite(dev_t dev, struct uio *uio, int ioflag)
{
+ u_int unit;
+
+ unit = minor(dev);
+ /* ioctl is the only supported operation of the control device */
+ if (TARG_IS_CONTROL_DEV(unit))
+ return EINVAL;
+
if (uio->uio_iovcnt == 0
|| uio->uio_iov->iov_len == 0) {
/* EOF */
struct cam_periph *periph;
struct targ_softc *softc;
- u_int unit;
int s;
s = splcam();
- unit = minor(dev);
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL)
return (ENXIO);
@@ -912,10 +1058,17 @@ targstrategy(struct buf *bp)
int s;
unit = minor(bp->b_dev);
+
+ /* ioctl is the only supported operation of the control device */
+ if (TARG_IS_CONTROL_DEV(unit)) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
periph = cam_extend_get(targperiphs, unit);
if (periph == NULL) {
bp->b_error = ENXIO;
- goto bad;
+ goto bad;
}
softc = (struct targ_softc *)periph->softc;
@@ -1154,7 +1307,6 @@ targdone(struct cam_periph *periph, union ccb *done_ccb)
cdb = atio->cdb_io.cdb_bytes;
if (softc->state == TARG_STATE_TEARDOWN
|| atio->ccb_h.status == CAM_REQ_ABORTED) {
- printf("Freed an accept tio\n");
freedescr(descr);
free(done_ccb, M_DEVBUF);
return;
@@ -1272,6 +1424,7 @@ targdone(struct cam_periph *periph, union ccb *done_ccb)
atio->ccb_h.flags |= CAM_DIR_NONE;
descr->data_resid = 0;
descr->data_increment = 0;
+ descr->timeout = 5 * 1000;
descr->status = SCSI_STATUS_OK;
break;
case REQUEST_SENSE:
@@ -1398,6 +1551,9 @@ targdone(struct cam_periph *periph, union ccb *done_ccb)
periph_links.tqe);
/* XXX Check for errors */
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+
+ }
desc->data_resid -= desc->data_increment;
if ((bp = desc->bp) != NULL) {
@@ -1473,12 +1629,15 @@ targdone(struct cam_periph *periph, union ccb *done_ccb)
case XPT_IMMED_NOTIFY:
{
if (softc->state == TARG_STATE_TEARDOWN
- || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
- printf("Freed an immediate notify\n");
+ || done_ccb->ccb_h.status == CAM_REQ_ABORTED)
free(done_ccb, M_DEVBUF);
- }
break;
}
+ default:
+ panic("targdone: Impossible xpt opcode %x encountered.",
+ done_ccb->ccb_h.func_code);
+ /* NOTREACHED */
+ break;
}
}
diff --git a/sys/cam/scsi/scsi_targetio.h b/sys/cam/scsi/scsi_targetio.h
index 59826c7..a983821 100644
--- a/sys/cam/scsi/scsi_targetio.h
+++ b/sys/cam/scsi/scsi_targetio.h
@@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: scsi_targetio.h,v 1.1 1998/09/15 06:36:34 gibbs Exp $
*/
#ifndef _CAM_SCSI_SCSI_TARGETIO_H_
@@ -100,4 +100,20 @@ struct ioc_initiator_state {
#define TARGIOCGETISTATE _IOWR('C', 6, struct ioc_initiator_state)
#define TARGIOCSETISTATE _IOW('C', 5, struct ioc_initiator_state)
+struct ioc_alloc_unit {
+ path_id_t path_id;
+ target_id_t target_id;
+ lun_id_t lun_id;
+ u_int unit;
+};
+
+/*
+ * Allocate and Free a target mode instance. For allocation, the path_id,
+ * target_id, and lun_id fields must be set. On successful completion
+ * of the ioctl, the unit field will indicate the unit number of the
+ * newly created instance. For de-allocation, all fields must match
+ * an instance in the inactive (i.e. closed) state.
+ */
+#define TARGCTLIOALLOCUNIT _IOWR('C', 7, struct ioc_alloc_unit)
+#define TARGCTLIOFREEUNIT _IOW('C', 8, struct ioc_alloc_unit)
#endif /* _CAM_SCSI_SCSI_TARGETIO_H_ */
OpenPOWER on IntegriCloud