diff options
-rw-r--r-- | sys/cam/scsi/scsi_target.c | 285 |
1 files changed, 190 insertions, 95 deletions
diff --git a/sys/cam/scsi/scsi_target.c b/sys/cam/scsi/scsi_target.c index d9e5453..2f34701 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.3 1998/10/22 22:16:56 ken Exp $ + * $Id: scsi_target.c,v 1.4 1998/12/10 04:07:42 gibbs Exp $ */ #include <stddef.h> /* For offsetof */ @@ -46,6 +46,7 @@ #include <cam/cam_ccb.h> #include <cam/cam_extend.h> #include <cam/cam_periph.h> +#include <cam/cam_queue.h> #include <cam/cam_xpt_periph.h> #include <cam/cam_debug.h> @@ -63,7 +64,8 @@ typedef enum { typedef enum { TARG_FLAG_NONE = 0x00, TARG_FLAG_SEND_EOF = 0x01, - TARG_FLAG_RECEIVE_EOF = 0x02 + TARG_FLAG_RECEIVE_EOF = 0x02, + TARG_FLAG_LUN_ENABLED = 0x04 } targ_flags; typedef enum { @@ -104,6 +106,8 @@ struct targ_softc { u_int init_level; u_int inq_data_len; struct scsi_inquiry_data *inq_data; + struct ccb_hdr_slist accept_tio_slist; + struct ccb_hdr_slist immed_notify_slist; struct initiator_state istate[MAX_INITIATORS]; }; @@ -155,6 +159,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 cam_status targenlun(struct cam_periph *periph); +static cam_status targdislun(struct cam_periph *periph); static periph_ctor_t targctor; static periph_dtor_t targdtor; static void targrunqueue(struct cam_periph *periph, @@ -287,68 +293,20 @@ targasync(void *callback_arg, u_int32_t code, } } +/* Attempt to enable our lun */ static cam_status -targctor(struct cam_periph *periph, void *arg) +targenlun(struct cam_periph *periph) { union ccb immed_ccb; - struct ccb_pathinq *cpi; struct targ_softc *softc; cam_status status; int i; - cpi = (struct ccb_pathinq *)arg; - - /* Allocate our per-instance private storage */ - softc = (struct targ_softc *)malloc(sizeof(*softc), M_DEVBUF, M_NOWAIT); - if (softc == NULL) { - printf("targctor: unable to malloc softc\n"); - return (CAM_REQ_CMP_ERR); - } - - bzero(softc, sizeof(softc)); - TAILQ_INIT(&softc->pending_queue); - TAILQ_INIT(&softc->work_queue); - TAILQ_INIT(&softc->snd_ccb_queue); - TAILQ_INIT(&softc->rcv_ccb_queue); - TAILQ_INIT(&softc->unknown_atio_queue); - bufq_init(&softc->snd_buf_queue); - bufq_init(&softc->rcv_buf_queue); - softc->state = TARG_STATE_NORMAL; - periph->softc = softc; - softc->init_level++; + softc = (struct targ_softc *)periph->softc; - cam_extend_set(targperiphs, periph->unit_number, periph); + if ((softc->flags & TARG_FLAG_LUN_ENABLED) != 0) + return (CAM_REQ_CMP); - /* - * We start out life with a UA to indicate power-on/reset. - */ - for (i = 0; i < MAX_INITIATORS; i++) - softc->istate[i].pending_ua = UA_POWER_ON; - - /* - * Allocate an initial inquiry data buffer. We might allow the - * user to override this later via an ioctl. - */ - softc->inq_data_len = sizeof(*softc->inq_data); - softc->inq_data = malloc(softc->inq_data_len, M_DEVBUF, M_NOWAIT); - if (softc->inq_data == NULL) { - printf("targctor - Unable to malloc inquiry data\n"); - targdtor(periph); - } - bzero(softc->inq_data, softc->inq_data_len); - softc->inq_data->device = T_PROCESSOR | (SID_QUAL_LU_CONNECTED << 5); - softc->inq_data->version = 2; - softc->inq_data->response_format = 2; /* SCSI2 Inquiry Format */ - softc->inq_data->flags = - cpi->hba_inquiry & PI_SDTR_ABLE; - /*cpi->hba_inquiry & (PI_SDTR_ABLE|PI_WIDE_16|PI_WIDE_32); */ - softc->inq_data->additional_length = softc->inq_data_len - 4; - strncpy(softc->inq_data->vendor, "FreeBSD ", SID_VENDOR_SIZE); - strncpy(softc->inq_data->product, "TM-PT ", SID_PRODUCT_SIZE); - strncpy(softc->inq_data->revision, "0.0 ", SID_REVISION_SIZE); - softc->init_level++; - - /* Attempt to enable the lun of interrest */ xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); immed_ccb.ccb_h.func_code = XPT_EN_LUN; @@ -358,17 +316,15 @@ targctor(struct cam_periph *periph, void *arg) immed_ccb.cel.enable = 1; xpt_action(&immed_ccb); status = immed_ccb.ccb_h.status; - if (status != CAM_REQ_CMP) { xpt_print_path(periph->path); - printf("targctor - Enable Lun Rejected for status 0x%x\n", + printf("targenlun - Enable Lun Rejected for status 0x%x\n", status); - targdtor(periph); return (status); } - - softc->init_level++; + softc->flags |= TARG_FLAG_LUN_ENABLED; + /* * Build up a buffer of accept target I/O * operations for incoming selections. @@ -400,13 +356,15 @@ targctor(struct cam_periph *periph, void *arg) free(atio, M_DEVBUF); break; } + SLIST_INSERT_HEAD(&softc->accept_tio_slist, &atio->ccb_h, + periph_links.sle); } if (i == 0) { xpt_print_path(periph->path); - printf("targctor - Could not allocate accept tio CCBs: " + printf("targenlun - Could not allocate accept tio CCBs: " "status = 0x%x\n", status); - targdtor(periph); + targdislun(periph); return (CAM_REQ_CMP_ERR); } @@ -434,19 +392,130 @@ targctor(struct cam_periph *periph, void *arg) free(inot, M_DEVBUF); break; } + SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, + periph_links.sle); } if (i == 0) { xpt_print_path(periph->path); - printf("targctor - Could not allocate immediate notify CCBs: " + printf("targenlun - Could not allocate immediate notify CCBs: " "status = 0x%x\n", status); - targdtor(periph); + targdislun(periph); return (CAM_REQ_CMP_ERR); } return (CAM_REQ_CMP); } +static cam_status +targdislun(struct cam_periph *periph) +{ + union ccb ccb; + struct targ_softc *softc; + struct ccb_hdr *ccb_h; + + softc = (struct targ_softc *)periph->softc; + if ((softc->flags & TARG_FLAG_LUN_ENABLED) == 0) + return CAM_REQ_CMP; + + /* XXX Block for Continue I/O completion */ + + /* Kill off all ACCECPT and IMMEDIATE CCBs */ + SLIST_FOREACH(ccb_h, &softc->accept_tio_slist, periph_links.sle) { + xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); + ccb.cab.ccb_h.func_code = XPT_ABORT; + ccb.cab.abort_ccb = (union ccb *)ccb_h; + xpt_action(&ccb); + } + + SLIST_FOREACH(ccb_h, &softc->immed_notify_slist, periph_links.sle) { + xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); + ccb.cab.ccb_h.func_code = XPT_ABORT; + ccb.cab.abort_ccb = (union ccb *)ccb_h; + xpt_action(&ccb); + } + + /* + * Dissable this lun. + */ + xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); + ccb.cel.ccb_h.func_code = XPT_EN_LUN; + ccb.cel.enable = 0; + xpt_action(&ccb); + + if (ccb.cel.ccb_h.status != CAM_REQ_CMP) + printf("targdislun - Disabling lun on controller failed " + "with status 0x%x\n", ccb.cel.ccb_h.status); + else + softc->flags &= ~TARG_FLAG_LUN_ENABLED; + return (ccb.cel.ccb_h.status); +} + +static cam_status +targctor(struct cam_periph *periph, void *arg) +{ + struct ccb_pathinq *cpi; + struct targ_softc *softc; + cam_status status; + int i; + + cpi = (struct ccb_pathinq *)arg; + + /* Allocate our per-instance private storage */ + softc = (struct targ_softc *)malloc(sizeof(*softc), M_DEVBUF, M_NOWAIT); + if (softc == NULL) { + printf("targctor: unable to malloc softc\n"); + return (CAM_REQ_CMP_ERR); + } + + bzero(softc, sizeof(softc)); + TAILQ_INIT(&softc->pending_queue); + TAILQ_INIT(&softc->work_queue); + TAILQ_INIT(&softc->snd_ccb_queue); + TAILQ_INIT(&softc->rcv_ccb_queue); + TAILQ_INIT(&softc->unknown_atio_queue); + bufq_init(&softc->snd_buf_queue); + bufq_init(&softc->rcv_buf_queue); + SLIST_INIT(&softc->accept_tio_slist); + SLIST_INIT(&softc->immed_notify_slist); + softc->state = TARG_STATE_NORMAL; + periph->softc = softc; + softc->init_level++; + + cam_extend_set(targperiphs, periph->unit_number, periph); + + /* + * We start out life with a UA to indicate power-on/reset. + */ + for (i = 0; i < MAX_INITIATORS; i++) + softc->istate[i].pending_ua = UA_POWER_ON; + + /* + * Allocate an initial inquiry data buffer. We might allow the + * user to override this later via an ioctl. + */ + softc->inq_data_len = sizeof(*softc->inq_data); + softc->inq_data = malloc(softc->inq_data_len, M_DEVBUF, M_NOWAIT); + if (softc->inq_data == NULL) { + printf("targctor - Unable to malloc inquiry data\n"); + targdtor(periph); + } + bzero(softc->inq_data, softc->inq_data_len); + softc->inq_data->device = T_PROCESSOR | (SID_QUAL_LU_CONNECTED << 5); + softc->inq_data->version = 2; + softc->inq_data->response_format = 2; /* SCSI2 Inquiry Format */ + softc->inq_data->flags = + cpi->hba_inquiry & PI_SDTR_ABLE; + /*cpi->hba_inquiry & (PI_SDTR_ABLE|PI_WIDE_16|PI_WIDE_32); */ + softc->inq_data->additional_length = softc->inq_data_len - 4; + strncpy(softc->inq_data->vendor, "FreeBSD ", SID_VENDOR_SIZE); + strncpy(softc->inq_data->product, "TM-PT ", SID_PRODUCT_SIZE); + strncpy(softc->inq_data->revision, "0.0 ", SID_REVISION_SIZE); + softc->init_level++; + + return (CAM_REQ_CMP); +} + static void targdtor(struct cam_periph *periph) { @@ -456,25 +525,11 @@ targdtor(struct cam_periph *periph) softc->state = TARG_STATE_TEARDOWN; + targdislun(periph); + switch (softc->init_level) { default: /* FALLTHROUGH */ - case 3: - { - struct ccb_en_lun cel; - /* - * XXX Spec requires abort of all ACCEPT and - * IMMEDIATE CCBS first. Act accordingly. - */ - /* - * Dissable this lun. - */ - xpt_setup_ccb(&cel.ccb_h, periph->path, /*priority*/1); - cel.ccb_h.func_code = XPT_EN_LUN; - cel.enable = 0; - xpt_action((union ccb *)&cel); - /* FALLTHROUGH */ - } case 2: free(softc->inq_data, M_DEVBUF); /* FALLTHROUGH */ @@ -490,32 +545,68 @@ static int targopen(dev_t dev, int flags, int fmt, struct proc *p) { struct cam_periph *periph; - struct targ_softc *softc; - u_int unit; - int s; + u_int unit; + cam_status status; + int error; + int s; unit = minor(dev); + + s = splsoftcam(); periph = cam_extend_get(targperiphs, unit); - if (periph == NULL) + if (periph == NULL) { return (ENXIO); - softc = (struct targ_softc *)periph->softc; - - return (0); + splx(s); + } + if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { + splx(s); + return (error); + } + splx(s); + + status = targenlun(periph); + switch (status) { + case CAM_REQ_CMP: + error = 0; + break; + case CAM_RESRC_UNAVAIL: + error = ENOMEM; + break; + case CAM_LUN_ALRDY_ENA: + error = EADDRINUSE; + break; + default: + error = ENXIO; + break; + } + cam_periph_unlock(periph); + return (error); } static int targclose(dev_t dev, int flag, int fmt, struct proc *p) { - struct cam_periph *periph; - struct targ_softc *softc; - u_int unit; - int s; + struct cam_periph *periph; + struct targ_softc *softc; + u_int unit; + int s; + int error; unit = minor(dev); + s = splsoftcam(); periph = cam_extend_get(targperiphs, unit); - if (periph == NULL) + if (periph == NULL) { + splx(s); return (ENXIO); + } + if ((error = cam_periph_lock(periph, PRIBIO)) != 0) + return (error); softc = (struct targ_softc *)periph->softc; + splx(s); + + targdislun(periph); + + cam_periph_unlock(periph); return (0); } @@ -1059,7 +1150,9 @@ targdone(struct cam_periph *periph, union ccb *done_ccb) descr = (struct targ_cmd_desc*)atio->ccb_h.ccb_descr; istate = &softc->istate[atio->init_id]; cdb = atio->cdb_io.cdb_bytes; - if (softc->state == TARG_STATE_TEARDOWN) { + 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; @@ -1373,7 +1466,9 @@ targdone(struct cam_periph *periph, union ccb *done_ccb) } case XPT_IMMED_NOTIFY: { - if (softc->state == TARG_STATE_TEARDOWN) { + if (softc->state == TARG_STATE_TEARDOWN + || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { + printf("Freed an immediate notify\n"); free(done_ccb, M_DEVBUF); } break; @@ -1451,7 +1546,7 @@ allocdescr() static void freedescr(struct targ_cmd_desc *descr) { - free(descr->data, M_DEVBUF); + free(descr->backing_store, M_DEVBUF); free(descr, M_DEVBUF); } |