From 3b63a91d6d123fe06ebc97779c7fcca4e09c7012 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 21 Feb 2017 06:10:11 +0000 Subject: [PATCH] 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. MFC after: 2 weeks --- sys/cam/ctl/scsi_ctl.c | 82 +++++++++++------------------------------- 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index 4a3f74372e01..4b9f23006bdf 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -1096,6 +1096,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")); @@ -1122,30 +1123,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: /* @@ -1424,14 +1410,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); @@ -1497,40 +1478,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; - 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_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); - + xpt_print(periph->path, + "%s: unsupported INOT status 0x%x\n", + __func__, status); + /* FALLTHROUGH */ + case CAM_REQ_ABORTED: + case CAM_REQ_INVALID: + case CAM_DEV_NOT_THERE: + case CAM_PROVIDE_FAIL: ctlfe_free_ccb(periph, done_ccb); - goto out; } if (send_ctl_io != 0) { @@ -1543,6 +1506,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. */ @@ -2023,14 +1991,6 @@ ctlfe_done(union ctl_io *io) softc = (struct ctlfe_lun_softc *)periph->softc; 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.