From 1d558d6a154f57cc9c84314a5bbddf39f706b830 Mon Sep 17 00:00:00 2001 From: Scott Long Date: Sun, 3 Jun 2007 23:13:05 +0000 Subject: [PATCH] mpt.c: mpt.h: Add support for reading extended configuration pages. mpt_cam.c: Do a top level topology scan on the SAS controller. If any SATA device are discovered in this scan, send a passthrough FIS to set the write cache. This is controllable through the following tunable at boot: hw.mpt.enable_sata_wc: -1 = Do not configure, use the controller default 0 = Disable the write cache 1 = Enable the write cache The default is -1. This tunable is just a hack and may be deprecated in the future. Turning on the write cache alleviates the write performance problems with SATA that many people have observed. It is not recommend for those who value data reliability! I cannot stress this strongly enough. However, it is useful in certain circumstances, and it brings the performence in line with what a generic SATA controller running under the FreeBSD ATA driver provides (and the ATA driver has had the WC enabled by default for years). --- sys/dev/mpt/mpt.c | 183 +++++++++++++++++++++---- sys/dev/mpt/mpt.h | 58 +++++++- sys/dev/mpt/mpt_cam.c | 305 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 514 insertions(+), 32 deletions(-) diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index a937f61bad9b..1e14f6f5857d 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 3e18496e9adf..52dbf1cd6996 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 59f1eb44b96a..4c7ddf3bacaa 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;