summaryrefslogtreecommitdiff
path: root/drivers/message/fusion/mptsas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r--drivers/message/fusion/mptsas.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index dcdf038..1c557a0 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -83,6 +83,7 @@ MODULE_PARM_DESC(mpt_pt_clear,
static int mptsasDoneCtx = -1;
static int mptsasTaskCtx = -1;
static int mptsasInternalCtx = -1; /* Used only for internal commands */
+static int mptsasMgmtCtx = -1;
/*
@@ -359,9 +360,92 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
return error;
}
+static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+ MPT_FRAME_HDR *reply)
+{
+ ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
+ if (reply != NULL) {
+ ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
+ memcpy(ioc->sas_mgmt.reply, reply,
+ min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
+ }
+ complete(&ioc->sas_mgmt.done);
+ return 1;
+}
+
+static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ MPT_ADAPTER *ioc = phy_to_ioc(phy);
+ SasIoUnitControlRequest_t *req;
+ SasIoUnitControlReply_t *reply;
+ MPT_FRAME_HDR *mf;
+ MPIHeader_t *hdr;
+ unsigned long timeleft;
+ int error = -ERESTARTSYS;
+
+ /* not implemented for expanders */
+ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
+ return -ENXIO;
+
+ if (down_interruptible(&ioc->sas_mgmt.mutex))
+ goto out;
+
+ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+ if (!mf) {
+ error = -ENOMEM;
+ goto out_unlock;
+ }
+
+ hdr = (MPIHeader_t *) mf;
+ req = (SasIoUnitControlRequest_t *)mf;
+ memset(req, 0, sizeof(SasIoUnitControlRequest_t));
+ req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+ req->MsgContext = hdr->MsgContext;
+ req->Operation = hard_reset ?
+ MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
+ req->PhyNum = phy->identify.phy_identifier;
+
+ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
+ 10 * HZ);
+ if (!timeleft) {
+ /* On timeout reset the board */
+ mpt_free_msg_frame(ioc, mf);
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ error = -ETIMEDOUT;
+ goto out_unlock;
+ }
+
+ /* a reply frame is expected */
+ if ((ioc->sas_mgmt.status &
+ MPT_IOCTL_STATUS_RF_VALID) == 0) {
+ error = -ENXIO;
+ goto out_unlock;
+ }
+
+ /* process the completed Reply Message Frame */
+ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
+ if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
+ printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ __FUNCTION__,
+ reply->IOCStatus,
+ reply->IOCLogInfo);
+ error = -ENXIO;
+ goto out_unlock;
+ }
+
+ error = 0;
+
+ out_unlock:
+ up(&ioc->sas_mgmt.mutex);
+ out:
+ return error;
+}
static struct sas_function_template mptsas_transport_functions = {
.get_linkerrors = mptsas_get_linkerrors,
+ .phy_reset = mptsas_phy_reset,
};
static struct scsi_transport_template *mptsas_transport_template;
@@ -1105,6 +1189,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->unique_id = ioc->id;
INIT_LIST_HEAD(&ioc->sas_topology);
+ init_MUTEX(&ioc->sas_mgmt.mutex);
+ init_completion(&ioc->sas_mgmt.done);
/* Verify that we won't exceed the maximum
* number of chain buffers
@@ -1291,6 +1377,7 @@ mptsas_init(void)
mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
mptsasInternalCtx =
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
+ mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
devtprintk((KERN_INFO MYNAM
@@ -1314,6 +1401,7 @@ mptsas_exit(void)
mpt_reset_deregister(mptsasDoneCtx);
mpt_event_deregister(mptsasDoneCtx);
+ mpt_deregister(mptsasMgmtCtx);
mpt_deregister(mptsasInternalCtx);
mpt_deregister(mptsasTaskCtx);
mpt_deregister(mptsasDoneCtx);