|
@@ -83,6 +83,7 @@ MODULE_PARM_DESC(mpt_pt_clear,
|
|
static int mptsasDoneCtx = -1;
|
|
static int mptsasDoneCtx = -1;
|
|
static int mptsasTaskCtx = -1;
|
|
static int mptsasTaskCtx = -1;
|
|
static int mptsasInternalCtx = -1; /* Used only for internal commands */
|
|
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;
|
|
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 = {
|
|
static struct sas_function_template mptsas_transport_functions = {
|
|
.get_linkerrors = mptsas_get_linkerrors,
|
|
.get_linkerrors = mptsas_get_linkerrors,
|
|
|
|
+ .phy_reset = mptsas_phy_reset,
|
|
};
|
|
};
|
|
|
|
|
|
static struct scsi_transport_template *mptsas_transport_template;
|
|
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;
|
|
sh->unique_id = ioc->id;
|
|
|
|
|
|
INIT_LIST_HEAD(&ioc->sas_topology);
|
|
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
|
|
/* Verify that we won't exceed the maximum
|
|
* number of chain buffers
|
|
* number of chain buffers
|
|
@@ -1291,6 +1377,7 @@ mptsas_init(void)
|
|
mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
|
|
mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
|
|
mptsasInternalCtx =
|
|
mptsasInternalCtx =
|
|
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
|
|
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
|
|
|
|
+ mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
|
|
|
|
|
|
if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
|
|
if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
|
|
devtprintk((KERN_INFO MYNAM
|
|
devtprintk((KERN_INFO MYNAM
|
|
@@ -1314,6 +1401,7 @@ mptsas_exit(void)
|
|
mpt_reset_deregister(mptsasDoneCtx);
|
|
mpt_reset_deregister(mptsasDoneCtx);
|
|
mpt_event_deregister(mptsasDoneCtx);
|
|
mpt_event_deregister(mptsasDoneCtx);
|
|
|
|
|
|
|
|
+ mpt_deregister(mptsasMgmtCtx);
|
|
mpt_deregister(mptsasInternalCtx);
|
|
mpt_deregister(mptsasInternalCtx);
|
|
mpt_deregister(mptsasTaskCtx);
|
|
mpt_deregister(mptsasTaskCtx);
|
|
mpt_deregister(mptsasDoneCtx);
|
|
mpt_deregister(mptsasDoneCtx);
|