diff options
| author | Alexander Motin <mav@FreeBSD.org> | 2024-12-09 16:52:26 +0000 |
|---|---|---|
| committer | Alexander Motin <mav@FreeBSD.org> | 2024-12-23 14:34:21 +0000 |
| commit | 1fd197d19221341e29a59351d0cb537d295eb047 (patch) | |
| tree | 1193279868b8be37dc9b43202cc4f882f79cc38e /sys/dev/isp | |
| parent | 71656857b308062fb1030d2ed5650a93c20f16d6 (diff) | |
Diffstat (limited to 'sys/dev/isp')
| -rw-r--r-- | sys/dev/isp/isp_freebsd.c | 142 | ||||
| -rw-r--r-- | sys/dev/isp/isp_freebsd.h | 9 | ||||
| -rw-r--r-- | 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) { @@ -968,16 +987,6 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) } /* - * 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. */ fcp = FCPARAM(isp, XS_CHANNEL(ccb)); @@ -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 */ |
