Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/mps/mps_sas_lsi.c
Show First 20 Lines • Show All 1,111 Lines • ▼ Show 20 Lines | |||||
mpssas_SSU_to_SATA_devices(struct mps_softc *sc) | mpssas_SSU_to_SATA_devices(struct mps_softc *sc) | ||||
{ | { | ||||
struct mpssas_softc *sassc = sc->sassc; | struct mpssas_softc *sassc = sc->sassc; | ||||
union ccb *ccb; | union ccb *ccb; | ||||
path_id_t pathid = cam_sim_path(sassc->sim); | path_id_t pathid = cam_sim_path(sassc->sim); | ||||
target_id_t targetid; | target_id_t targetid; | ||||
struct mpssas_target *target; | struct mpssas_target *target; | ||||
char path_str[64]; | char path_str[64]; | ||||
struct timeval cur_time, start_time; | |||||
/* | /* | ||||
* For each target, issue a StartStopUnit command to stop the device. | * Disable interrupts now because shutdown is in progress and don't want | ||||
* to rely on ISR to complete these. So polling must be done here as | |||||
* well. | |||||
*/ | */ | ||||
sc->SSU_started = TRUE; | mps_mask_intr(sc); | ||||
sc->SSU_refcount = 0; | |||||
for (targetid = 0; targetid < sc->max_devices; targetid++) { | for (targetid = 0; targetid < sc->max_devices; targetid++) { | ||||
target = &sassc->targets[targetid]; | target = &sassc->targets[targetid]; | ||||
if (target->handle == 0x0) { | if (target->handle == 0x0) { | ||||
continue; | continue; | ||||
} | } | ||||
ccb = xpt_alloc_ccb_nowait(); | ccb = xpt_alloc_ccb_nowait(); | ||||
if (ccb == NULL) { | if (ccb == NULL) { | ||||
Show All 17 Lines | if (target->stop_at_shutdown) { | ||||
} | } | ||||
xpt_path_string(ccb->ccb_h.path, path_str, | xpt_path_string(ccb->ccb_h.path, path_str, | ||||
sizeof(path_str)); | sizeof(path_str)); | ||||
mps_dprint(sc, MPS_INFO, "Sending StopUnit: path %s " | mps_dprint(sc, MPS_INFO, "Sending StopUnit: path %s " | ||||
"handle %d\n", path_str, target->handle); | "handle %d\n", path_str, target->handle); | ||||
/* | /* | ||||
* Issue a START STOP UNIT command for the target. | * Issue a START STOP UNIT command for the target and | ||||
* Increment the SSU counter to be used to count the | * poll for completion. | ||||
* number of required replies. | |||||
*/ | */ | ||||
mps_dprint(sc, MPS_INFO, "Incrementing SSU count\n"); | |||||
sc->SSU_refcount++; | |||||
ccb->ccb_h.target_id = | ccb->ccb_h.target_id = | ||||
xpt_path_target_id(ccb->ccb_h.path); | xpt_path_target_id(ccb->ccb_h.path); | ||||
ccb->ccb_h.ppriv_ptr1 = sassc; | ccb->ccb_h.ppriv_ptr1 = sassc; | ||||
scsi_start_stop(&ccb->csio, | scsi_start_stop(&ccb->csio, | ||||
/*retries*/0, | /*retries*/0, | ||||
mpssas_stop_unit_done, | mpssas_stop_unit_done, | ||||
MSG_SIMPLE_Q_TAG, | MSG_SIMPLE_Q_TAG, | ||||
/*start*/FALSE, | /*start*/FALSE, | ||||
/*load/eject*/0, | /*load/eject*/0, | ||||
/*immediate*/FALSE, | /*immediate*/FALSE, | ||||
MPS_SENSE_LEN, | MPS_SENSE_LEN, | ||||
/*timeout*/10000); | /*timeout*/10000); | ||||
xpt_action(ccb); | xpt_polled_action(ccb); | ||||
ken: xpt_polled_action() does not cause the done routine to get called. Or at least it shouldn't. | |||||
} | } | ||||
} | } | ||||
/* | |||||
* Wait until all of the SSU commands have completed or time has | |||||
* expired (60 seconds). Pause for 100ms each time through. If any | |||||
* command times out, the target will be reset in the SCSI command | |||||
* timeout routine. | |||||
*/ | |||||
getmicrotime(&start_time); | |||||
while (sc->SSU_refcount) { | |||||
pause("mpswait", hz/10); | |||||
getmicrotime(&cur_time); | |||||
if ((cur_time.tv_sec - start_time.tv_sec) > 60) { | |||||
mps_dprint(sc, MPS_FAULT, "Time has expired waiting " | |||||
"for SSU commands to complete.\n"); | |||||
break; | |||||
} | } | ||||
} | |||||
} | |||||
static void | static void | ||||
mpssas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb) | mpssas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb) | ||||
{ | { | ||||
struct mpssas_softc *sassc; | struct mpssas_softc *sassc; | ||||
char path_str[64]; | char path_str[64]; | ||||
if (done_ccb == NULL) | if (done_ccb == NULL) | ||||
return; | return; | ||||
sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; | sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; | ||||
xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); | xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); | ||||
mps_dprint(sassc->sc, MPS_INFO, "Completing stop unit for %s\n", | mps_dprint(sassc->sc, MPS_INFO, "Completing stop unit for %s\n", | ||||
path_str); | path_str); | ||||
/* | /* | ||||
* Nothing more to do except free the CCB and path. If the command | * Nothing more to do except free the CCB and path. | ||||
* timed out, an abort reset, then target reset will be issued during | |||||
* the SCSI Command process. | |||||
*/ | */ | ||||
xpt_free_path(done_ccb->ccb_h.path); | xpt_free_path(done_ccb->ccb_h.path); | ||||
xpt_free_ccb(done_ccb); | xpt_free_ccb(done_ccb); | ||||
} | } | ||||
/** | /** | ||||
* mpssas_ir_shutdown - IR shutdown notification | * mpssas_ir_shutdown - IR shutdown notification | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
▲ Show 20 Lines • Show All 114 Lines • Show Last 20 Lines |
xpt_polled_action() does not cause the done routine to get called. Or at least it shouldn't. You'll need to do the cleanup (free the CCB and path) that has been going on in mpssas_stop_unit_done().
Also, according to Harald Schmalzbauer, this panics on shutdown. It looks like you probably need to acquire the device mutex before xpt_polled_action() and release it afterwards.
Take a look at how dadump() from the da(4) driver interacts with xpt_polled_action().