include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / scsi / mpt2sas / mpt2sas_transport.c
index e4d8586..bd7ca2b 100644 (file)
@@ -2,7 +2,7 @@
  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2008  LSI Corporation
+ * Copyright (C) 2007-2009  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -49,6 +49,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
 #include "mpt2sas_base.h"
 /**
- * _transport_sas_node_find_by_handle - sas node search
+ * _transport_sas_node_find_by_sas_address - sas node search
  * @ioc: per adapter object
- * @handle: expander or hba handle (assigned by firmware)
+ * @sas_address: sas address of expander or sas host
  * Context: Calling function should acquire ioc->sas_node_lock.
  *
  * Search for either hba phys or expander device based on handle, then returns
  * the sas_node object.
  */
 static struct _sas_node *
-_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+    u64 sas_address)
 {
-       int i;
-
-       for (i = 0; i < ioc->sas_hba.num_phys; i++)
-               if (ioc->sas_hba.phy[i].handle == handle)
-                       return &ioc->sas_hba;
-
-       return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+       if (ioc->sas_hba.sas_address == sas_address)
+               return &ioc->sas_hba;
+       else
+               return mpt2sas_scsih_expander_find_by_sas_address(ioc,
+                   sas_address);
 }
 
 /**
@@ -140,11 +140,18 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
        u32 device_info;
        u32 ioc_status;
 
+       if (ioc->shost_recovery) {
+               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+                   __func__, ioc->name);
+               return -EFAULT;
+       }
+
        if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
            MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+
                    ioc->name, __FILE__, __LINE__, __func__);
-               return -1;
+               return -ENXIO;
        }
 
        ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
@@ -153,7 +160,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
                printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
                    "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
                     __FILE__, __LINE__, __func__);
-               return -1;
+               return -EIO;
        }
 
        memset(identify, 0, sizeof(identify));
@@ -205,25 +212,26 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
  * mpt2sas_transport_done -  internal transport layer callback handler.
  * @ioc: per adapter object
  * @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
  * @reply: reply message frame(lower 32bit addr)
  *
  * Callback handler when sending internal generated transport cmds.
  * The callback index passed is `ioc->transport_cb_idx`
  *
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
  */
-void
-mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+u8
+mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
     u32 reply)
 {
        MPI2DefaultReply_t *mpi_reply;
 
        mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
        if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
-               return;
+               return 1;
        if (ioc->transport_cmds.smid != smid)
-               return;
+               return 1;
        ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
        if (mpi_reply) {
                memcpy(ioc->transport_cmds.reply, mpi_reply,
@@ -232,6 +240,7 @@ mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
        }
        ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
        complete(&ioc->transport_cmds.done);
+       return 1;
 }
 
 /* report manufacture request structure */
@@ -250,8 +259,7 @@ struct rep_manu_reply{
        u8 response_length;
        u16 expander_change_count;
        u8 reserved0[2];
-       u8 sas_format:1;
-       u8 reserved1:7;
+       u8 sas_format;
        u8 reserved2[3];
        u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
        u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
@@ -288,21 +296,17 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
        void *psge;
        u32 sgl_flags;
        u8 issue_reset = 0;
-       unsigned long flags;
        void *data_out = NULL;
        dma_addr_t data_out_dma;
        u32 sz;
        u64 *sas_address_le;
        u16 wait_state_count;
 
-       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
-       if (ioc->ioc_reset_in_progress) {
-               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->shost_recovery) {
                printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
                    __func__, ioc->name);
                return -EFAULT;
        }
-       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
        mutex_lock(&ioc->transport_cmds.mutex);
 
@@ -366,9 +370,12 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
        memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
        mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
        mpi_request->PhysicalPort = 0xFF;
+       mpi_request->VF_ID = 0; /* TODO */
+       mpi_request->VP_ID = 0;
        sas_address_le = (u64 *)&mpi_request->SASAddress;
        *sas_address_le = cpu_to_le64(sas_address);
-       mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
+       mpi_request->RequestDataLength =
+           cpu_to_le16(sizeof(struct rep_manu_request));
        psge = &mpi_request->SGL;
 
        /* WRITE sgel first */
@@ -393,7 +400,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
        dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
            "send to sas_addr(0x%016llx)\n", ioc->name,
            (unsigned long long)sas_address));
-       mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+       mpt2sas_base_put_smid_default(ioc, smid);
+       init_completion(&ioc->transport_cmds.done);
        timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
            10*HZ);
 
@@ -430,8 +438,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
                     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) {
+               edev->level = manufacture_reply->sas_format & 1;
+               if (edev->level) {
                        strncpy(edev->component_vendor_id,
                            manufacture_reply->component_vendor_id,
                             SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
@@ -461,7 +469,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
  * mpt2sas_transport_port_add - insert port to the list
  * @ioc: per adapter object
  * @handle: handle of attached device
- * @parent_handle: parent handle(either hba or expander)
+ * @sas_address: sas address of parent expander or sas host
  * Context: This function will acquire ioc->sas_node_lock.
  *
  * Adding new port object to the sas_node->sas_port_list.
@@ -470,7 +478,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
  */
 struct _sas_port *
 mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
-    u16 parent_handle)
+    u64 sas_address)
 {
        struct _sas_phy *mpt2sas_phy, *next;
        struct _sas_port *mpt2sas_port;
@@ -480,9 +488,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
        int i;
        struct sas_port *port;
 
-       if (!parent_handle)
-               return NULL;
-
        mpt2sas_port = kzalloc(sizeof(struct _sas_port),
            GFP_KERNEL);
        if (!mpt2sas_port) {
@@ -494,17 +499,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
        INIT_LIST_HEAD(&mpt2sas_port->port_list);
        INIT_LIST_HEAD(&mpt2sas_port->phy_list);
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
-       sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+       sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
        spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 
        if (!sas_node) {
-               printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
-                   ioc->name, __func__, parent_handle);
+               printk(MPT2SAS_ERR_FMT "%s: Could not find "
+                   "parent sas_address(0x%016llx)!\n", ioc->name,
+                   __func__, (unsigned long long)sas_address);
                goto out_fail;
        }
 
-       mpt2sas_port->handle = parent_handle;
-       mpt2sas_port->sas_address = sas_node->sas_address;
        if ((_transport_set_identify(ioc, handle,
            &mpt2sas_port->remote_identify))) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -596,7 +600,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
  * mpt2sas_transport_port_remove - remove port from the list
  * @ioc: per adapter object
  * @sas_address: sas address of attached device
- * @parent_handle: handle to the upstream parent(either hba or expander)
+ * @sas_address_parent: sas address of parent expander or sas host
  * Context: This function will acquire ioc->sas_node_lock.
  *
  * Removing object and freeing associated memory from the
@@ -606,7 +610,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
  */
 void
 mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
-    u16 parent_handle)
+    u64 sas_address_parent)
 {
        int i;
        unsigned long flags;
@@ -616,7 +620,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
        struct _sas_phy *mpt2sas_phy, *next_phy;
 
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
-       sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+       sas_node = _transport_sas_node_find_by_sas_address(ioc,
+           sas_address_parent);
        spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
        if (!sas_node)
                return;
@@ -642,8 +647,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
            &mpt2sas_port->phy_list, port_siblings) {
                if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
                        dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
-                           "remove: parent_handle(0x%04x), "
-                           "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
+                           "remove: sas_addr(0x%016llx), phy(%d)\n",
                            (unsigned long long)
                            mpt2sas_port->remote_identify.sas_address,
                            mpt2sas_phy->phy_id);
@@ -789,33 +793,36 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
 }
 
 /**
- * mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices
+ * mpt2sas_transport_update_links - refreshing phy link changes
  * @ioc: per adapter object
- * @handle: handle to sas_host or expander
- * @attached_handle: attached device handle
+ * @sas_address: sas address of parent expander or sas host
+ * @handle: attached device handle
  * @phy_numberv: phy number
  * @link_rate: new link rate
  *
  * Returns nothing.
  */
 void
-mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
-    u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
+mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
+     u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
 {
        unsigned long flags;
        struct _sas_node *sas_node;
        struct _sas_phy *mpt2sas_phy;
 
+       if (ioc->shost_recovery)
+               return;
+
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
-       sas_node = _transport_sas_node_find_by_handle(ioc, handle);
+       sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
        spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
        if (!sas_node)
                return;
 
        mpt2sas_phy = &sas_node->phy[phy_number];
-       mpt2sas_phy->attached_handle = attached_handle;
-       if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
-               _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+       mpt2sas_phy->attached_handle = handle;
+       if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+               _transport_set_identify(ioc, handle,
                    &mpt2sas_phy->remote_identify);
        else
                memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
@@ -827,13 +834,11 @@ mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
 
        if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
                dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
-                   "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
+                   "refresh: parent sas_addr(0x%016llx),\n"
                    "\tlink_rate(0x%02x), phy(%d)\n"
                    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
-                   handle, (unsigned long long)
-                   mpt2sas_phy->identify.sas_address, link_rate,
-                   phy_number, attached_handle,
-                   (unsigned long long)
+                   (unsigned long long)sas_address,
+                   link_rate, phy_number, handle, (unsigned long long)
                    mpt2sas_phy->remote_identify.sas_address);
 }
 
@@ -851,6 +856,17 @@ rphy_to_ioc(struct sas_rphy *rphy)
        return shost_priv(shost);
 }
 
+static struct _sas_phy *
+_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
+{
+       int i;
+
+       for (i = 0; i < ioc->sas_hba.num_phys; i++)
+               if (ioc->sas_hba.phy[i].phy == phy)
+                       return(&ioc->sas_hba.phy[i]);
+       return NULL;
+}
+
 /**
  * _transport_get_linkerrors -
  * @phy: The sas phy object
@@ -866,14 +882,8 @@ _transport_get_linkerrors(struct sas_phy *phy)
        struct _sas_phy *mpt2sas_phy;
        Mpi2ConfigReply_t mpi_reply;
        Mpi2SasPhyPage1_t phy_pg1;
-       int i;
 
-       for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
-           !mpt2sas_phy; i++) {
-               if (ioc->sas_hba.phy[i].phy != phy)
-                       continue;
-               mpt2sas_phy = &ioc->sas_hba.phy[i];
-       }
+       mpt2sas_phy = _transport_find_local_phy(ioc, phy);
 
        if (!mpt2sas_phy) /* this phy not on sas_host */
                return -EINVAL;
@@ -967,14 +977,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
        struct _sas_phy *mpt2sas_phy;
        Mpi2SasIoUnitControlReply_t mpi_reply;
        Mpi2SasIoUnitControlRequest_t mpi_request;
-       int i;
 
-       for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
-           !mpt2sas_phy; i++) {
-               if (ioc->sas_hba.phy[i].phy != phy)
-                       continue;
-               mpt2sas_phy = &ioc->sas_hba.phy[i];
-       }
+       mpt2sas_phy = _transport_find_local_phy(ioc, phy);
 
        if (!mpt2sas_phy) /* this phy not on sas_host */
                return -EINVAL;
@@ -1002,6 +1006,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
 }
 
 /**
+ * _transport_phy_enable - enable/disable phys
+ * @phy: The sas phy object
+ * @enable: enable phy when true
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_transport_phy_enable(struct sas_phy *phy, int enable)
+{
+       struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+       struct _sas_phy *mpt2sas_phy;
+       Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       u16 sz;
+       int rc = 0;
+
+       mpt2sas_phy = _transport_find_local_phy(ioc, phy);
+
+       if (!mpt2sas_phy) /* this phy not on sas_host */
+               return -EINVAL;
+
+       /* sas_iounit page 1 */
+       sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
+           sizeof(Mpi2SasIOUnit1PhyData_t));
+       sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+       if (!sas_iounit_pg1) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -ENOMEM;
+               goto out;
+       }
+       if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+           sas_iounit_pg1, sz))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -ENXIO;
+               goto out;
+       }
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -EIO;
+               goto out;
+       }
+
+       if (enable)
+               sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+                   &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+       else
+               sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+                   |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+
+       mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
+
+ out:
+       kfree(sas_iounit_pg1);
+       return rc;
+}
+
+/**
+ * _transport_phy_speed - set phy min/max link rates
+ * @phy: The sas phy object
+ * @rates: rates defined in sas_phy_linkrates
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
+{
+       struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+       struct _sas_phy *mpt2sas_phy;
+       Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+       Mpi2SasPhyPage0_t phy_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       u16 sz;
+       int i;
+       int rc = 0;
+
+       mpt2sas_phy = _transport_find_local_phy(ioc, phy);
+
+       if (!mpt2sas_phy) /* this phy not on sas_host */
+               return -EINVAL;
+
+       if (!rates->minimum_linkrate)
+               rates->minimum_linkrate = phy->minimum_linkrate;
+       else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
+               rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+       if (!rates->maximum_linkrate)
+               rates->maximum_linkrate = phy->maximum_linkrate;
+       else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
+               rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+       /* sas_iounit page 1 */
+       sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
+           sizeof(Mpi2SasIOUnit1PhyData_t));
+       sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+       if (!sas_iounit_pg1) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -ENOMEM;
+               goto out;
+       }
+       if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+           sas_iounit_pg1, sz))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -ENXIO;
+               goto out;
+       }
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -EIO;
+               goto out;
+       }
+
+       for (i = 0; i < ioc->sas_hba.num_phys; i++) {
+               if (mpt2sas_phy->phy_id != i) {
+                       sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
+                           (ioc->sas_hba.phy[i].phy->minimum_linkrate +
+                           (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
+               } else {
+                       sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
+                           (rates->minimum_linkrate +
+                           (rates->maximum_linkrate << 4));
+               }
+       }
+
+       if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
+           sz)) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               rc = -ENXIO;
+               goto out;
+       }
+
+       /* link reset */
+       _transport_phy_reset(phy, 0);
+
+       /* read phy page 0, then update the rates in the sas transport phy */
+       if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
+           mpt2sas_phy->phy_id)) {
+               phy->minimum_linkrate = _transport_convert_phy_link_rate(
+                   phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
+               phy->maximum_linkrate = _transport_convert_phy_link_rate(
+                   phy_pg0.ProgrammedLinkRate >> 4);
+               phy->negotiated_linkrate = _transport_convert_phy_link_rate(
+                   phy_pg0.NegotiatedLinkRate &
+                   MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
+       }
+
+ out:
+       kfree(sas_iounit_pg1);
+       return rc;
+}
+
+
+/**
  * _transport_smp_handler - transport portal for smp passthru
  * @shost: shost object
  * @rphy: sas transport rphy object
@@ -1025,7 +1196,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        void *psge;
        u32 sgl_flags;
        u8 issue_reset = 0;
-       unsigned long flags;
        dma_addr_t dma_addr_in = 0;
        dma_addr_t dma_addr_out = 0;
        u16 wait_state_count;
@@ -1041,18 +1211,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
                printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
                    "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
-                   req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
+                   blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
-       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
-       if (ioc->ioc_reset_in_progress) {
-               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->shost_recovery) {
                printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
                    __func__, ioc->name);
                return -EFAULT;
        }
-       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
        rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
        if (rc)
@@ -1101,10 +1268,12 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
        mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
        mpi_request->PhysicalPort = 0xFF;
+       mpi_request->VF_ID = 0; /* TODO */
+       mpi_request->VP_ID = 0;
        *((u64 *)&mpi_request->SASAddress) = (rphy) ?
            cpu_to_le64(rphy->identify.sas_address) :
            cpu_to_le64(ioc->sas_hba.sas_address);
-       mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4);
+       mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
        psge = &mpi_request->SGL;
 
        /* WRITE sgel first */
@@ -1112,13 +1281,13 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
            MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
        dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
-             req->data_len, PCI_DMA_BIDIRECTIONAL);
+               blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_out) {
-               mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+               mpt2sas_base_free_smid(ioc, smid);
                goto unmap;
        }
 
-       ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4),
+       ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
            dma_addr_out);
 
        /* incr sgel */
@@ -1129,20 +1298,21 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
            MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
            MPI2_SGE_FLAGS_END_OF_LIST);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-       dma_addr_in =  pci_map_single(ioc->pdev, bio_data(rsp->bio),
-             rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+       dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
+                                    blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_in) {
-               mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+               mpt2sas_base_free_smid(ioc, smid);
                goto unmap;
        }
 
-       ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4),
+       ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
            dma_addr_in);
 
        dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
            "sending smp request\n", ioc->name, __func__));
 
-       mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+       mpt2sas_base_put_smid_default(ioc, smid);
+       init_completion(&ioc->transport_cmds.done);
        timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
            10*HZ);
 
@@ -1170,9 +1340,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
                memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
                req->sense_len = sizeof(*mpi_reply);
-               req->data_len = 0;
-               rsp->data_len -= mpi_reply->ResponseDataLength;
-
+               req->resid_len = 0;
+               rsp->resid_len -= mpi_reply->ResponseDataLength;
        } else {
                dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
                    "%s - no reply\n", ioc->name, __func__));
@@ -1188,10 +1357,10 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
  unmap:
        if (dma_addr_out)
-               pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len,
+               pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
                    PCI_DMA_BIDIRECTIONAL);
        if (dma_addr_in)
-               pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len,
+               pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
                    PCI_DMA_BIDIRECTIONAL);
 
  out:
@@ -1205,6 +1374,8 @@ struct sas_function_template mpt2sas_transport_functions = {
        .get_enclosure_identifier = _transport_get_enclosure_identifier,
        .get_bay_identifier     = _transport_get_bay_identifier,
        .phy_reset              = _transport_phy_reset,
+       .phy_enable             = _transport_phy_enable,
+       .set_phy_speed          = _transport_phy_speed,
        .smp_handler            = _transport_smp_handler,
 };