|
@@ -2686,6 +2686,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+struct rep_manu_request{
|
|
|
+ u8 smp_frame_type;
|
|
|
+ u8 function;
|
|
|
+ u8 reserved;
|
|
|
+ u8 request_length;
|
|
|
+};
|
|
|
+
|
|
|
+struct rep_manu_reply{
|
|
|
+ u8 smp_frame_type; /* 0x41 */
|
|
|
+ u8 function; /* 0x01 */
|
|
|
+ u8 function_result;
|
|
|
+ u8 response_length;
|
|
|
+ u16 expander_change_count;
|
|
|
+ u8 reserved0[2];
|
|
|
+ u8 sas_format:1;
|
|
|
+ u8 reserved1:7;
|
|
|
+ u8 reserved2[3];
|
|
|
+ u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
|
|
|
+ u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
|
|
|
+ u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
|
|
|
+ u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
|
|
|
+ u16 component_id;
|
|
|
+ u8 component_revision_id;
|
|
|
+ u8 reserved3;
|
|
|
+ u8 vendor_specific[8];
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * mptsas_exp_repmanufacture_info -
|
|
|
+ * @ioc: per adapter object
|
|
|
+ * @sas_address: expander sas address
|
|
|
+ * @edev: the sas_expander_device object
|
|
|
+ *
|
|
|
+ * Fills in the sas_expander_device object when SMP port is created.
|
|
|
+ *
|
|
|
+ * Returns 0 for success, non-zero for failure.
|
|
|
+ */
|
|
|
+static int
|
|
|
+mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
|
|
|
+ u64 sas_address, struct sas_expander_device *edev)
|
|
|
+{
|
|
|
+ MPT_FRAME_HDR *mf;
|
|
|
+ SmpPassthroughRequest_t *smpreq;
|
|
|
+ SmpPassthroughReply_t *smprep;
|
|
|
+ struct rep_manu_reply *manufacture_reply;
|
|
|
+ struct rep_manu_request *manufacture_request;
|
|
|
+ int ret;
|
|
|
+ int flagsLength;
|
|
|
+ unsigned long timeleft;
|
|
|
+ char *psge;
|
|
|
+ unsigned long flags;
|
|
|
+ void *data_out = NULL;
|
|
|
+ dma_addr_t data_out_dma = 0;
|
|
|
+ u32 sz;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
|
|
+ if (ioc->ioc_reset_in_progress) {
|
|
|
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
|
|
+ printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
|
|
|
+ __func__, ioc->name);
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
|
|
+
|
|
|
+ ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
|
|
|
+ if (!mf) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ smpreq = (SmpPassthroughRequest_t *)mf;
|
|
|
+ memset(smpreq, 0, sizeof(*smpreq));
|
|
|
+
|
|
|
+ sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
|
|
|
+
|
|
|
+ data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
|
|
|
+ if (!data_out) {
|
|
|
+ printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
|
|
|
+ __FILE__, __LINE__, __func__);
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto put_mf;
|
|
|
+ }
|
|
|
+
|
|
|
+ manufacture_request = data_out;
|
|
|
+ manufacture_request->smp_frame_type = 0x40;
|
|
|
+ manufacture_request->function = 1;
|
|
|
+ manufacture_request->reserved = 0;
|
|
|
+ manufacture_request->request_length = 0;
|
|
|
+
|
|
|
+ smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
|
|
|
+ smpreq->PhysicalPort = 0xFF;
|
|
|
+ *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
|
|
|
+ smpreq->RequestDataLength = sizeof(struct rep_manu_request);
|
|
|
+
|
|
|
+ psge = (char *)
|
|
|
+ (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
|
|
|
+
|
|
|
+ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
|
|
|
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
|
|
|
+ MPI_SGE_FLAGS_HOST_TO_IOC |
|
|
|
+ MPI_SGE_FLAGS_END_OF_BUFFER;
|
|
|
+ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
|
|
|
+ flagsLength |= sizeof(struct rep_manu_request);
|
|
|
+
|
|
|
+ ioc->add_sge(psge, flagsLength, data_out_dma);
|
|
|
+ psge += ioc->SGE_size;
|
|
|
+
|
|
|
+ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
|
|
|
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
|
|
|
+ MPI_SGE_FLAGS_IOC_TO_HOST |
|
|
|
+ MPI_SGE_FLAGS_END_OF_BUFFER;
|
|
|
+ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
|
|
|
+ flagsLength |= sizeof(struct rep_manu_reply);
|
|
|
+ ioc->add_sge(psge, flagsLength, data_out_dma +
|
|
|
+ sizeof(struct rep_manu_request));
|
|
|
+
|
|
|
+ INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
|
|
|
+ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
|
|
|
+
|
|
|
+ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
|
|
|
+ if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
|
|
+ ret = -ETIME;
|
|
|
+ mpt_free_msg_frame(ioc, mf);
|
|
|
+ mf = NULL;
|
|
|
+ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
|
|
|
+ goto out_free;
|
|
|
+ if (!timeleft)
|
|
|
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ mf = NULL;
|
|
|
+
|
|
|
+ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
|
|
|
+ u8 *tmp;
|
|
|
+
|
|
|
+ smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
|
|
|
+ if (le16_to_cpu(smprep->ResponseDataLength) !=
|
|
|
+ sizeof(struct rep_manu_reply))
|
|
|
+ goto out_free;
|
|
|
+
|
|
|
+ manufacture_reply = data_out + sizeof(struct rep_manu_request);
|
|
|
+ strncpy(edev->vendor_id, manufacture_reply->vendor_id,
|
|
|
+ SAS_EXPANDER_VENDOR_ID_LEN);
|
|
|
+ strncpy(edev->product_id, manufacture_reply->product_id,
|
|
|
+ SAS_EXPANDER_PRODUCT_ID_LEN);
|
|
|
+ strncpy(edev->product_rev, manufacture_reply->product_rev,
|
|
|
+ SAS_EXPANDER_PRODUCT_REV_LEN);
|
|
|
+ edev->level = manufacture_reply->sas_format;
|
|
|
+ if (manufacture_reply->sas_format) {
|
|
|
+ strncpy(edev->component_vendor_id,
|
|
|
+ manufacture_reply->component_vendor_id,
|
|
|
+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
|
|
|
+ tmp = (u8 *)&manufacture_reply->component_id;
|
|
|
+ edev->component_id = tmp[0] << 8 | tmp[1];
|
|
|
+ edev->component_revision_id =
|
|
|
+ manufacture_reply->component_revision_id;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ printk(MYIOC_s_ERR_FMT
|
|
|
+ "%s: smp passthru reply failed to be returned\n",
|
|
|
+ ioc->name, __func__);
|
|
|
+ ret = -ENXIO;
|
|
|
+ }
|
|
|
+out_free:
|
|
|
+ if (data_out_dma)
|
|
|
+ pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
|
|
|
+put_mf:
|
|
|
+ if (mf)
|
|
|
+ mpt_free_msg_frame(ioc, mf);
|
|
|
+out_unlock:
|
|
|
+ CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
|
|
|
+ mutex_unlock(&ioc->sas_mgmt.mutex);
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
static void
|
|
|
mptsas_parse_device_info(struct sas_identify *identify,
|
|
|
struct mptsas_devinfo *device_info)
|
|
@@ -2967,6 +3148,11 @@ static int mptsas_probe_one_phy(struct device *dev,
|
|
|
goto out;
|
|
|
}
|
|
|
mptsas_set_rphy(ioc, phy_info, rphy);
|
|
|
+ if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
|
|
|
+ identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
|
|
|
+ mptsas_exp_repmanufacture_info(ioc,
|
|
|
+ identify.sas_address,
|
|
|
+ rphy_to_expander_device(rphy));
|
|
|
}
|
|
|
|
|
|
out:
|