aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mps/mps_sas_lsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mps/mps_sas_lsi.c')
-rw-r--r--sys/dev/mps/mps_sas_lsi.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/sys/dev/mps/mps_sas_lsi.c b/sys/dev/mps/mps_sas_lsi.c
index cc207f7f1dfb..8cfb1700c705 100644
--- a/sys/dev/mps/mps_sas_lsi.c
+++ b/sys/dev/mps/mps_sas_lsi.c
@@ -123,6 +123,7 @@ static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate);
static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
u32 devinfo);
+static void mpssas_ata_id_complete(struct mps_softc *, struct mps_command *);
static void mpssas_ata_id_timeout(struct mps_softc *, struct mps_command *);
int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD);
@@ -780,7 +781,8 @@ mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
* An Abort Task TM should be used instead of a Target Reset, but that
* would be much more difficult because targets have not been fully
* discovered yet, and LUN's haven't been setup. So, just reset the
- * target instead of the LUN.
+ * target instead of the LUN. The commands should complete once the
+ * target has been reset.
*/
for (i = 1; i < sc->num_reqs; i++) {
cm = &sc->commands[i];
@@ -808,16 +810,6 @@ mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
}
}
out:
- /*
- * Free the commands that may not have been freed from the SATA ID call
- */
- for (i = 1; i < sc->num_reqs; i++) {
- cm = &sc->commands[i];
- if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
- free(cm->cm_data, M_MPT2);
- mps_free_command(sc, cm);
- }
- }
mpssas_startup_decrement(sassc);
return (error);
}
@@ -993,8 +985,8 @@ mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
out:
/*
* If the SATA_ID_TIMEOUT flag has been set for this command, don't free
- * it. The command and buffer will be freed after sending an Abort
- * Task TM.
+ * it. The command and buffer will be freed after we send a Target
+ * Reset TM and the command comes back from the controller.
*/
if ((cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) == 0) {
mps_free_command(sc, cm);
@@ -1003,21 +995,41 @@ out:
return (error);
}
+/*
+ * This is completion handler to make sure that commands and allocated
+ * buffers get freed when timed out SATA ID commands finally complete after
+ * we've reset the target. In the normal case, we wait for the command to
+ * complete.
+ */
static void
-mpssas_ata_id_timeout(struct mps_softc *sc, struct mps_command *cm)
+mpssas_ata_id_complete(struct mps_softc *sc, struct mps_command *cm)
{
+ mps_dprint(sc, MPS_INFO, "%s ATA ID completed late cm %p sc %p\n",
+ __func__, cm, sc);
+
+ free(cm->cm_data, M_MPT2);
+ mps_free_command(sc, cm);
+}
+
+static void
+mpssas_ata_id_timeout(struct mps_softc *sc, struct mps_command *cm)
+{
mps_dprint(sc, MPS_INFO, "%s ATA ID command timeout cm %p sc %p\n",
__func__, cm, sc);
/*
* The Abort Task cannot be sent from here because the driver has not
* completed setting up targets. Instead, the command is flagged so
- * that special handling will be used to send the abort. Now that
- * this command has timed out, it's no longer in the queue.
+ * that special handling will be used to send a target reset.
*/
cm->cm_flags |= MPS_CM_FLAGS_SATA_ID_TIMEOUT;
- cm->cm_state = MPS_CM_STATE_BUSY;
+
+ /*
+ * Since we will no longer be waiting for the command to complete,
+ * set a completion handler to make sure we free all resources.
+ */
+ cm->cm_complete = mpssas_ata_id_complete;
}
static int