static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo) { Mpi2SataPassthroughRequest_t *mpi_request; Mpi2SataPassthroughReply_t *reply; struct mps_command *cm; char *buffer; int error = 0; buffer = kmalloc( sz, M_MPT2, M_NOWAIT | M_ZERO); if (!buffer) return ENOMEM; if ((cm = mps_alloc_command(sc)) == NULL) { kfree(buffer, M_MPT2); return (EBUSY); } mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req; bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST)); mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH; mpi_request->VF_ID = 0; mpi_request->DevHandle = htole16(handle); mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO | MPI2_SATA_PT_REQ_PT_FLAGS_READ); mpi_request->DataLength = htole32(sz); mpi_request->CommandFIS[0] = 0x27; mpi_request->CommandFIS[1] = 0x80; mpi_request->CommandFIS[2] = (devinfo & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC; cm->cm_sge = &mpi_request->SGL; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = buffer; cm->cm_length = htole32(sz); error = mps_request_polled(sc, cm); reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ kprintf("%s: poll for page completed with error %d", __func__, error); error = ENXIO; goto out; } bcopy(buffer, id_buffer, sz); bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t)); if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { kprintf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n", __func__, reply->IOCStatus); error = ENXIO; goto out; } out: mps_free_command(sc, cm); kfree(buffer, M_MPT2); return (error); }
/** * mpssas_ir_shutdown - IR shutdown notification * @sc: per adapter object * * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that * the host system is shutting down. * * Return nothing. */ void mpssas_ir_shutdown(struct mps_softc *sc) { u16 volume_mapping_flags; u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); struct dev_mapping_table *mt_entry; u32 start_idx, end_idx; unsigned int id, found_volume = 0; struct mps_command *cm; Mpi2RaidActionRequest_t *action; mps_lock(sc); mps_dprint(sc, MPS_TRACE, "%s\n", __func__); /* is IR firmware build loaded? */ if (!sc->ir_firmware) goto back; /* are there any volumes? Look at IR target IDs. */ // TODO-later, this should be looked up in the RAID config structure // when it is implemented. volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { start_idx = 0; if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) start_idx = 1; } else start_idx = sc->max_devices - sc->max_volumes; end_idx = start_idx + sc->max_volumes - 1; for (id = start_idx; id < end_idx; id++) { mt_entry = &sc->mapping_table[id]; if ((mt_entry->physical_id != 0) && (mt_entry->missing_count == 0)) { found_volume = 1; break; } } if (!found_volume) goto back; if ((cm = mps_alloc_command(sc)) == NULL) { kprintf("%s: command alloc failed\n", __func__); goto back; } action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; action->Function = MPI2_FUNCTION_RAID_ACTION; action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; mps_request_polled(sc, cm); /* * Don't check for reply, just leave. */ if (cm) mps_free_command(sc, cm); back: mps_unlock(sc); }
/** * mps_config_get_bios_pg3 - obtain BIOS page 3 * @sc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page * Context: sleep. * * Returns 0 for success, non-zero for failure. */ int mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage3_t *config_page) { MPI2_CONFIG_REQUEST *request; MPI2_CONFIG_REPLY *reply; struct mps_command *cm; Mpi2BiosPage3_t *page = NULL; int error = 0; u16 ioc_status; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; request->Header.PageNumber = 3; request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = NULL; error = mps_wait_command(sc, cm, 60, CAN_SLEEP); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: request for header completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: header read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } /* We have to do free and alloc for the reply-free and reply-post * counters to match - Need to review the reply FIFO handling. */ mps_free_command(sc, cm); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; request->Header.PageNumber = 3; request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; request->Header.PageLength = mpi_reply->Header.PageLength; cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; cm->cm_sge = &request->PageBufferSGE; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); if (!page) { printf("%s: page alloc failed\n", __func__); error = ENOMEM; goto out; } cm->cm_data = page; error = mps_wait_command(sc, cm, 60, CAN_SLEEP); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: request for page completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: page read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t))); out: free(page, M_MPT2); if (cm) mps_free_command(sc, cm); return (error); }
/** * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags * accordingly. Currently, this page does not need to return to caller. * @sc: per adapter object * @mpi_reply: reply mf payload returned from firmware * Context: sleep. * * Returns 0 for success, non-zero for failure. */ int mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply) { MPI2_CONFIG_REQUEST *request; MPI2_CONFIG_REPLY *reply; struct mps_command *cm; pMpi2ManufacturingPagePS_t page = NULL; uint32_t *pPS_info; uint8_t OEM_Value = 0; int error = 0; u16 ioc_status; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; request->Header.PageNumber = 10; request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = NULL; /* * This page must be polled because the IOC isn't ready yet when this * page is needed. */ error = mps_request_polled(sc, cm); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: poll for header completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: header read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } /* We have to do free and alloc for the reply-free and reply-post * counters to match - Need to review the reply FIFO handling. */ mps_free_command(sc, cm); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; request->Header.PageNumber = 10; request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION; request->Header.PageLength = mpi_reply->Header.PageLength; cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; cm->cm_sge = &request->PageBufferSGE; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT); if (!page) { printf("%s: page alloc failed\n", __func__); error = ENOMEM; goto out; } cm->cm_data = page; /* * This page must be polled because the IOC isn't ready yet when this * page is needed. */ error = mps_request_polled(sc, cm); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: poll for page completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: page read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } /* * If OEM ID is unknown, fail the request. */ sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS; OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF); if (OEM_Value != MPS_WD_LSI_OEM) { mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive " "(0x%x)\n", OEM_Value); error = ENXIO; goto out; } /* * Set the phys disks hide/expose value. */ pPS_info = &page->ProductSpecificInfo; sc->WD_hide_expose = (uint8_t)(pPS_info[5]); sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK; if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) && (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) && (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) { mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive " "hide/expose: 0x%x\n", sc->WD_hide_expose); error = ENXIO; goto out; } out: free(page, M_MPT2); if (cm) mps_free_command(sc, cm); return (error); }
int mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, Mpi2DriverMappingPage0_t *config_page, u16 entry_idx) { MPI2_CONFIG_REQUEST *request; MPI2_CONFIG_REPLY *reply; struct mps_command *cm; MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL; int error = 0; u16 ioc_status; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; request->Header.PageNumber = 0; request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; /* We can remove below two lines ????*/ request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; request->PageAddress |= htole16(entry_idx); cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = NULL; error = mps_wait_command(sc, cm, 60, CAN_SLEEP); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: request for header completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: header read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } /* We have to do free and alloc for the reply-free and reply-post * counters to match - Need to review the reply FIFO handling. */ mps_free_command(sc, cm); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; request->Header.PageNumber = 0; request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; request->ExtPageLength = mpi_reply->ExtPageLength; request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; request->PageAddress |= htole16(entry_idx); cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4; cm->cm_sge = &request->PageBufferSGE; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); if (!page) { printf("%s: page alloc failed\n", __func__); error = ENOMEM; goto out; } bcopy(config_page, page, MIN(cm->cm_length, (sizeof(Mpi2DriverMappingPage0_t)))); cm->cm_data = page; error = mps_wait_command(sc, cm, 60, CAN_SLEEP); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: request to write page completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: page written with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } out: free(page, M_MPT2); if (cm) mps_free_command(sc, cm); return (error); }
/** * mps_config_get_pd_pg0 - obtain raid phys disk page 0 * @sc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page * @page_address: form and handle value used to get page * Context: sleep. * * Returns 0 for success, non-zero for failure. */ int mps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address) { MPI2_CONFIG_REQUEST *request; MPI2_CONFIG_REPLY *reply; struct mps_command *cm; Mpi2RaidPhysDiskPage0_t *page = NULL; int error = 0; u16 ioc_status; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; request->Header.PageNumber = 0; request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = NULL; /* * This page must be polled because the IOC isn't ready yet when this * page is needed. */ error = mps_request_polled(sc, cm); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: poll for header completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: header read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } /* We have to do free and alloc for the reply-free and reply-post * counters to match - Need to review the reply FIFO handling. */ mps_free_command(sc, cm); if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed @ line %d\n", __func__, __LINE__); error = EBUSY; goto out; } request = (MPI2_CONFIG_REQUEST *)cm->cm_req; bzero(request, sizeof(MPI2_CONFIG_REQUEST)); request->Function = MPI2_FUNCTION_CONFIG; request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; request->Header.PageNumber = 0; request->Header.PageLength = mpi_reply->Header.PageLength; request->Header.PageVersion = mpi_reply->Header.PageVersion; request->PageAddress = page_address; cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; cm->cm_sge = &request->PageBufferSGE; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); if (!page) { printf("%s: page alloc failed\n", __func__); error = ENOMEM; goto out; } cm->cm_data = page; /* * This page must be polled because the IOC isn't ready yet when this * page is needed. */ error = mps_request_polled(sc, cm); reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: poll for page completed with error %d", __func__, error); error = ENXIO; goto out; } ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { /* FIXME */ /* If the poll returns error then we need to do diag reset */ printf("%s: page read with error; iocstatus = 0x%x\n", __func__, ioc_status); error = ENXIO; goto out; } bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2RaidPhysDiskPage0_t))); out: free(page, M_MPT2); if (cm) mps_free_command(sc, cm); return (error); }
static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo) { Mpi2SataPassthroughRequest_t *mpi_request; Mpi2SataPassthroughReply_t *reply; struct mps_command *cm; char *buffer; int error = 0; buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO); if (!buffer) return ENOMEM; if ((cm = mps_alloc_command(sc)) == NULL) { free(buffer, M_MPT2); return (EBUSY); } mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req; bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST)); mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH; mpi_request->VF_ID = 0; mpi_request->DevHandle = htole16(handle); mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO | MPI2_SATA_PT_REQ_PT_FLAGS_READ); mpi_request->DataLength = htole32(sz); mpi_request->CommandFIS[0] = 0x27; mpi_request->CommandFIS[1] = 0x80; mpi_request->CommandFIS[2] = (devinfo & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC; cm->cm_sge = &mpi_request->SGL; cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = buffer; cm->cm_length = htole32(sz); /* * Start a timeout counter specifically for the SATA ID command. This * is used to fix 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 * command so that processing can continue normally. */ mps_dprint(sc, MPS_XINFO, "%s start timeout counter for SATA ID " "command\n", __func__); callout_reset(&cm->cm_callout, MPS_ATA_ID_TIMEOUT * hz, mpssas_ata_id_timeout, cm); error = mps_wait_command(sc, cm, 60, CAN_SLEEP); mps_dprint(sc, MPS_XINFO, "%s stop timeout counter for SATA ID " "command\n", __func__); callout_stop(&cm->cm_callout); reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset */ printf("%s: request for page completed with error %d", __func__, error); error = ENXIO; goto out; } bcopy(buffer, id_buffer, sz); bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t)); if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n", __func__, reply->IOCStatus); error = ENXIO; goto out; } out: /* * If the SATA_ID_TIMEOUT flag has been set for this command, don't free * it. The command will be freed after sending a target reset TM. If * the command did timeout, use EWOULDBLOCK. */ if ((cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) == 0) mps_free_command(sc, cm); else if (error == 0) error = EWOULDBLOCK; free(buffer, M_MPT2); return (error); }
static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){ char devstring[80]; struct mpssas_softc *sassc; struct mpssas_target *targ; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t config_page; uint64_t sas_address; uint64_t parent_sas_address = 0; u32 device_info, parent_devinfo = 0; unsigned int id; int ret = 1, error = 0, i; struct mpssas_lun *lun; u8 is_SATA_SSD = 0; struct mps_command *cm; sassc = sc->sassc; mpssas_startup_increment(sassc); if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { printf("%s: error reading SAS device page0\n", __func__); error = ENXIO; goto out; } device_info = le32toh(config_page.DeviceInfo); if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) && (le16toh(config_page.ParentDevHandle) != 0)) { Mpi2ConfigReply_t tmp_mpi_reply; Mpi2SasDevicePage0_t parent_config_page; if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply, &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, le16toh(config_page.ParentDevHandle)))) { printf("%s: error reading SAS device %#x page0\n", __func__, le16toh(config_page.ParentDevHandle)); } else { parent_sas_address = parent_config_page.SASAddress.High; parent_sas_address = (parent_sas_address << 32) | parent_config_page.SASAddress.Low; parent_devinfo = le32toh(parent_config_page.DeviceInfo); } } /* TODO Check proper endianess */ sas_address = config_page.SASAddress.High; sas_address = (sas_address << 32) | config_page.SASAddress.Low; /* * Always get SATA Identify information because this is used to * determine if Start/Stop Unit should be sent to the drive when the * system is shutdown. */ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { ret = mpssas_get_sas_address_for_sata_disk(sc, &sas_address, handle, device_info, &is_SATA_SSD); if (ret) { mps_dprint(sc, MPS_INFO, "%s: failed to get disk type " "(SSD or HDD) for SATA device with handle 0x%04x\n", __func__, handle); } else { mps_dprint(sc, MPS_INFO, "SAS Address from SATA " "device = %jx\n", sas_address); } } id = mps_mapping_get_sas_id(sc, sas_address, handle); if (id == MPS_MAP_BAD_ID) { printf("failure at %s:%d/%s()! Could not get ID for device " "with handle 0x%04x\n", __FILE__, __LINE__, __func__, handle); error = ENXIO; goto out; } if (mpssas_check_id(sassc, id) != 0) { device_printf(sc->mps_dev, "Excluding target id %d\n", id); error = ENXIO; goto out; } mps_dprint(sc, MPS_MAPPING, "SAS Address from SAS device page0 = %jx\n", sas_address); targ = &sassc->targets[id]; targ->devinfo = device_info; targ->devname = le32toh(config_page.DeviceName.High); targ->devname = (targ->devname << 32) | le32toh(config_page.DeviceName.Low); targ->encl_handle = le16toh(config_page.EnclosureHandle); targ->encl_slot = le16toh(config_page.Slot); targ->handle = handle; targ->parent_handle = le16toh(config_page.ParentDevHandle); targ->sasaddr = mps_to_u64(&config_page.SASAddress); targ->parent_sasaddr = le64toh(parent_sas_address); targ->parent_devinfo = parent_devinfo; targ->tid = id; targ->linkrate = (linkrate>>4); targ->flags = 0; if (is_SATA_SSD) { targ->flags = MPS_TARGET_IS_SATA_SSD; } TAILQ_INIT(&targ->commands); TAILQ_INIT(&targ->timedout_commands); while(!SLIST_EMPTY(&targ->luns)) { lun = SLIST_FIRST(&targ->luns); SLIST_REMOVE_HEAD(&targ->luns, lun_link); free(lun, M_MPT2); } SLIST_INIT(&targ->luns); mps_describe_devinfo(targ->devinfo, devstring, 80); mps_dprint(sc, MPS_MAPPING, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring, mps_describe_table(mps_linkrate_names, targ->linkrate), targ->handle, targ->encl_handle, targ->encl_slot); #if __FreeBSD_version < 1000039 if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) #endif mpssas_rescan_target(sc, targ); mps_dprint(sc, MPS_MAPPING, "Target id 0x%x added\n", targ->tid); /* * Check all commands to see if the SATA_ID_TIMEOUT flag has been set. * If so, send a Target Reset TM to the target that was just created. * 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. */ for (i = 1; i < sc->num_reqs; i++) { cm = &sc->commands[i]; if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) { targ->timeouts++; cm->cm_state = MPS_CM_STATE_TIMEDOUT; if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) { mps_dprint(sc, MPS_INFO, "%s: sending Target " "Reset for stuck SATA identify command " "(cm = %p)\n", __func__, cm); targ->tm->cm_targ = targ; mpssas_send_reset(sc, targ->tm, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); } else { mps_dprint(sc, MPS_ERROR, "Failed to allocate " "tm for Target Reset after SATA ID command " "timed out (cm %p)\n", cm); } /* * No need to check for more since the target is * already being reset. */ break; } } 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) { mps_free_command(sc, cm); } } mpssas_startup_decrement(sassc); return (error); }
/** * mpssas_ir_shutdown - IR shutdown notification * @sc: per adapter object * * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that * the host system is shutting down. * * Return nothing. */ void mpssas_ir_shutdown(struct mps_softc *sc) { u16 volume_mapping_flags; u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); struct dev_mapping_table *mt_entry; u32 start_idx, end_idx; unsigned int id, found_volume = 0; struct mps_command *cm; Mpi2RaidActionRequest_t *action; target_id_t targetid; struct mpssas_target *target; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); /* is IR firmware build loaded? */ if (!sc->ir_firmware) goto out; /* are there any volumes? Look at IR target IDs. */ // TODO-later, this should be looked up in the RAID config structure // when it is implemented. volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { start_idx = 0; if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) start_idx = 1; } else start_idx = sc->max_devices - sc->max_volumes; end_idx = start_idx + sc->max_volumes - 1; for (id = start_idx; id < end_idx; id++) { mt_entry = &sc->mapping_table[id]; if ((mt_entry->physical_id != 0) && (mt_entry->missing_count == 0)) { found_volume = 1; break; } } if (!found_volume) goto out; if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed\n", __func__); goto out; } action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; action->Function = MPI2_FUNCTION_RAID_ACTION; action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; mps_lock(sc); mps_wait_command(sc, cm, 5, CAN_SLEEP); mps_unlock(sc); /* * Don't check for reply, just leave. */ if (cm) mps_free_command(sc, cm); out: /* * All of the targets must have the correct value set for * 'stop_at_shutdown' for the current 'enable_ssu' sysctl variable. * * The possible values for the 'enable_ssu' variable are: * 0: disable to SSD and HDD * 1: disable only to HDD (default) * 2: disable only to SSD * 3: enable to SSD and HDD * anything else will default to 1. */ for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { target = &sc->sassc->targets[targetid]; if (target->handle == 0x0) { continue; } if (target->supports_SSU) { switch (sc->enable_ssu) { case MPS_SSU_DISABLE_SSD_DISABLE_HDD: target->stop_at_shutdown = FALSE; break; case MPS_SSU_DISABLE_SSD_ENABLE_HDD: target->stop_at_shutdown = TRUE; if (target->flags & MPS_TARGET_IS_SATA_SSD) { target->stop_at_shutdown = FALSE; } break; case MPS_SSU_ENABLE_SSD_ENABLE_HDD: target->stop_at_shutdown = TRUE; break; case MPS_SSU_ENABLE_SSD_DISABLE_HDD: default: target->stop_at_shutdown = TRUE; if ((target->flags & MPS_TARGET_IS_SATA_SSD) == 0) { target->stop_at_shutdown = FALSE; } break; } } } mpssas_SSU_to_SATA_devices(sc); }
static int mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd) { MPI2_REQUEST_HEADER *hdr; MPI2_DEFAULT_REPLY *rpl; void *buf = NULL; struct mps_command *cm = NULL; int err = 0; int sz; mps_lock(sc); cm = mps_alloc_command(sc); if (cm == NULL) { mps_printf(sc, "mps_user_command: no mps requests\n"); err = ENOMEM; goto Ret; } mps_unlock(sc); hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d rpl %p %d\n", cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len ); if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { err = EINVAL; goto RetFreeUnlocked; } err = copyin(cmd->req, hdr, cmd->req_len); if (err != 0) goto RetFreeUnlocked; mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X " "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags ); err = mps_user_setup_request(cm, cmd); if (err != 0) { mps_printf(sc, "mps_user_command: unsupported function 0x%X\n", hdr->Function ); goto RetFreeUnlocked; } if (cmd->len > 0) { buf = kmalloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO); cm->cm_data = buf; cm->cm_length = cmd->len; } else { cm->cm_data = NULL; cm->cm_length = 0; } cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; mps_lock(sc); err = mps_map_command(sc, cm); if (err != 0 && err != EINPROGRESS) { mps_printf(sc, "%s: invalid request: error %d\n", __func__, err); goto Ret; } lksleep(cm, &sc->mps_lock, 0, "mpsuser", 0); rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; if (sz > cmd->rpl_len) { mps_printf(sc, "mps_user_command: reply buffer too small %d required %d\n", cmd->rpl_len, sz ); err = EINVAL; sz = cmd->rpl_len; } mps_unlock(sc); copyout(rpl, cmd->rpl, sz); if (buf != NULL) copyout(buf, cmd->buf, cmd->len); mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz ); RetFreeUnlocked: mps_lock(sc); if (cm != NULL) mps_free_command(sc, cm); Ret: mps_unlock(sc); if (buf != NULL) kfree(buf, M_MPSUSER); return (err); }