summaryrefslogtreecommitdiffstats
path: root/sys/cam/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1998-12-15 08:15:15 +0000
committergibbs <gibbs@FreeBSD.org>1998-12-15 08:15:15 +0000
commit41e7e01c3b4d0b2cfd3e5887f58ed3dc5ad4166a (patch)
tree3390ffecb447226fd2d2af7f35ed9149b9b6db78 /sys/cam/scsi
parent98b3fe0bf58f93eb2390905460874df9003809fc (diff)
downloadFreeBSD-src-41e7e01c3b4d0b2cfd3e5887f58ed3dc5ad4166a.zip
FreeBSD-src-41e7e01c3b4d0b2cfd3e5887f58ed3dc5ad4166a.tar.gz
Enable/Disable our lun on open/close. Track resources kept at the controller
level so they can be reclaimed before attempting to disable our lun. Correctly free descriptors. Add periph locking and spl protection around open and close.
Diffstat (limited to 'sys/cam/scsi')
-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