Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/mpr/mpr_sas_lsi.c
Show First 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
static void mprsas_fw_event_free(struct mpr_softc *, | static void mprsas_fw_event_free(struct mpr_softc *, | ||||
struct mpr_fw_event_work *); | struct mpr_fw_event_work *); | ||||
static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate); | static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate); | ||||
static int mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, | static int mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, | ||||
u8 linkrate); | u8 linkrate); | ||||
static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, | static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, | ||||
Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, | Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, | ||||
u32 devinfo); | u32 devinfo); | ||||
static void mprsas_ata_id_timeout(void *data); | static void mprsas_ata_id_timeout(struct mpr_softc *, struct mpr_command *); | ||||
int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, | int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, | ||||
u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD); | u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD); | ||||
static int mprsas_volume_add(struct mpr_softc *sc, | static int mprsas_volume_add(struct mpr_softc *sc, | ||||
u16 handle); | u16 handle); | ||||
static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc, int howto); | static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc, int howto); | ||||
static void mprsas_stop_unit_done(struct cam_periph *periph, | static void mprsas_stop_unit_done(struct cam_periph *periph, | ||||
union ccb *done_ccb); | union ccb *done_ccb); | ||||
▲ Show 20 Lines • Show All 1,026 Lines • ▼ Show 20 Lines | mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, | ||||
cm->cm_sge = &mpi_request->SGL; | cm->cm_sge = &mpi_request->SGL; | ||||
cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); | cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); | ||||
cm->cm_flags = MPR_CM_FLAGS_DATAIN; | cm->cm_flags = MPR_CM_FLAGS_DATAIN; | ||||
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; | cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; | ||||
cm->cm_data = buffer; | cm->cm_data = buffer; | ||||
cm->cm_length = htole32(sz); | cm->cm_length = htole32(sz); | ||||
/* | /* | ||||
* Start a timeout counter specifically for the SATA ID command. This | * Use a custom handler to avoid reinit'ing the controller on timeout. | ||||
* is used to fix a problem where the FW does not send a reply sometimes | * This fixes a problem where the FW does not send a reply sometimes | ||||
* when a bad disk is in the topology. So, this is used to timeout the | * when a bad disk is in the topology. So, this is used to timeout the | ||||
* command so that processing can continue normally. | * command so that processing can continue normally. | ||||
*/ | */ | ||||
mpr_dprint(sc, MPR_XINFO, "%s start timeout counter for SATA ID " | cm->cm_timeout_handler = mprsas_ata_id_timeout; | ||||
"command\n", __func__); | |||||
callout_reset(&cm->cm_callout, MPR_ATA_ID_TIMEOUT * hz, | |||||
mprsas_ata_id_timeout, cm); | |||||
error = mpr_wait_command(sc, &cm, 60, CAN_SLEEP); | |||||
mpr_dprint(sc, MPR_XINFO, "%s stop timeout counter for SATA ID " | |||||
"command\n", __func__); | |||||
/* XXX KDM need to fix the case where this command is destroyed */ | |||||
callout_stop(&cm->cm_callout); | |||||
if (cm != NULL) | error = mpr_wait_command(sc, &cm, MPR_ATA_ID_TIMEOUT, CAN_SLEEP); | ||||
/* mprsas_ata_id_timeout does not reset controller */ | |||||
KASSERT(cm != NULL, ("%s: surprise command freed", __func__)); | |||||
reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; | reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; | ||||
if (error || (reply == NULL)) { | if (error || (reply == NULL)) { | ||||
/* FIXME */ | /* FIXME */ | ||||
/* | /* | ||||
* If the request returns an error then we need to do a diag | * If the request returns an error then we need to do a diag | ||||
* reset | * reset | ||||
*/ | */ | ||||
mpr_dprint(sc, MPR_INFO|MPR_FAULT|MPR_MAPPING, | mpr_dprint(sc, MPR_INFO|MPR_FAULT|MPR_MAPPING, | ||||
"Request for SATA PASSTHROUGH page completed with error %d", | "Request for SATA PASSTHROUGH page completed with error %d", | ||||
Show All 10 Lines | mpr_dprint(sc, MPR_INFO|MPR_MAPPING|MPR_FAULT, | ||||
handle, reply->IOCStatus); | handle, reply->IOCStatus); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto out; | goto out; | ||||
} | } | ||||
out: | out: | ||||
/* | /* | ||||
* If the SATA_ID_TIMEOUT flag has been set for this command, don't free | * 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 | * it. The command and buffer will be freed after sending an Abort | ||||
* Task TM. If the command did timeout, use EWOULDBLOCK. | * Task TM. | ||||
*/ | */ | ||||
if ((cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) == 0) { | if ((cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) == 0) { | ||||
mpr_free_command(sc, cm); | mpr_free_command(sc, cm); | ||||
free(buffer, M_MPR); | free(buffer, M_MPR); | ||||
} else if (error == 0) | } | ||||
error = EWOULDBLOCK; | |||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
mprsas_ata_id_timeout(void *data) | mprsas_ata_id_timeout(struct mpr_softc *sc, struct mpr_command *cm) | ||||
{ | { | ||||
struct mpr_softc *sc; | |||||
struct mpr_command *cm; | |||||
cm = (struct mpr_command *)data; | mpr_dprint(sc, MPR_INFO, "%s ATA ID command timeout cm %p sc %p\n", | ||||
sc = cm->cm_sc; | |||||
mtx_assert(&sc->mpr_mtx, MA_OWNED); | |||||
mpr_dprint(sc, MPR_INFO, "%s checking ATA ID command %p sc %p\n", | |||||
__func__, cm, sc); | __func__, cm, sc); | ||||
if ((callout_pending(&cm->cm_callout)) || | |||||
(!callout_active(&cm->cm_callout))) { | |||||
mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed out\n", | |||||
__func__); | |||||
return; | |||||
} | |||||
callout_deactivate(&cm->cm_callout); | |||||
/* | /* | ||||
* Run the interrupt handler to make sure it's not pending. This | * The Abort Task cannot be sent from here because the driver has not | ||||
* isn't perfect because the command could have already completed | * completed setting up targets. Instead, the command is flagged so | ||||
* and been re-used, though this is unlikely. | * that special handling will be used to send the abort. | ||||
*/ | */ | ||||
mpr_intr_locked(sc); | |||||
if (cm->cm_state == MPR_CM_STATE_FREE) { | |||||
mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed out\n", | |||||
__func__); | |||||
return; | |||||
} | |||||
mpr_dprint(sc, MPR_INFO, "ATA ID command timeout cm %p\n", cm); | |||||
/* | |||||
* Send wakeup() to the sleeping thread that issued this ATA ID command. | |||||
* wakeup() will cause msleep to return a 0 (not EWOULDBLOCK), and this | |||||
* will keep reinit() from being called. This way, an Abort Task TM can | |||||
* be issued so that the timed out command can be cleared. 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. | |||||
*/ | |||||
cm->cm_flags |= MPR_CM_FLAGS_SATA_ID_TIMEOUT; | cm->cm_flags |= MPR_CM_FLAGS_SATA_ID_TIMEOUT; | ||||
wakeup(cm); | |||||
} | } | ||||
static int | static int | ||||
mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate) | mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate) | ||||
{ | { | ||||
char devstring[80]; | char devstring[80]; | ||||
struct mprsas_softc *sassc; | struct mprsas_softc *sassc; | ||||
struct mprsas_target *targ; | struct mprsas_target *targ; | ||||
▲ Show 20 Lines • Show All 440 Lines • Show Last 20 Lines |