summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/scsi/scsi_target.c285
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);
}
OpenPOWER on IntegriCloud