aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mpt
diff options
context:
space:
mode:
authorScott Long <scottl@FreeBSD.org>2007-06-03 23:13:05 +0000
committerScott Long <scottl@FreeBSD.org>2007-06-03 23:13:05 +0000
commit1d558d6a154f57cc9c84314a5bbddf39f706b830 (patch)
tree9ae0a0f56436749bee81e119dde56bd9acafe6ff /sys/dev/mpt
parent62ae194db25fe9743d03cb8a6c86634af4f95dd9 (diff)
Notes
Diffstat (limited to 'sys/dev/mpt')
-rw-r--r--sys/dev/mpt/mpt.c183
-rw-r--r--sys/dev/mpt/mpt.h58
-rw-r--r--sys/dev/mpt/mpt_cam.c305
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, &params, /*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, &params,
+ 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, &params, /*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, &params,
+ 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, &params,
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 <sys/sysctl.h>
#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;