Index: sys/dev/mpr/mpr_sas.h =================================================================== --- sys/dev/mpr/mpr_sas.h +++ sys/dev/mpr/mpr_sas.h @@ -64,6 +64,7 @@ SLIST_HEAD(, mprsas_lun) luns; TAILQ_HEAD(, mpr_command) commands; struct mpr_command *tm; + struct mpr_command *pending_remove_tm; TAILQ_HEAD(, mpr_command) timedout_commands; uint16_t exp_dev_handle; uint16_t phy_num; Index: sys/dev/mpr/mpr_sas.c =================================================================== --- sys/dev/mpr/mpr_sas.c +++ sys/dev/mpr/mpr_sas.c @@ -559,7 +559,6 @@ MPI2_SCSI_TASK_MANAGE_REPLY *reply; MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; struct mprsas_target *targ; - struct mpr_command *next_cm; uint16_t handle; MPR_FUNCTRACE(sc); @@ -593,7 +592,7 @@ "device 0x%x\n", le16toh(reply->IOCStatus), handle); } - mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", + mpr_dprint(sc, MPR_INFO, "Reset aborted %u commands\n", le32toh(reply->TerminationCount)); mpr_free_reply(sc, tm->cm_reply_data); tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ @@ -609,8 +608,18 @@ tm->cm_complete = mprsas_remove_complete; tm->cm_complete_data = (void *)(uintptr_t)handle; - mpr_map_command(sc, tm); - + /* + * Wait to send the REMOVE_DEVICE until all the commands have cleared. + * They should be aborted or time out and we'll kick thus off there + * if so. + */ + if (TAILQ_FIRST(&targ->commands) == NULL) { + mpr_dprint(sc, MPR_INFO, "No race: starting remove_device\n"); + mpr_map_command(sc, tm); + targ->pending_remove_tm = NULL; + } else { + targ->pending_remove_tm = tm; + } mpr_dprint(sc, MPR_INFO, "clearing target %u handle 0x%04x\n", targ->tid, handle); if (targ->encl_level_valid) { @@ -618,15 +627,6 @@ "connector name (%4s)\n", targ->encl_level, targ->encl_slot, targ->connector_name); } - TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { - union ccb *ccb; - - mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); - ccb = tm->cm_complete_data; - mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); - tm->cm_state = MPR_CM_STATE_BUSY; - mprsas_scsiio_complete(sc, tm); - } } static void @@ -663,7 +663,7 @@ return; } - mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", + mpr_dprint(sc, MPR_INFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__, handle, le16toh(reply->IOCStatus)); /* @@ -1970,7 +1970,7 @@ if (targ->devinfo == 0) mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); else - mprsas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } @@ -2846,17 +2846,33 @@ * causes a command addressed to a drive to fail), but * avoiding getting into an infinite retry loop. */ - mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); - mpr_dprint(sc, MPR_INFO, - "Controller reported %s tgt %u SMID %u loginfo %x\n", - mpr_describe_table(mpr_iocstatus_string, - le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK), - target_id, cm->cm_desc.Default.SMID, - le32toh(rep->IOCLogInfo)); - mpr_dprint(sc, MPR_XINFO, - "SCSIStatus %x SCSIState %x xfercount %u\n", - rep->SCSIStatus, rep->SCSIState, - le32toh(rep->TransferCount)); + if (target->flags & MPRSAS_TARGET_INREMOVAL) { + /* + * We've kicked off the removal protocol. We'll wait + * to do the final remove until all the pending + * commands for the target are done to do that. + * XXX not sure what to do about timedout commands + */ + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + mpr_dprint(sc, MPR_INFO, "Aborted %p\n", cm); + if (TAILQ_FIRST(&target->commands) == NULL) { + mpr_dprint(sc, MPR_INFO, "Last one, starting remove_device\n"); + mpr_map_command(sc, target->pending_remove_tm); + target->pending_remove_tm = NULL; + } + } else { + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); + mpr_dprint(sc, MPR_INFO, + "Controller reported %s tgt %u SMID %u loginfo %x\n", + mpr_describe_table(mpr_iocstatus_string, + le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK), + target_id, cm->cm_desc.Default.SMID, + le32toh(rep->IOCLogInfo)); + mpr_dprint(sc, MPR_XINFO, + "SCSIStatus %x SCSIState %x xfercount %u\n", + rep->SCSIStatus, rep->SCSIState, + le32toh(rep->TransferCount)); + } break; case MPI2_IOCSTATUS_INVALID_FUNCTION: case MPI2_IOCSTATUS_INTERNAL_ERROR: