DF-3984 / fix.diff
--- a/sys/dev/disk/sbp/sbp.c +++ b/sys/dev/disk/sbp/sbp.c @@ -182,6 +182,9 @@ struct sbp_login_res *login; struct callout login_callout; struct sbp_ocb *ocb; + /* DF-3984: recently-completed mgm ORB address; a status replay must + * not match the recycled command ORB that now owns this address. */ + u_int32_t stale_orb_lo; STAILQ_HEAD(, sbp_ocb) ocbs; STAILQ_HEAD(, sbp_ocb) free_ocbs; char vendor[32]; @@ -1599,6 +1602,7 @@ if (OCB_MATCH(ocb, sbp_status)) { callout_stop(&target->mgm_ocb_timeout); target->mgm_ocb_cur = NULL; + sdev->stale_orb_lo = ntohl(sbp_status->orb_lo); break; } } @@ -2583,6 +2587,18 @@ END_DEBUG for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) { next = STAILQ_NEXT(ocb, ocb); + if (sdev->stale_orb_lo != 0 && + ntohl(sbp_status->orb_lo) == sdev->stale_orb_lo) { + /* replayed mgm status: matches only the recycled + * command ORB that inherited the address (DF-3984) */ + kprintf("sbp%d:%d: stale mgm status replay " + "(orb 0x%08x) dropped\n", + device_get_unit(sdev->target->sbp->fd.dev), + sdev->lun_id, sdev->stale_orb_lo); + sdev->stale_orb_lo = 0; + crit_exit(); + return (NULL); + } if (OCB_MATCH(ocb, sbp_status)) { /* found */ STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb); |