diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index a937f61bad9..1e14f6f5857 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -503,6 +503,8 @@ mpt_config_reply_handler(struct mpt_softc *mpt, request_t *req, req->IOCStatus = le16toh(reply_frame->IOCStatus); bcopy(&reply->Header, &cfgp->Header, sizeof(cfgp->Header)); + cfgp->ExtPageLength = reply->ExtPageLength; + cfgp->ExtPageType = reply->ExtPageType; } req->state &= ~REQ_STATE_QUEUED; req->state |= REQ_STATE_DONE; @@ -1548,31 +1550,37 @@ mpt_send_ioc_init(struct mpt_softc *mpt, uint32_t who) * Utiltity routine to read configuration headers and pages */ int -mpt_issue_cfg_req(struct mpt_softc *mpt, request_t *req, u_int Action, - u_int PageVersion, u_int PageLength, u_int PageNumber, - u_int PageType, uint32_t PageAddress, bus_addr_t addr, - bus_size_t len, int sleep_ok, int timeout_ms) +mpt_issue_cfg_req(struct mpt_softc *mpt, request_t *req, cfgparms_t *params, + bus_addr_t addr, bus_size_t len, int sleep_ok, int timeout_ms) { MSG_CONFIG *cfgp; SGE_SIMPLE32 *se; cfgp = req->req_vbuf; memset(cfgp, 0, sizeof *cfgp); - cfgp->Action = Action; + cfgp->Action = params->Action; cfgp->Function = MPI_FUNCTION_CONFIG; - cfgp->Header.PageVersion = PageVersion; - cfgp->Header.PageLength = PageLength; - cfgp->Header.PageNumber = PageNumber; - cfgp->Header.PageType = PageType; - cfgp->PageAddress = htole32(PageAddress); + cfgp->Header.PageVersion = params->PageVersion; + cfgp->Header.PageNumber = params->PageNumber; + cfgp->PageAddress = htole32(params->PageAddress); + if ((params->PageType & MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { + cfgp->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + cfgp->Header.PageLength = 0; + cfgp->ExtPageLength = htole16(params->ExtPageLength); + cfgp->ExtPageType = params->ExtPageType; + } else { + cfgp->Header.PageType = params->PageType; + cfgp->Header.PageLength = params->PageLength; + } se = (SGE_SIMPLE32 *)&cfgp->PageBufferSGE; se->Address = htole32(addr); MPI_pSGE_SET_LENGTH(se, len); MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_END_OF_LIST | - ((Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT - || Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) + ((params->Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT + || params->Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) ? MPI_SGE_FLAGS_HOST_TO_IOC : MPI_SGE_FLAGS_IOC_TO_HOST))); se->FlagsLength = htole32(se->FlagsLength); cfgp->MsgContext = htole32(req->index | MPT_REPLY_HANDLER_CONFIG); @@ -1583,6 +1591,113 @@ mpt_issue_cfg_req(struct mpt_softc *mpt, request_t *req, u_int Action, sleep_ok, timeout_ms)); } +int +mpt_read_extcfg_header(struct mpt_softc *mpt, int PageVersion, int PageNumber, + uint32_t PageAddress, int ExtPageType, + CONFIG_EXTENDED_PAGE_HEADER *rslt, + int sleep_ok, int timeout_ms) +{ + request_t *req; + cfgparms_t params; + MSG_CONFIG_REPLY *cfgp; + int error; + + req = mpt_get_request(mpt, sleep_ok); + if (req == NULL) { + mpt_prt(mpt, "mpt_extread_cfg_header: Get request failed!\n"); + return (ENOMEM); + } + + params.Action = MPI_CONFIG_ACTION_PAGE_HEADER; + params.PageVersion = PageVersion; + params.PageLength = 0; + params.PageNumber = PageNumber; + params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + params.PageAddress = PageAddress; + params.ExtPageType = ExtPageType; + params.ExtPageLength = 0; + error = mpt_issue_cfg_req(mpt, req, ¶ms, /*addr*/0, /*len*/0, + sleep_ok, timeout_ms); + if (error != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mpt_prt(mpt, "read_extcfg_header timed out\n"); + return (ETIMEDOUT); + } + + switch (req->IOCStatus & MPI_IOCSTATUS_MASK) { + case MPI_IOCSTATUS_SUCCESS: + cfgp = req->req_vbuf; + rslt->PageVersion = cfgp->Header.PageVersion; + rslt->PageNumber = cfgp->Header.PageNumber; + rslt->PageType = cfgp->Header.PageType; + rslt->ExtPageLength = cfgp->ExtPageLength; + rslt->ExtPageType = cfgp->ExtPageType; + error = 0; + break; + case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Invalid Page Type %d Number %d Addr 0x%0x\n", + MPI_CONFIG_PAGETYPE_EXTENDED, PageNumber, PageAddress); + error = EINVAL; + break; + default: + mpt_prt(mpt, "mpt_read_extcfg_header: Config Info Status %x\n", + req->IOCStatus); + error = EIO; + break; + } + mpt_free_request(mpt, req); + return (error); +} + +int +mpt_read_extcfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, + CONFIG_EXTENDED_PAGE_HEADER *hdr, void *buf, size_t len, + int sleep_ok, int timeout_ms) +{ + request_t *req; + cfgparms_t params; + int error; + + req = mpt_get_request(mpt, sleep_ok); + if (req == NULL) { + mpt_prt(mpt, "mpt_read_cfg_page: Get request failed!\n"); + return (-1); + } + + params.Action = Action; + params.PageVersion = hdr->PageVersion; + params.PageLength = 0; + params.PageNumber = hdr->PageNumber; + params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + params.PageAddress = PageAddress; + params.ExtPageType = hdr->ExtPageType; + params.ExtPageLength = hdr->ExtPageLength; + error = mpt_issue_cfg_req(mpt, req, ¶ms, + req->req_pbuf + MPT_RQSL(mpt), + len, sleep_ok, timeout_ms); + if (error != 0) { + mpt_prt(mpt, "read_extcfg_page(%d) timed out\n", Action); + return (-1); + } + + if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + mpt_prt(mpt, "mpt_read_extcfg_page: Config Info Status %x\n", + req->IOCStatus); + mpt_free_request(mpt, req); + return (-1); + } + bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, + BUS_DMASYNC_POSTREAD); + memcpy(buf, ((uint8_t *)req->req_vbuf)+MPT_RQSL(mpt), len); + mpt_free_request(mpt, req); + return (0); +} int mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, @@ -1590,6 +1705,7 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, int sleep_ok, int timeout_ms) { request_t *req; + cfgparms_t params; MSG_CONFIG *cfgp; int error; @@ -1599,9 +1715,13 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, return (ENOMEM); } - error = mpt_issue_cfg_req(mpt, req, MPI_CONFIG_ACTION_PAGE_HEADER, - /*PageVersion*/0, /*PageLength*/0, PageNumber, - PageType, PageAddress, /*addr*/0, /*len*/0, + params.Action = MPI_CONFIG_ACTION_PAGE_HEADER; + params.PageVersion = 0; + params.PageLength = 0; + params.PageNumber = PageNumber; + params.PageType = PageType; + params.PageAddress = PageAddress; + error = mpt_issue_cfg_req(mpt, req, ¶ms, /*addr*/0, /*len*/0, sleep_ok, timeout_ms); if (error != 0) { /* @@ -1642,6 +1762,7 @@ mpt_read_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, int timeout_ms) { request_t *req; + cfgparms_t params; int error; req = mpt_get_request(mpt, sleep_ok); @@ -1650,10 +1771,14 @@ mpt_read_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, return (-1); } - error = mpt_issue_cfg_req(mpt, req, Action, hdr->PageVersion, - hdr->PageLength, hdr->PageNumber, - hdr->PageType & MPI_CONFIG_PAGETYPE_MASK, - PageAddress, req->req_pbuf + MPT_RQSL(mpt), + params.Action = Action; + params.PageVersion = hdr->PageVersion; + params.PageLength = hdr->PageLength; + params.PageNumber = hdr->PageNumber; + params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK; + params.PageAddress = PageAddress; + error = mpt_issue_cfg_req(mpt, req, ¶ms, + req->req_pbuf + MPT_RQSL(mpt), len, sleep_ok, timeout_ms); if (error != 0) { mpt_prt(mpt, "read_cfg_page(%d) timed out\n", Action); @@ -1679,6 +1804,7 @@ mpt_write_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, int timeout_ms) { request_t *req; + cfgparms_t params; u_int hdr_attr; int error; @@ -1708,22 +1834,21 @@ mpt_write_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, * if you then mask them going down to issue the request. */ + params.Action = Action; + params.PageVersion = hdr->PageVersion; + params.PageLength = hdr->PageLength; + params.PageNumber = hdr->PageNumber; + params.PageAddress = PageAddress; #if 0 /* Restore stripped out attributes */ hdr->PageType |= hdr_attr; - - error = mpt_issue_cfg_req(mpt, req, Action, hdr->PageVersion, - hdr->PageLength, hdr->PageNumber, - hdr->PageType & MPI_CONFIG_PAGETYPE_MASK, - PageAddress, req->req_pbuf + MPT_RQSL(mpt), - len, sleep_ok, timeout_ms); + params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK; #else - error = mpt_issue_cfg_req(mpt, req, Action, hdr->PageVersion, - hdr->PageLength, hdr->PageNumber, - hdr->PageType, PageAddress, + params.PageType = hdr->PageType; +#endif + error = mpt_issue_cfg_req(mpt, req, ¶ms, req->req_pbuf + MPT_RQSL(mpt), len, sleep_ok, timeout_ms); -#endif if (error != 0) { mpt_prt(mpt, "mpt_write_cfg_page timed out\n"); return (-1); diff --git a/sys/dev/mpt/mpt.h b/sys/dev/mpt/mpt.h index 3e18496e9ad..52dbf1cd699 100644 --- a/sys/dev/mpt/mpt.h +++ b/sys/dev/mpt/mpt.h @@ -341,6 +341,17 @@ struct req_entry { struct callout callout; /* Timeout for the request */ }; +typedef struct mpt_config_params { + u_int Action; + u_int PageVersion; + u_int PageLength; + u_int PageNumber; + u_int PageType; + u_int PageAddress; + u_int ExtPageLength; + u_int ExtPageType; +} cfgparms_t; + /**************************** MPI Target State Info ***************************/ typedef struct { @@ -514,6 +525,36 @@ struct mpt_evtf_record { LIST_HEAD(mpt_evtf_list, mpt_evtf_record); +struct mptsas_devinfo { + uint16_t dev_handle; + uint16_t parent_dev_handle; + uint16_t enclosure_handle; + uint16_t slot; + uint8_t phy_num; + uint8_t physical_port; + uint8_t target_id; + uint8_t bus; + uint64_t sas_address; + uint32_t device_info; +}; + +struct mptsas_phyinfo { + uint16_t handle; + uint8_t phy_num; + uint8_t port_id; + uint8_t negotiated_link_rate; + uint8_t hw_link_rate; + uint8_t programmed_link_rate; + uint8_t sas_port_add_phy; + struct mptsas_devinfo identify; + struct mptsas_devinfo attached; +}; + +struct mptsas_portinfo { + uint16_t num_phys; + struct mptsas_phyinfo *phy_info; +}; + struct mpt_softc { device_t dev; #if __FreeBSD_version < 500000 @@ -721,6 +762,9 @@ struct mpt_softc { bus_dmamap_t fw_dmap; /* DMA map for firmware image */ bus_addr_t fw_phys; /* BusAddr of firmware image */ + /* SAS Topology */ + struct mptsas_portinfo *sas_portinfo; + /* Shutdown Event Handler. */ eventhandler_tag eh; @@ -1186,11 +1230,19 @@ void mpt_dump_reply_frame(struct mpt_softc *mpt, void mpt_set_config_regs(struct mpt_softc *); int mpt_issue_cfg_req(struct mpt_softc */*mpt*/, request_t */*req*/, - u_int /*Action*/, u_int /*PageVersion*/, - u_int /*PageLength*/, u_int /*PageNumber*/, - u_int /*PageType*/, uint32_t /*PageAddress*/, + cfgparms_t *params, bus_addr_t /*addr*/, bus_size_t/*len*/, int /*sleep_ok*/, int /*timeout_ms*/); +int mpt_read_extcfg_header(struct mpt_softc *mpt, int PageVersion, + int PageNumber, uint32_t PageAddress, + int ExtPageType, + CONFIG_EXTENDED_PAGE_HEADER *rslt, + int sleep_ok, int timeout_ms); +int mpt_read_extcfg_page(struct mpt_softc *mpt, int Action, + uint32_t PageAddress, + CONFIG_EXTENDED_PAGE_HEADER *hdr, + void *buf, size_t len, int sleep_ok, + int timeout_ms); int mpt_read_cfg_header(struct mpt_softc *, int /*PageType*/, int /*PageNumber*/, uint32_t /*PageAddress*/, diff --git a/sys/dev/mpt/mpt_cam.c b/sys/dev/mpt/mpt_cam.c index 59f1eb44b96..4c7ddf3baca 100644 --- a/sys/dev/mpt/mpt_cam.c +++ b/sys/dev/mpt/mpt_cam.c @@ -104,6 +104,7 @@ __FBSDID("$FreeBSD$"); #include "dev/mpt/mpilib/mpi_init.h" #include "dev/mpt/mpilib/mpi_targ.h" #include "dev/mpt/mpilib/mpi_fc.h" +#include "dev/mpt/mpilib/mpi_sas.h" #if __FreeBSD_version >= 500000 #include #endif @@ -159,10 +160,12 @@ mpt_scsi_tgt_tsk_mgmt(struct mpt_softc *, request_t *, mpt_task_mgmt_t, static void mpt_tgt_dump_tgt_state(struct mpt_softc *, request_t *); static void mpt_tgt_dump_req_state(struct mpt_softc *, request_t *); static mpt_reply_handler_t mpt_scsi_tgt_reply_handler; +static mpt_reply_handler_t mpt_sata_pass_reply_handler; static uint32_t scsi_io_handler_id = MPT_HANDLER_ID_NONE; static uint32_t scsi_tmf_handler_id = MPT_HANDLER_ID_NONE; static uint32_t fc_els_handler_id = MPT_HANDLER_ID_NONE; +static uint32_t sata_pass_handler_id = MPT_HANDLER_ID_NONE; static mpt_probe_handler_t mpt_cam_probe; static mpt_attach_handler_t mpt_cam_attach; @@ -187,6 +190,9 @@ static struct mpt_personality mpt_cam_personality = DECLARE_MPT_PERSONALITY(mpt_cam, SI_ORDER_SECOND); MODULE_DEPEND(mpt_cam, cam, 1, 1, 1); +int mpt_enable_sata_wc = -1; +TUNABLE_INT("hw.mpt.enable_sata_wc", &mpt_enable_sata_wc); + int mpt_cam_probe(struct mpt_softc *mpt) { @@ -273,6 +279,16 @@ mpt_cam_attach(struct mpt_softc *mpt) } } + if (mpt->is_sas) { + handler.reply_handler = mpt_sata_pass_reply_handler; + error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, + &sata_pass_handler_id); + if (error != 0) { + MPT_UNLOCK(mpt); + goto cleanup; + } + } + /* * We keep one request reserved for timeout TMF requests. */ @@ -584,24 +600,310 @@ mpt_set_initial_config_fc(struct mpt_softc *mpt) return (0); } +static int +mptsas_sas_io_unit_pg0(struct mpt_softc *mpt, struct mptsas_portinfo *portinfo) +{ + ConfigExtendedPageHeader_t hdr; + struct mptsas_phyinfo *phyinfo; + SasIOUnitPage0_t *buffer; + int error, len, i; + + error = mpt_read_extcfg_header(mpt, MPI_SASIOUNITPAGE0_PAGEVERSION, + 0, 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, + &hdr, 0, 10000); + if (error) + goto out; + if (hdr.ExtPageLength == 0) { + error = ENXIO; + goto out; + } + + len = hdr.ExtPageLength * 4; + buffer = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); + if (buffer == NULL) { + error = ENOMEM; + goto out; + } + + error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, + 0, &hdr, buffer, len, 0, 10000); + if (error) { + free(buffer, M_DEVBUF); + goto out; + } + + portinfo->num_phys = buffer->NumPhys; + portinfo->phy_info = malloc(sizeof(*portinfo->phy_info) * + portinfo->num_phys, M_DEVBUF, M_NOWAIT|M_ZERO); + if (portinfo->phy_info == NULL) { + free(buffer, M_DEVBUF); + error = ENOMEM; + goto out; + } + + for (i = 0; i < portinfo->num_phys; i++) { + phyinfo = &portinfo->phy_info[i]; + phyinfo->phy_num = i; + phyinfo->port_id = buffer->PhyData[i].Port; + phyinfo->negotiated_link_rate = + buffer->PhyData[i].NegotiatedLinkRate; + phyinfo->handle = + le16toh(buffer->PhyData[i].ControllerDevHandle); + } + + free(buffer, M_DEVBUF); +out: + return (error); +} + +static int +mptsas_sas_phy_pg0(struct mpt_softc *mpt, struct mptsas_phyinfo *phy_info, + uint32_t form, uint32_t form_specific) +{ + ConfigExtendedPageHeader_t hdr; + SasPhyPage0_t *buffer; + int error; + + error = mpt_read_extcfg_header(mpt, MPI_SASPHY0_PAGEVERSION, 0, 0, + MPI_CONFIG_EXTPAGETYPE_SAS_PHY, &hdr, + 0, 10000); + if (error) + goto out; + if (hdr.ExtPageLength == 0) { + error = ENXIO; + goto out; + } + + buffer = malloc(sizeof(SasPhyPage0_t), M_DEVBUF, M_NOWAIT|M_ZERO); + if (buffer == NULL) { + error = ENOMEM; + goto out; + } + + error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, + form + form_specific, &hdr, buffer, + sizeof(SasPhyPage0_t), 0, 10000); + if (error) { + free(buffer, M_DEVBUF); + goto out; + } + + phy_info->hw_link_rate = buffer->HwLinkRate; + phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; + phy_info->identify.dev_handle = le16toh(buffer->OwnerDevHandle); + phy_info->attached.dev_handle = le16toh(buffer->AttachedDevHandle); + + free(buffer, M_DEVBUF); +out: + return (error); +} + +static int +mptsas_sas_device_pg0(struct mpt_softc *mpt, struct mptsas_devinfo *device_info, + uint32_t form, uint32_t form_specific) +{ + ConfigExtendedPageHeader_t hdr; + SasDevicePage0_t *buffer; + uint64_t sas_address; + int error = 0; + + bzero(device_info, sizeof(*device_info)); + error = mpt_read_extcfg_header(mpt, MPI_SASDEVICE0_PAGEVERSION, 0, 0, + MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, + &hdr, 0, 10000); + if (error) + goto out; + if (hdr.ExtPageLength == 0) { + error = ENXIO; + goto out; + } + + buffer = malloc(sizeof(SasDevicePage0_t), M_DEVBUF, M_NOWAIT|M_ZERO); + if (buffer == NULL) { + error = ENOMEM; + goto out; + } + + error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, + form + form_specific, &hdr, buffer, + sizeof(SasDevicePage0_t), 0, 10000); + if (error) { + free(buffer, M_DEVBUF); + goto out; + } + + device_info->dev_handle = le16toh(buffer->DevHandle); + device_info->parent_dev_handle = le16toh(buffer->ParentDevHandle); + device_info->enclosure_handle = le16toh(buffer->EnclosureHandle); + device_info->slot = le16toh(buffer->Slot); + device_info->phy_num = buffer->PhyNum; + device_info->physical_port = buffer->PhysicalPort; + device_info->target_id = buffer->TargetID; + device_info->bus = buffer->Bus; + bcopy(&buffer->SASAddress, &sas_address, sizeof(uint64_t)); + device_info->sas_address = le64toh(sas_address); + device_info->device_info = le32toh(buffer->DeviceInfo); + + free(buffer, M_DEVBUF); +out: + return (error); +} + /* * Read SAS configuration information. Nothing to do yet. */ static int mpt_read_config_info_sas(struct mpt_softc *mpt) { + struct mptsas_portinfo *portinfo; + struct mptsas_phyinfo *phyinfo; + int error, i; + + portinfo = malloc(sizeof(*portinfo), M_DEVBUF, M_NOWAIT|M_ZERO); + if (portinfo == NULL) + return (ENOMEM); + + error = mptsas_sas_io_unit_pg0(mpt, portinfo); + if (error) { + free(portinfo, M_DEVBUF); + return (0); + } + + for (i = 0; i < portinfo->num_phys; i++) { + phyinfo = &portinfo->phy_info[i]; + error = mptsas_sas_phy_pg0(mpt, phyinfo, + (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << + MPI_SAS_PHY_PGAD_FORM_SHIFT), i); + if (error) + break; + error = mptsas_sas_device_pg0(mpt, &phyinfo->identify, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + phyinfo->handle); + if (error) + break; + phyinfo->identify.phy_num = phyinfo->phy_num = i; + if (phyinfo->attached.dev_handle) + error = mptsas_sas_device_pg0(mpt, + &phyinfo->attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + phyinfo->attached.dev_handle); + if (error) + break; + } + mpt->sas_portinfo = portinfo; + free(portinfo, M_DEVBUF); return (0); } +static void +mptsas_set_sata_wc(struct mpt_softc *mpt, struct mptsas_devinfo *devinfo, + int enabled) +{ + SataPassthroughRequest_t *pass; + request_t *req; + int error, status; + + req = mpt_get_request(mpt, 0); + if (req == NULL) + return; + + pass = req->req_vbuf; + bzero(pass, sizeof(SataPassthroughRequest_t)); + pass->Function = MPI_FUNCTION_SATA_PASSTHROUGH; + pass->TargetID = devinfo->target_id; + pass->Bus = devinfo->bus; + pass->PassthroughFlags = 0; + pass->ConnectionRate = MPI_SATA_PT_REQ_CONNECT_RATE_NEGOTIATED; + pass->DataLength = 0; + pass->MsgContext = htole32(req->index | sata_pass_handler_id); + pass->CommandFIS[0] = 0x27; + pass->CommandFIS[1] = 0x80; + pass->CommandFIS[2] = 0xef; + pass->CommandFIS[3] = (enabled) ? 0x02 : 0x82; + pass->CommandFIS[7] = 0x40; + pass->CommandFIS[15] = 0x08; + + mpt_check_doorbell(mpt); + mpt_send_cmd(mpt, req); + error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, 0, + 10 * 1000); + if (error) { + mpt_free_request(mpt, req); + printf("error %d sending passthrough\n", error); + return; + } + + status = le16toh(req->IOCStatus); + if (status != MPI_IOCSTATUS_SUCCESS) { + mpt_free_request(mpt, req); + printf("IOCSTATUS %d\n", status); + return; + } + + mpt_free_request(mpt, req); +} + /* * Set SAS configuration information. Nothing to do yet. */ static int mpt_set_initial_config_sas(struct mpt_softc *mpt) { + struct mptsas_phyinfo *phyinfo; + int i; + + if ((mpt_enable_sata_wc != -1) && (mpt->sas_portinfo != NULL)) { + for (i = 0; i < mpt->sas_portinfo->num_phys; i++) { + phyinfo = &mpt->sas_portinfo->phy_info[i]; + if (phyinfo->attached.dev_handle == 0) + continue; + if ((phyinfo->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) + continue; + if (bootverbose) + device_printf(mpt->dev, + "%sabling SATA WC on phy %d\n", + (mpt_enable_sata_wc) ? "En" : "Dis", i); + mptsas_set_sata_wc(mpt, &phyinfo->attached, + mpt_enable_sata_wc); + } + } + return (0); } +static int +mpt_sata_pass_reply_handler(struct mpt_softc *mpt, request_t *req, + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) +{ + if (req != NULL) { + + if (reply_frame != NULL) { + MSG_SATA_PASSTHROUGH_REQUEST *pass; + MSG_SATA_PASSTHROUGH_REPLY *reply; + + pass = (MSG_SATA_PASSTHROUGH_REQUEST *)req->req_vbuf; + reply = (MSG_SATA_PASSTHROUGH_REPLY *)reply_frame; + req->IOCStatus = le16toh(reply_frame->IOCStatus); + } + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { + wakeup(req); + } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) { + /* + * Whew- we can free this request (late completion) + */ + mpt_free_request(mpt, req); + } + } + + return (TRUE); +} + /* * Read SCSI configuration information */ @@ -888,6 +1190,9 @@ mpt_cam_detach(struct mpt_softc *mpt) handler.reply_handler = mpt_scsi_tgt_reply_handler; mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, mpt->scsi_tgt_handler_id); + handler.reply_handler = mpt_sata_pass_reply_handler; + mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, + sata_pass_handler_id); if (mpt->tmf_req != NULL) { mpt->tmf_req->state = REQ_STATE_ALLOCATED;