diff options
author | ken <ken@FreeBSD.org> | 2012-06-26 14:51:35 +0000 |
---|---|---|
committer | ken <ken@FreeBSD.org> | 2012-06-26 14:51:35 +0000 |
commit | 877f7e22dc80676c9ece47bf58c4a6bdc79be4c7 (patch) | |
tree | 7b016bc8afd686b682aaffe21bfcace67afaf0e7 /sys | |
parent | 4183957bce956b38c2e2189a30e2a92d9dc592af (diff) | |
download | FreeBSD-src-877f7e22dc80676c9ece47bf58c4a6bdc79be4c7.zip FreeBSD-src-877f7e22dc80676c9ece47bf58c4a6bdc79be4c7.tar.gz |
Fix an issue that caused the kernel to panic inside CTL when trying
to attach to target capable HBAs that implement the old immediate
notify (XPT_IMMED_NOTIFY) and notify acknowledge (XPT_NOTIFY_ACK)
CCBs. The new API has been in place since SVN change 196008 in
2009.
The solution is two-fold: fix CTL to handle the responses from the
HBAs, and convert the HBA drivers in question to use the new API.
These drivers have not been tested with CTL, so how well they will
interoperate with CTL is unknown.
scsi_target.c: Update the userland target example code to use the
new immediate notify API.
scsi_ctl.c: Detect when an immediate notify CCB is returned
with CAM_REQ_INVALID or CAM_PROVIDE_FAIL status,
and just free it.
Fix a duplicate assignment.
aic79xx.c,
aic79xx_osm.c: Update the aic79xx driver to use the new API.
Target mode is not enabled on for this driver, so
the changes will have no practical effect.
aic7xxx.c,
aic7xxx_osm.c: Update the aic7xxx driver to use the new API.
sbp_targ.c: Update the firewire target code to work with the
new API.
mpt_cam.c: Update the mpt(4) driver to work with the new API.
Target mode is only enabled for Fibre Channel
mpt(4) devices.
MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/cam/ctl/scsi_ctl.c | 44 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx.c | 9 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx_osm.c | 8 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 9 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.c | 8 | ||||
-rw-r--r-- | sys/dev/firewire/sbp_targ.c | 10 | ||||
-rw-r--r-- | sys/dev/mpt/mpt_cam.c | 34 |
7 files changed, 73 insertions, 49 deletions
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index 0563f72..044b9a9 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -558,7 +558,6 @@ ctlferegister(struct cam_periph *periph, void *arg) TAILQ_INIT(&softc->work_queue); softc->periph = periph; - softc->parent_softc = bus_softc; callout_init_mtx(&softc->dma_callout, sim->mtx, /*flags*/ 0); periph->softc = softc; @@ -628,12 +627,22 @@ ctlferegister(struct cam_periph *periph, void *arg) xpt_action(new_ccb); softc->inots_sent++; status = new_ccb->ccb_h.status; - if (status != CAM_REQ_INPROG) { - free(new_ccb, M_CTLFE); + if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { + /* + * Note that we don't free the CCB here. If the + * status is not CAM_REQ_INPROG, then we're + * probably talking to a SIM that says it is + * target-capable but doesn't support the + * XPT_IMMEDIATE_NOTIFY CCB. i.e. it supports the + * older API. In that case, it'll call xpt_done() + * on the CCB, and we need to free it in our done + * routine as a result. + */ break; } } - if (i == 0) { + if ((i == 0) + || (status != CAM_REQ_INPROG)) { xpt_print(periph->path, "%s: could not allocate immediate " "notify CCBs, status 0x%x\n", __func__, status); return (CAM_REQ_CMP_ERR); @@ -1460,12 +1469,29 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) */ send_ctl_io = 0; break; + case CAM_REQ_INVALID: + case CAM_PROVIDE_FAIL: default: - xpt_print(periph->path, "%s: " - "unsupported CAM status 0x%x\n", - __func__, status); - send_ctl_io = 0; - break; + /* + * 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); + + ctl_free_io(io); + ctlfe_free_ccb(periph, done_ccb); + + return; } if (send_ctl_io != 0) { ctl_queue(io); diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c index 86b13fa..363301b 100644 --- a/sys/dev/aic7xxx/aic79xx.c +++ b/sys/dev/aic7xxx/aic79xx.c @@ -8561,7 +8561,7 @@ void ahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate) { struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; + struct ccb_immediate_notify *inot; while (lstate->event_r_idx != lstate->event_w_idx && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { @@ -8569,19 +8569,18 @@ ahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate) event = &lstate->event_buffer[lstate->event_r_idx]; SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); - inot = (struct ccb_immed_notify *)ccbh; + inot = (struct ccb_immediate_notify *)ccbh; switch (event->event_type) { case EVENT_TYPE_BUS_RESET: ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; break; default: ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; - inot->message_args[0] = event->event_type; - inot->message_args[1] = event->event_arg; + inot->arg = event->event_type; + inot->seq_id = event->event_arg; break; } inot->initiator_id = event->initiator_id; - inot->sense_len = 0; xpt_done((union ccb *)inot); lstate->event_r_idx++; if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) diff --git a/sys/dev/aic7xxx/aic79xx_osm.c b/sys/dev/aic7xxx/aic79xx_osm.c index 375de63..1d44b9f 100644 --- a/sys/dev/aic7xxx/aic79xx_osm.c +++ b/sys/dev/aic7xxx/aic79xx_osm.c @@ -601,8 +601,8 @@ ahd_action(struct cam_sim *sim, union ccb *ccb) break; } #ifdef AHD_TARGET_MODE - case XPT_NOTIFY_ACK: - case XPT_IMMED_NOTIFY: + case XPT_NOTIFY_ACKNOWLEDGE: + case XPT_IMMEDIATE_NOTIFY: { struct ahd_tmode_tstate *tstate; struct ahd_tmode_lstate *lstate; @@ -1189,7 +1189,7 @@ ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) switch (abort_ccb->ccb_h.func_code) { #ifdef AHD_TARGET_MODE case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: + case XPT_IMMEDIATE_NOTIFY: case XPT_CONT_TARGET_IO: { struct ahd_tmode_tstate *tstate; @@ -1207,7 +1207,7 @@ ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) list = &lstate->accept_tios; - else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) + else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) list = &lstate->immed_notifies; else list = NULL; diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index d5bac1d..7bbe3c5 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -6368,7 +6368,7 @@ void ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) { struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; + struct ccb_immediate_notify *inot; while (lstate->event_r_idx != lstate->event_w_idx && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { @@ -6376,19 +6376,18 @@ ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) event = &lstate->event_buffer[lstate->event_r_idx]; SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); - inot = (struct ccb_immed_notify *)ccbh; + inot = (struct ccb_immediate_notify *)ccbh; switch (event->event_type) { case EVENT_TYPE_BUS_RESET: ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; break; default: ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; - inot->message_args[0] = event->event_type; - inot->message_args[1] = event->event_arg; + inot->arg = event->event_type; + inot->seq_id = event->event_arg; break; } inot->initiator_id = event->initiator_id; - inot->sense_len = 0; xpt_done((union ccb *)inot); lstate->event_r_idx++; if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c index eeb06af..281b00e 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/aic7xxx/aic7xxx_osm.c @@ -568,8 +568,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } break; } - case XPT_NOTIFY_ACK: - case XPT_IMMED_NOTIFY: + case XPT_NOTIFY_ACKNOWLEDGE: + case XPT_IMMEDIATE_NOTIFY: { struct ahc_tmode_tstate *tstate; struct ahc_tmode_lstate *lstate; @@ -1248,7 +1248,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) abort_ccb = ccb->cab.abort_ccb; switch (abort_ccb->ccb_h.func_code) { case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: + case XPT_IMMEDIATE_NOTIFY: case XPT_CONT_TARGET_IO: { struct ahc_tmode_tstate *tstate; @@ -1266,7 +1266,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) list = &lstate->accept_tios; - else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) + else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) list = &lstate->immed_notifies; else list = NULL; diff --git a/sys/dev/firewire/sbp_targ.c b/sys/dev/firewire/sbp_targ.c index 3a74389..34a75cb 100644 --- a/sys/dev/firewire/sbp_targ.c +++ b/sys/dev/firewire/sbp_targ.c @@ -533,7 +533,7 @@ sbp_targ_send_lstate_events(struct sbp_targ_softc *sc, { #if 0 struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; + struct ccb_immediate_notify *inot; printf("%s: not implemented yet\n", __func__); #endif @@ -908,7 +908,7 @@ sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb) if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) list = &lstate->accept_tios; - else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) + else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) list = &lstate->immed_notifies; else return (CAM_UA_ABORT); @@ -1301,8 +1301,8 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) } } break; - case XPT_NOTIFY_ACK: /* recycle notify ack */ - case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ + case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */ + case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ if (status != CAM_REQ_CMP) { ccb->ccb_h.status = status; xpt_done(ccb); @@ -1349,7 +1349,7 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) switch (accb->ccb_h.func_code) { case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: + case XPT_IMMEDIATE_NOTIFY: ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb); break; case XPT_CONT_TARGET_IO: diff --git a/sys/dev/mpt/mpt_cam.c b/sys/dev/mpt/mpt_cam.c index 39619c2..e56bf67 100644 --- a/sys/dev/mpt/mpt_cam.c +++ b/sys/dev/mpt/mpt_cam.c @@ -3411,7 +3411,7 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) CAMLOCK_2_MPTLOCK(mpt); switch (accb->ccb_h.func_code) { case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: + case XPT_IMMEDIATE_NOTIFY: ccb->ccb_h.status = mpt_abort_target_ccb(mpt, ccb); break; case XPT_CONT_TARGET_IO: @@ -3785,8 +3785,8 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) } break; } - case XPT_NOTIFY_ACK: /* recycle notify ack */ - case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ + case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */ + case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ { tgt_resource_t *trtp; @@ -3813,7 +3813,7 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) "Put FREE ATIO %p lun %d\n", ccb, lun); STAILQ_INSERT_TAIL(&trtp->atios, &ccb->ccb_h, sim_links.stqe); - } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { + } else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { mpt_lprt(mpt, MPT_PRT_DEBUG1, "Put FREE INOT lun %d\n", lun); STAILQ_INSERT_TAIL(&trtp->inots, &ccb->ccb_h, @@ -4822,7 +4822,7 @@ mpt_abort_target_ccb(struct mpt_softc *mpt, union ccb *ccb) if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { lp = &trtp->atios; - } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { + } else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { lp = &trtp->inots; } else { return (CAM_REQ_INVALID); @@ -5043,11 +5043,11 @@ static void mpt_scsi_tgt_tsk_mgmt(struct mpt_softc *mpt, request_t *req, mpt_task_mgmt_t fc, tgt_resource_t *trtp, int init_id) { - struct ccb_immed_notify *inot; + struct ccb_immediate_notify *inot; mpt_tgt_state_t *tgt; tgt = MPT_TGT_STATE(mpt, req); - inot = (struct ccb_immed_notify *) STAILQ_FIRST(&trtp->inots); + inot = (struct ccb_immediate_notify *) STAILQ_FIRST(&trtp->inots); if (inot == NULL) { mpt_lprt(mpt, MPT_PRT_WARN, "no INOTSs- sending back BSY\n"); mpt_scsi_tgt_status(mpt, NULL, req, SCSI_STATUS_BUSY, NULL); @@ -5057,35 +5057,35 @@ mpt_scsi_tgt_tsk_mgmt(struct mpt_softc *mpt, request_t *req, mpt_task_mgmt_t fc, mpt_lprt(mpt, MPT_PRT_DEBUG1, "Get FREE INOT %p lun %d\n", inot, inot->ccb_h.target_lun); - memset(&inot->sense_data, 0, sizeof (inot->sense_data)); - inot->sense_len = 0; - memset(inot->message_args, 0, sizeof (inot->message_args)); inot->initiator_id = init_id; /* XXX */ - /* * This is a somewhat grotesque attempt to map from task management * to old style SCSI messages. God help us all. */ switch (fc) { case MPT_ABORT_TASK_SET: - inot->message_args[0] = MSG_ABORT_TAG; + inot->arg = MSG_ABORT_TAG; break; case MPT_CLEAR_TASK_SET: - inot->message_args[0] = MSG_CLEAR_TASK_SET; + inot->arg = MSG_CLEAR_TASK_SET; break; case MPT_TARGET_RESET: - inot->message_args[0] = MSG_TARGET_RESET; + inot->arg = MSG_TARGET_RESET; break; case MPT_CLEAR_ACA: - inot->message_args[0] = MSG_CLEAR_ACA; + inot->arg = MSG_CLEAR_ACA; break; case MPT_TERMINATE_TASK: - inot->message_args[0] = MSG_ABORT_TAG; + inot->arg = MSG_ABORT_TAG; break; default: - inot->message_args[0] = MSG_NOOP; + inot->arg = MSG_NOOP; break; } + /* + * XXX KDM we need the sequence/tag number for the target of the + * task management operation, especially if it is an abort. + */ tgt->ccb = (union ccb *) inot; inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; MPTLOCK_2_CAMLOCK(mpt); |