summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2017-03-06 06:19:02 +0000
committermav <mav@FreeBSD.org>2017-03-06 06:19:02 +0000
commitfeaabbfe8ab7e994a87f2a19004fc7fca92f3fa2 (patch)
treebb84eaaf7bd62962b31ae20238f7223ad92b212c /sys/cam
parenta305a63de0c22be1b4e043cf58b8a6299f1075c9 (diff)
downloadFreeBSD-src-feaabbfe8ab7e994a87f2a19004fc7fca92f3fa2.zip
FreeBSD-src-feaabbfe8ab7e994a87f2a19004fc7fca92f3fa2.tar.gz
MFC r314027: Do not blindly free completed ATIOs/INOTs on invalidation.
When LUN is disabled, SIM starts returning queued ATIOs/INOTs. But at the same time there can be some ATIOs/INOTs still carrying real new requests. If we free those, SIM may leak some resources, forever expecting for any response from us. So try to be careful, separating ATIOs/INOTs carrying requests which still must be processed, from ATIOs/INOTs completed with errors which can be freed.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ctl/scsi_ctl.c78
1 files changed, 19 insertions, 59 deletions
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c
index dc82e91..65f9b60 100644
--- a/sys/cam/ctl/scsi_ctl.c
+++ b/sys/cam/ctl/scsi_ctl.c
@@ -1102,6 +1102,7 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
struct ccb_accept_tio *atio = NULL;
union ctl_io *io = NULL;
struct mtx *mtx;
+ cam_status status;
KASSERT((done_ccb->ccb_h.flags & CAM_UNLOCKED) != 0,
("CCB in ctlfedone() without CAM_UNLOCKED flag"));
@@ -1128,30 +1129,15 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
mtx = cam_periph_mtx(periph);
mtx_lock(mtx);
- /*
- * If the peripheral is invalid, ATIOs and immediate notify CCBs
- * need to be freed. Most of the ATIOs and INOTs that come back
- * will be CCBs that are being returned from the SIM as a result of
- * our disabling the LUN.
- *
- * Other CCB types are handled in their respective cases below.
- */
- if (periph->flags & CAM_PERIPH_INVALID) {
- switch (done_ccb->ccb_h.func_code) {
- case XPT_ACCEPT_TARGET_IO:
- case XPT_IMMEDIATE_NOTIFY:
- case XPT_NOTIFY_ACKNOWLEDGE:
- ctlfe_free_ccb(periph, done_ccb);
- goto out;
- default:
- break;
- }
-
- }
switch (done_ccb->ccb_h.func_code) {
case XPT_ACCEPT_TARGET_IO: {
atio = &done_ccb->atio;
+ status = atio->ccb_h.status & CAM_STATUS_MASK;
+ if (status != CAM_CDB_RECVD) {
+ ctlfe_free_ccb(periph, done_ccb);
+ goto out;
+ }
resubmit:
/*
@@ -1430,14 +1416,9 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
case XPT_IMMEDIATE_NOTIFY: {
union ctl_io *io;
struct ccb_immediate_notify *inot;
- cam_status status;
int send_ctl_io;
inot = &done_ccb->cin1;
- printf("%s: got XPT_IMMEDIATE_NOTIFY status %#x tag %#x "
- "seq %#x\n", __func__, inot->ccb_h.status,
- inot->tag_id, inot->seq_id);
-
io = done_ccb->ccb_h.io_ptr;
ctl_zero_io(io);
@@ -1503,40 +1484,22 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
break;
default:
xpt_print(periph->path,
- "%s: unsupported message 0x%x\n",
- __func__, inot->arg);
+ "%s: unsupported INOT message 0x%x\n",
+ __func__, inot->arg);
send_ctl_io = 0;
break;
}
break;
+ default:
+ xpt_print(periph->path,
+ "%s: unsupported INOT status 0x%x\n",
+ __func__, status);
+ /* FALLTHROUGH */
case CAM_REQ_ABORTED:
- /*
- * This request was sent back by the driver.
- * XXX KDM what do we do here?
- */
- send_ctl_io = 0;
- break;
case CAM_REQ_INVALID:
+ case CAM_DEV_NOT_THERE:
case CAM_PROVIDE_FAIL:
- default:
- /*
- * We should only get here if we're talking
- * to a talking to a SIM that is target
- * capable but supports the old API. In
- * that case, we need to just free the CCB.
- * If we actually send a notify acknowledge,
- * it will send that back with an error as
- * well.
- */
-
- if ((status != CAM_REQ_INVALID)
- && (status != CAM_PROVIDE_FAIL))
- xpt_print(periph->path,
- "%s: unsupported CAM status 0x%x\n",
- __func__, status);
-
ctlfe_free_ccb(periph, done_ccb);
-
goto out;
}
if (send_ctl_io != 0) {
@@ -1549,6 +1512,11 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
break;
}
case XPT_NOTIFY_ACKNOWLEDGE:
+ if (periph->flags & CAM_PERIPH_INVALID) {
+ ctlfe_free_ccb(periph, done_ccb);
+ goto out;
+ }
+
/*
* Queue this back down to the SIM as an immediate notify.
*/
@@ -2029,14 +1997,6 @@ ctlfe_done(union ctl_io *io)
if (io->io_hdr.io_type == CTL_IO_TASK) {
/*
- * Task management commands don't require any further
- * communication back to the adapter. Requeue the CCB
- * to the adapter, and free the CTL I/O.
- */
- xpt_print(ccb->ccb_h.path, "%s: returning task I/O "
- "tag %#x seq %#x\n", __func__,
- ccb->cin1.tag_id, ccb->cin1.seq_id);
- /*
* Send the notify acknowledge down to the SIM, to let it
* know we processed the task management command.
*/
OpenPOWER on IntegriCloud