git: ec3175fc3b2c - main - isp: Improve task aborts handling
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 09 Dec 2024 17:11:00 UTC
The branch main has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=ec3175fc3b2c1b07144a85e6a3e2fe534acc0c87 commit ec3175fc3b2c1b07144a85e6a3e2fe534acc0c87 Author: Alexander Motin <mav@FreeBSD.org> AuthorDate: 2024-12-09 16:52:26 +0000 Commit: Alexander Motin <mav@FreeBSD.org> CommitDate: 2024-12-09 16:52:26 +0000 isp: Improve task aborts handling - When handling notify acknowledge from target code for task abort request, not only send abort to the firmware, but also delete the ATIO private data associated with the command. It is required for proper tag reuse, allowing new "conflicting" commands to be passed to the target. CTL was already fixed to handle that right, instead of delaying them in restart queue of the driver. - When target finally aborts the command (which it should have done before the notify ack) we should not send another abort to the firmware. Since we already sent the abort and deleted ATIO private data above, just return successful completion here, doing nothing. Since the tag can be reused by that time, we can not rely on its uniqueness, so when searching to the ATIO private data compare also the aborted CCB pointer in addition to the tag. - Fix BA_RJT sending in isp_acknak_abts(). While it should be rare, teach the code to send error responses for ABTS requests. MFC after: 2 weeks --- sys/dev/isp/isp_freebsd.c | 142 +++++++++++++++++++++------------------------- sys/dev/isp/isp_freebsd.h | 9 ++- sys/dev/isp/isp_target.c | 11 ++-- 3 files changed, 77 insertions(+), 85 deletions(-) diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 51c1e3abb6de..d5aa7a54142e 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -626,8 +626,9 @@ isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb) */ #ifdef ISP_TARGET_MODE static ISP_INLINE tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); -static atio_private_data_t *isp_get_atpd(ispsoftc_t *, int, uint32_t); +static atio_private_data_t *isp_get_atpd(ispsoftc_t *, int, uint32_t, void *); static atio_private_data_t *isp_find_atpd(ispsoftc_t *, int, uint32_t); +static atio_private_data_t *isp_find_atpd_ccb(ispsoftc_t *, int, uint32_t, void *); static void isp_put_atpd(ispsoftc_t *, int, atio_private_data_t *); static inot_private_data_t *isp_get_ntpd(ispsoftc_t *, int); static inot_private_data_t *isp_find_ntpd(ispsoftc_t *, int, uint32_t, uint32_t); @@ -715,7 +716,7 @@ isp_tmcmd_restart(ispsoftc_t *isp) } static atio_private_data_t * -isp_get_atpd(ispsoftc_t *isp, int chan, uint32_t tag) +isp_get_atpd(ispsoftc_t *isp, int chan, uint32_t tag, void *ccb) { struct isp_fc *fc = ISP_FC_PC(isp, chan); atio_private_data_t *atp; @@ -723,6 +724,7 @@ isp_get_atpd(ispsoftc_t *isp, int chan, uint32_t tag) atp = LIST_FIRST(&fc->atfree); if (atp) { LIST_REMOVE(atp, next); + atp->ccb = ccb; atp->tag = tag; LIST_INSERT_HEAD(&fc->atused[ATPDPHASH(tag)], atp, next); } @@ -742,6 +744,23 @@ isp_find_atpd(ispsoftc_t *isp, int chan, uint32_t tag) return (NULL); } +/* + * Similar to above, but in addition to tag searches for opaque CCB pointer, + * It can be used in situations when the tag alone may already be reused. + */ +static atio_private_data_t * +isp_find_atpd_ccb(ispsoftc_t *isp, int chan, uint32_t tag, void *ccb) +{ + struct isp_fc *fc = ISP_FC_PC(isp, chan); + atio_private_data_t *atp; + + LIST_FOREACH(atp, &fc->atused[ATPDPHASH(tag)], next) { + if (atp->tag == tag && atp->ccb == ccb) + return (atp); + } + return (NULL); +} + static void isp_put_atpd(ispsoftc_t *isp, int chan, atio_private_data_t *atp) { @@ -967,16 +986,6 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) continue; } - /* - * Is this command a dead duck? - */ - if (atp->dead) { - isp_prt(isp, ISP_LOGERR, "%s: [0x%x] not sending a CTIO for a dead command", __func__, cso->tag_id); - ccb->ccb_h.status = CAM_REQ_ABORTED; - xpt_done(ccb); - continue; - } - /* * Check to make sure we're still in target mode. */ @@ -1378,7 +1387,7 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) */ goto noresrc; } - atp = isp_get_atpd(isp, chan, aep->at_rxid); + atp = isp_get_atpd(isp, chan, aep->at_rxid, atiop); if (atp == NULL) { isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid); isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); @@ -1733,32 +1742,8 @@ isp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp, uint32_ /* * This case is for a responding to an ABTS frame */ - if (mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) { - - /* - * Overload nt_need_ack here to mark whether we've terminated the associated command. - */ - if (mp->nt_need_ack) { - abts_t *abts = (abts_t *)mp->nt_lreserved; - - ISP_MEMZERO(cto, sizeof (ct7_entry_t)); - isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task); - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; - cto->ct_header.rqs_entry_count = 1; - cto->ct_nphdl = mp->nt_nphdl; - cto->ct_rxid = abts->abts_rxid_task; - cto->ct_iid_lo = mp->nt_sid; - cto->ct_iid_hi = mp->nt_sid >> 16; - cto->ct_oxid = abts->abts_ox_id; - cto->ct_vpidx = mp->nt_channel; - cto->ct_flags = CT7_NOACK|CT7_TERMINATE; - if (isp_send_entry(isp, cto)) { - return (ENOMEM); - } - mp->nt_need_ack = 0; - } - return (isp_acknak_abts(isp, mp->nt_lreserved, 0)); - } + if (mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) + return (isp_acknak_abts(isp, mp->nt_lreserved, (rsp == 0) ? 0 : EINVAL)); /* * General purpose acknowledgement @@ -1890,17 +1875,15 @@ bad: } } +/* + * Clean aborted commands pending restart + */ static void isp_target_mark_aborted_early(ispsoftc_t *isp, int chan, tstate_t *tptr, uint32_t tag_id) { - struct isp_fc *fc = ISP_FC_PC(isp, chan); - atio_private_data_t *atp; inot_private_data_t *ntp, *tmp; uint32_t this_tag_id; - /* - * First, clean any commands pending restart - */ STAILQ_FOREACH_SAFE(ntp, &tptr->restart_queue, next, tmp) { this_tag_id = ((at7_entry_t *)ntp->data)->at_rxid; if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) { @@ -1911,16 +1894,6 @@ isp_target_mark_aborted_early(ispsoftc_t *isp, int chan, tstate_t *tptr, uint32_ isp_put_ntpd(isp, chan, ntp); } } - - /* - * Now mark other ones dead as well. - */ - for (atp = fc->atpool; atp < &fc->atpool[ATPDPSIZE]; atp++) { - if (atp->lun != tptr->ts_lun) - continue; - if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) - atp->dead = 1; - } } #endif @@ -2283,6 +2256,25 @@ isp_kthread(void *arg) } #ifdef ISP_TARGET_MODE +static int +isp_abort_atpd(ispsoftc_t *isp, int chan, atio_private_data_t *atp) +{ + uint8_t storage[QENTRY_LEN]; + ct7_entry_t *cto = (ct7_entry_t *) storage; + + ISP_MEMZERO(cto, sizeof (ct7_entry_t)); + cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + cto->ct_header.rqs_entry_count = 1; + cto->ct_nphdl = atp->nphdl; + cto->ct_vpidx = chan; + cto->ct_iid_lo = atp->sid; + cto->ct_iid_hi = atp->sid >> 16; + cto->ct_rxid = atp->tag; + cto->ct_flags = CT7_NOACK|CT7_TERMINATE; + cto->ct_oxid = atp->oxid; + return (isp_send_entry(isp, cto)); +} + static void isp_abort_atio(ispsoftc_t *isp, union ccb *ccb) { @@ -2308,30 +2300,16 @@ isp_abort_atio(ispsoftc_t *isp, union ccb *ccb) } /* Search for the ATIO among running. */ - atp = isp_find_atpd(isp, XS_CHANNEL(accb), accb->atio.tag_id); + atp = isp_find_atpd_ccb(isp, XS_CHANNEL(accb), accb->atio.tag_id, accb); if (atp != NULL) { - /* Send TERMINATE to firmware. */ - if (!atp->dead) { - uint8_t storage[QENTRY_LEN]; - ct7_entry_t *cto = (ct7_entry_t *) storage; - - ISP_MEMZERO(cto, sizeof (ct7_entry_t)); - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; - cto->ct_header.rqs_entry_count = 1; - cto->ct_nphdl = atp->nphdl; - cto->ct_rxid = atp->tag; - cto->ct_iid_lo = atp->sid; - cto->ct_iid_hi = atp->sid >> 16; - cto->ct_oxid = atp->oxid; - cto->ct_vpidx = XS_CHANNEL(accb); - cto->ct_flags = CT7_NOACK|CT7_TERMINATE; - isp_send_entry(isp, cto); + if (isp_abort_atpd(isp, XS_CHANNEL(accb), atp)) { + ccb->ccb_h.status = CAM_UA_ABORT; + return; } isp_put_atpd(isp, XS_CHANNEL(accb), atp); - ccb->ccb_h.status = CAM_REQ_CMP; - } else { - ccb->ccb_h.status = CAM_UA_ABORT; } + + ccb->ccb_h.status = CAM_REQ_CMP; } static void @@ -2504,6 +2482,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) } case XPT_NOTIFY_ACKNOWLEDGE: /* notify ack */ { + atio_private_data_t *atp; inot_private_data_t *ntp; /* @@ -2522,8 +2501,19 @@ isp_action(struct cam_sim *sim, union ccb *ccb) xpt_done(ccb); break; } - if (isp_handle_platform_target_notify_ack(isp, &ntp->nt, - (ccb->ccb_h.flags & CAM_SEND_STATUS) ? ccb->cna2.arg : 0)) { + + /* + * Target should abort all affected CCBs before ACK-ing INOT, + * but if/since it doesn't, add this hack to allow tag reuse. + */ + uint32_t rsp = (ccb->ccb_h.flags & CAM_SEND_STATUS) ? ccb->cna2.arg : 0; + if (ntp->nt.nt_ncode == NT_ABORT_TASK && (rsp & 0xff) == 0 && + (atp = isp_find_atpd(isp, XS_CHANNEL(ccb), ccb->cna2.seq_id)) != NULL) { + if (isp_abort_atpd(isp, XS_CHANNEL(ccb), atp) == 0) + isp_put_atpd(isp, XS_CHANNEL(ccb), atp); + } + + if (isp_handle_platform_target_notify_ack(isp, &ntp->nt, rsp)) { cam_freeze_devq(ccb->ccb_h.path); cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 10, 0); ccb->ccb_h.status &= ~CAM_STATUS_MASK; diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index bd5bba92c0a9..5bb3dd43b6de 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -89,10 +89,11 @@ void isp_put_ecmd(struct ispsoftc *, isp_ecmd_t *); #include <dev/isp/isp_target.h> typedef struct atio_private_data { LIST_ENTRY(atio_private_data) next; + void * ccb; + uint32_t tag; /* typically f/w RX_ID */ uint32_t orig_datalen; uint32_t bytes_xfered; uint32_t bytes_in_transit; - uint32_t tag; /* typically f/w RX_ID */ lun_id_t lun; uint32_t nphdl; uint32_t sid; @@ -102,11 +103,9 @@ typedef struct atio_private_data { uint16_t word3; /* PRLI word3 params */ uint16_t ctcnt; /* number of CTIOs currently active */ uint8_t seqno; /* CTIO sequence number */ - uint32_t - srr_notify_rcvd : 1, - cdb0 : 8, + uint8_t cdb0; + uint8_t srr_notify_rcvd : 1, sendst : 1, - dead : 1, tattr : 3, state : 3; void * ests; diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c index 081524aff53c..9d8f8e2a3766 100644 --- a/sys/dev/isp/isp_target.c +++ b/sys/dev/isp/isp_target.c @@ -481,10 +481,14 @@ isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) ISP_MEMCPY(rsp, abts, QENTRY_LEN); rsp->abts_rsp_header.rqs_entry_type = RQSTYPE_ABTS_RSP; + isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS of 0x%x being %s'd", + rsp->abts_rsp_rxid_abts, rsp->abts_rsp_rxid_task, + (errno == 0) ? "BA_ACC" : "BA_RJT"); + rsp->abts_rsp_r_ctl = (errno == 0) ? BA_ACC : BA_RJT; + /* * Swap destination and source for response. */ - rsp->abts_rsp_r_ctl = BA_ACC; tmpw = rsp->abts_rsp_did_lo; tmpb = rsp->abts_rsp_did_hi; rsp->abts_rsp_did_lo = rsp->abts_rsp_sid_lo; @@ -505,15 +509,14 @@ isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) rx_id = rsp->abts_rsp_rx_id; ox_id = rsp->abts_rsp_ox_id; ISP_MEMZERO(&rsp->abts_rsp_payload.ba_acc, sizeof (rsp->abts_rsp_payload.ba_acc)); - isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS of 0x%x being BA_ACC'd", rsp->abts_rsp_rxid_abts, rsp->abts_rsp_rxid_task); rsp->abts_rsp_payload.ba_acc.aborted_rx_id = rx_id; rsp->abts_rsp_payload.ba_acc.aborted_ox_id = ox_id; rsp->abts_rsp_payload.ba_acc.high_seq_cnt = 0xffff; } else { - ISP_MEMZERO(&rsp->abts_rsp_payload.ba_rjt, sizeof (rsp->abts_rsp_payload.ba_acc)); + ISP_MEMZERO(&rsp->abts_rsp_payload.ba_rjt, sizeof (rsp->abts_rsp_payload.ba_rjt)); switch (errno) { case ENOMEM: - rsp->abts_rsp_payload.ba_rjt.reason = 5; /* Logical Unit Busy */ + rsp->abts_rsp_payload.ba_rjt.reason = 5; /* Logical busy */ break; default: rsp->abts_rsp_payload.ba_rjt.reason = 9; /* Unable to perform command request */