Skip to contentSkip to conversation

pm80xx : Updates for the driver version 0.1.39.

PATCH Superseded Deepak Ukey 4 participants 6 messages Aug 3, 2020

Subsystems (2)

v5 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v5 cover pm80xx : Updates for the driver version 0.1.39.

From: Deepak Ukey <[email protected]>

This patch set includes some bug fixes and features for pm80xx driver.

Changes from V4:
For "Support for get phy profile functionality."
-Added support for big endian system for phy_status structure.

Viswas G (2):
pm80xx : Support for get phy profile functionality. pm80xx : Staggered spin up support.

 drivers/scsi/pm8001/pm8001_ctl.h  |  33 ++++++
 drivers/scsi/pm8001/pm8001_defs.h |   3 +
 drivers/scsi/pm8001/pm8001_hwi.c  |  14 ++-
 drivers/scsi/pm8001/pm8001_init.c |  55 +++++++++-
 drivers/scsi/pm8001/pm8001_sas.c  |  36 ++++++-
 drivers/scsi/pm8001/pm8001_sas.h  |  18 ++++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 213 ++++++++++++++++++++++++++++++++++----
 drivers/scsi/pm8001/pm80xx_hwi.h  |   2 +
 8 files changed, 349 insertions(+), 25 deletions(-)
Signature · 1 line
2.16.3
#1 lore raw

PATCH v5 1/2 pm80xx : Support for get phy profile functionality.

From: Viswas G <[email protected]>

Added the support to get the phy profile which gives information about the phy states, port and errors on phy.

---
 drivers/scsi/pm8001/pm8001_ctl.h  | 33 +++++++++++++++
 drivers/scsi/pm8001/pm8001_init.c |  2 +
 drivers/scsi/pm8001/pm8001_sas.h  |  5 +++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 88 ++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm80xx_hwi.h  |  2 +
 5 files changed, 128 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_ctl.h +33 -0
index d0d43a250b9e..29b3852cea2c 100644
@@ -41,6 +41,39 @@
 #ifndef PM8001_CTL_H_INCLUDED
 #define PM8001_CTL_H_INCLUDED
 
+#ifdef __LITTLE_ENDIAN_BITFIELD
+struct phy_status {
+	char		phy_id;
+	unsigned int	phy_state:4;
+	unsigned int	nlr:4;
+	unsigned int	plr:4;
+	unsigned int	reserved1:12;
+	unsigned char	port_id;
+	unsigned int	prts:4;
+	unsigned int	reserved2:20;
+} __packed;
+#else
+struct phy_status {
+	char		phy_id;
+	unsigned int	reserved:12;
+	unsigned int	plr:4;
+	unsigned int	nlr:4;
+	unsigned int	phy_state:4;
+	unsigned char	port_id;
+	unsigned int	reserved:20;
+	unsigned int	prts:4;
+} __packed;
+#endif
+
+struct phy_errcnt {
+	unsigned int	InvalidDword;
+	unsigned int	runningDisparityError;
+	unsigned int	codeViolation;
+	unsigned int	LossOfSyncDW;
+	unsigned int	phyResetProblem;
+	unsigned int	inboundCRCError;
+};
+
 #define IOCTL_BUF_SIZE		4096
 #define HEADER_LEN			28
 #define SIZE_OFFSET			16
drivers/scsi/pm8001/pm8001_init.c +2 -0
index 9e99262a2b9d..ff65d6cf6d31 100644
@@ -398,6 +398,8 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
 		pm8001_ha->ccb_info[i].task = NULL;
 		pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff;
 		pm8001_ha->ccb_info[i].device = NULL;
+		pm8001_ha->ccb_info[i].completion = NULL;
+		pm8001_ha->ccb_info[i].resp_buf = NULL;
 		++pm8001_ha->tags_num;
 	}
 	pm8001_ha->flags = PM8001F_INIT_TIME;
drivers/scsi/pm8001/pm8001_sas.h +5 -0
index ae7ba9b3c4bc..488af79dec47 100644
@@ -56,6 +56,7 @@
 #include <scsi/sas_ata.h>
 #include <linux/atomic.h>
 #include "pm8001_defs.h"
+#include "pm8001_ctl.h"
 
 #define DRV_NAME		"pm80xx"
 #define DRV_VERSION		"0.1.39"
@@ -244,6 +245,8 @@ struct pm8001_dispatch {
 	int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
 		u32 state);
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
+		int phy, int page, struct completion *comp, void *buf);
 };
 
 struct pm8001_chip_info {
@@ -318,6 +321,8 @@ struct pm8001_ccb_info {
 	struct pm8001_prd	buf_prd[PM8001_MAX_DMA_SG];
 	struct fw_control_ex	*fw_control_context;
 	u8			open_retry;
+	struct completion	*completion;
+	void			*resp_buf;
 };
 
 struct mpi_mem {
drivers/scsi/pm8001/pm80xx_hwi.c +86 -2

112 lines not on this page · raw message

drivers/scsi/pm8001/pm80xx_hwi.h +2 -0
index 701951a0f715..b5119c5479da 100644
@@ -175,7 +175,9 @@
 #define PHY_STOP_ERR_DEVICE_ATTACHED	0x1046
 
 /* phy_profile */
+#define SAS_PHY_ERR_COUNTERS_PAGE	0x01
 #define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04
+#define SAS_PHY_GENERAL_STATUS_PAGE	0x05
 #define PHY_DWORD_LENGTH		0xC
 
 /* Thermal related */
Signature · 1 line
2.16.3
maintainer
#2 lore raw

Re: [PATCH V5 1/2] pm80xx : Support for get phy profile functionality.

Quoted 242 lines · Deepak Ukey

From: Viswas G <[email protected]>

Added the support to get the phy profile which gives information about the phy states, port and errors on phy.

---
 drivers/scsi/pm8001/pm8001_ctl.h  | 33 +++++++++++++++
 drivers/scsi/pm8001/pm8001_init.c |  2 +
 drivers/scsi/pm8001/pm8001_sas.h  |  5 +++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 88 ++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm80xx_hwi.h  |  2 +
 5 files changed, 128 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_ctl.h +33 -0
index d0d43a250b9e..29b3852cea2c 100644
@@ -41,6 +41,39 @@
 #ifndef PM8001_CTL_H_INCLUDED
 #define PM8001_CTL_H_INCLUDED
 
+#ifdef __LITTLE_ENDIAN_BITFIELD
+struct phy_status {
+       char            phy_id;
+       unsigned int    phy_state:4;
+       unsigned int    nlr:4;
+       unsigned int    plr:4;
+       unsigned int    reserved1:12;
+       unsigned char   port_id;
+       unsigned int    prts:4;
+       unsigned int    reserved2:20;
+} __packed;
+#else
+struct phy_status {
+       char            phy_id;
+       unsigned int    reserved:12; reserved1?
+       unsigned int    plr:4;
+       unsigned int    nlr:4;
+       unsigned int    phy_state:4;
+       unsigned char   port_id;
+       unsigned int    reserved:20; reserved2?
+       unsigned int    prts:4;
+} __packed;
+#endif
+
+struct phy_errcnt {
+       unsigned int    InvalidDword;
+       unsigned int    runningDisparityError;
+       unsigned int    codeViolation;
+       unsigned int    LossOfSyncDW;
+       unsigned int    phyResetProblem;
+       unsigned int    inboundCRCError;
+};
+
 #define IOCTL_BUF_SIZE         4096
 #define HEADER_LEN                     28
 #define SIZE_OFFSET                    16
drivers/scsi/pm8001/pm8001_init.c +2 -0
index 9e99262a2b9d..ff65d6cf6d31 100644
@@ -398,6 +398,8 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
                pm8001_ha->ccb_info[i].task = NULL;
                pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff;
                pm8001_ha->ccb_info[i].device = NULL;
+               pm8001_ha->ccb_info[i].completion = NULL;
+               pm8001_ha->ccb_info[i].resp_buf = NULL;
                ++pm8001_ha->tags_num;
        }
        pm8001_ha->flags = PM8001F_INIT_TIME;
drivers/scsi/pm8001/pm8001_sas.h +5 -0
index ae7ba9b3c4bc..488af79dec47 100644
@@ -56,6 +56,7 @@
 #include <scsi/sas_ata.h>
 #include <linux/atomic.h>
 #include "pm8001_defs.h"
+#include "pm8001_ctl.h"
 
 #define DRV_NAME               "pm80xx"
 #define DRV_VERSION            "0.1.39"
@@ -244,6 +245,8 @@ struct pm8001_dispatch {
        int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
                u32 state);
        int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+       int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
+               int phy, int page, struct completion *comp, void *buf);
 };
 
 struct pm8001_chip_info {
@@ -318,6 +321,8 @@ struct pm8001_ccb_info {
        struct pm8001_prd       buf_prd[PM8001_MAX_DMA_SG];
        struct fw_control_ex    *fw_control_context;
        u8                      open_retry;
+       struct completion       *completion;
+       void                    *resp_buf;
 };
 
 struct mpi_mem {
drivers/scsi/pm8001/pm80xx_hwi.c +86 -2
index 4d205ebaee87..baccb082e65f 100644
@@ -3792,7 +3792,6 @@ static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha,
        PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
                        "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n",
                        status, err_qlfr_pgcd));
-
        return 0;
 }
 
@@ -3818,9 +3817,63 @@ static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha,
 static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
                        void *piomb)
 {
+       u32 tag, page_code;
+       struct phy_status *phy_status, *phy_stat;
+       struct phy_errcnt *phy_err, *phy_err_cnt;
+       struct pm8001_ccb_info *ccb;
+       struct get_phy_profile_resp *pPayload =
+               (struct get_phy_profile_resp *)(piomb + 4);
+       u32 status = le32_to_cpu(pPayload->status);
+
+       page_code = (u8)((pPayload->ppc_phyid & 0xFF00) >> 8);
+
        PM8001_MSG_DBG(pm8001_ha,
-                       pm8001_printk(" pm80xx_addition_functionality\n"));
+               pm8001_printk(" pm80xx_addition_functionality\n"));
+       if (status) {
+               /* status is FAILED */
+               PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+                       "mpiGetPhyProfileReq failed  with status 0x%08x\n",
+                       status));
+       }
 
+       tag = le32_to_cpu(pPayload->tag);
+       ccb = &pm8001_ha->ccb_info[tag];
+       if (ccb->completion != NULL) {
+               if (status) {
+                       /* signal fail status */
+                       memset(&ccb->resp_buf, 0xff, sizeof(ccb->resp_buf));
+               } else if (page_code == SAS_PHY_GENERAL_STATUS_PAGE) {
+                       phy_status = (struct phy_status *)ccb->resp_buf;
+                       phy_stat =
+                       (struct phy_status *)pPayload->ppc_specific_rsp;
+                       phy_status->phy_id =
+                               le32_to_cpu((__force __le32)phy_stat->phy_id);
+                       phy_status->phy_state =
+                               le32_to_cpu((__force __le32)phy_stat->phy_state);
+                       phy_status->plr =
+                               le32_to_cpu((__force __le32)phy_stat->plr);
+                       phy_status->nlr =
+                               le32_to_cpu((__force __le32)phy_stat->nlr);
+                       phy_status->port_id =
+                               le32_to_cpu((__force __le32)phy_stat->port_id);
+                       phy_status->prts =
+                               le32_to_cpu((__force __le32)phy_stat->prts);
+               } else if (page_code == SAS_PHY_ERR_COUNTERS_PAGE) {
+                       phy_err = (struct phy_errcnt *)ccb->resp_buf;
+                       phy_err_cnt =
+                       (struct phy_errcnt *)pPayload->ppc_specific_rsp;
+                       phy_err->InvalidDword =
+                       le32_to_cpu((__force __le32)phy_err_cnt->InvalidDword);
+                       phy_err->runningDisparityError = le32_to_cpu
+                       ((__force __le32)phy_err_cnt->runningDisparityError);
+                       phy_err->LossOfSyncDW = le32_to_cpu
+                       ((__force __le32)phy_err_cnt->LossOfSyncDW);
+                       phy_err->phyResetProblem = le32_to_cpu
+                       ((__force __le32)phy_err_cnt->phyResetProblem);
+               }
+               complete(ccb->completion);
+       }
+       pm8001_tag_free(pm8001_ha, tag);
        return 0;
 }
 
@@ -5013,6 +5066,36 @@ pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
        return IRQ_HANDLED;
 }
 
+static int pm8001_chip_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
+       int phy_id, int page_code, struct completion *comp, void *buf)
+{
+       u32 tag;
+       struct get_phy_profile_req payload;
+       struct inbound_queue_table *circularQ;
+       struct pm8001_ccb_info *ccb;
+       int rc, ppc_phyid;
+       u32 opc = OPC_INB_GET_PHY_PROFILE;
+
+       memset(&payload, 0, sizeof(payload));
+
+       rc = pm8001_tag_alloc(pm8001_ha, &tag);
+       if (rc)
+               PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Invalid tag\n"));
+
+       ccb = &pm8001_ha->ccb_info[tag];
+       ccb->completion = comp;
+       ccb->resp_buf = buf;
+       circularQ = &pm8001_ha->inbnd_q_tbl[0];
+
+       payload.tag = cpu_to_le32(tag);
+       ppc_phyid = (page_code & 0xFF)  << 8 | (phy_id & 0xFF);
+       payload.ppc_phyid = cpu_to_le32(ppc_phyid);
+
+       pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+                       sizeof(payload), 0);
+       return rc;
+}
+
 void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
        u32 operation, u32 phyid, u32 length, u32 *buf)
 {
@@ -5113,4 +5196,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
        .set_nvmd_req           = pm8001_chip_set_nvmd_req,
        .fw_flash_update_req    = pm8001_chip_fw_flash_update_req,
        .set_dev_state_req      = pm8001_chip_set_dev_state_req,
+       .get_phy_profile_req    = pm8001_chip_get_phy_profile,
 };
drivers/scsi/pm8001/pm80xx_hwi.h +2 -1
index 701951a0f715..b5119c5479da 100644
@@ -175,7 +175,9 @@
 #define PHY_STOP_ERR_DEVICE_ATTACHED   0x1046
 
 /* phy_profile */
+#define SAS_PHY_ERR_COUNTERS_PAGE      0x01
 #define SAS_PHY_ANALOG_SETTINGS_PAGE   0x04
+#define SAS_PHY_GENERAL_STATUS_PAGE    0x05
 #define PHY_DWORD_LENGTH               0xC
 
 /* Thermal related */
--

2.16.3

#3 lore raw

Re: [PATCH V5 1/2] pm80xx : Support for get phy profile functionality.

In reply to Deepak Ukey
Thank you for the patch! Yet something to improve:

Hi Deepak,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on v5.8]
[cannot apply to mkp-scsi/for-next scsi/for-next next-20200731] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Deepak-Ukey/pm80xx-Updates-for-the-driver-version-0-1-39/20200803-202113
base:    bcf876870b95592b52519ed4aafcf9d95999bc9c
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 9.3.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=xtensa

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

In file included from drivers/scsi/pm8001/pm8001_sas.h:59,

                    from drivers/scsi/pm8001/pm8001_init.c:42:
>> drivers/scsi/pm8001/pm8001_ctl.h:63:15: error: duplicate member 'reserved'
      63 |  unsigned int reserved:20;
         |               ^~~~~~~~
--
   In file included from drivers/scsi/pm8001/pm8001_sas.h:59,
                    from drivers/scsi/pm8001/pm8001_hwi.c:41:
>> drivers/scsi/pm8001/pm8001_ctl.h:63:15: error: duplicate member 'reserved'
      63 |  unsigned int reserved:20;
         |               ^~~~~~~~
   drivers/scsi/pm8001/pm8001_hwi.c: In function 'mpi_set_phys_g3_with_ssc':
   drivers/scsi/pm8001/pm8001_hwi.c:413:6: warning: variable 'value' set but not used [-Wunused-but-set-variable]
     413 |  u32 value, offset, i;
         |      ^~~~~
--
   In file included from drivers/scsi/pm8001/pm8001_sas.h:59,
                    from drivers/scsi/pm8001/pm80xx_hwi.c:41:
>> drivers/scsi/pm8001/pm8001_ctl.h:63:15: error: duplicate member 'reserved'
      63 |  unsigned int reserved:20;
         |               ^~~~~~~~
   drivers/scsi/pm8001/pm80xx_hwi.c:69:6: warning: no previous prototype for 'pm80xx_pci_mem_copy' [-Wmissing-prototypes]
      69 | void pm80xx_pci_mem_copy(struct pm8001_hba_info  *pm8001_ha, u32 soffset,
         |      ^~~~~~~~~~~~~~~~~~~
   drivers/scsi/pm8001/pm80xx_hwi.c:5099:6: warning: no previous prototype for 'mpi_set_phy_profile_req' [-Wmissing-prototypes]
    5099 | void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
         |      ^~~~~~~~~~~~~~~~~~~~~~~

vim +/reserved +63 drivers/scsi/pm8001/pm8001_ctl.h

    43	
    44	#ifdef __LITTLE_ENDIAN_BITFIELD
    45	struct phy_status {
    46		char		phy_id;
    47		unsigned int	phy_state:4;
    48		unsigned int	nlr:4;
    49		unsigned int	plr:4;
    50		unsigned int	reserved1:12;
    51		unsigned char	port_id;
    52		unsigned int	prts:4;
    53		unsigned int	reserved2:20;
    54	} __packed;
    55	#else
    56	struct phy_status {
    57		char		phy_id;
    58		unsigned int	reserved:12;
    59		unsigned int	plr:4;
    60		unsigned int	nlr:4;
    61		unsigned int	phy_state:4;
    62		unsigned char	port_id;
  > 63		unsigned int	reserved:20;
    64		unsigned int	prts:4;
    65	} __packed;
    66	#endif
    67	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#4 lore raw

PATCH v5 2/2 pm80xx : Staggered spin up support.

In reply to Deepak Ukey

From: Viswas G <[email protected]>

As a part of drive discovery, driver will initaite the drive spin up. If all drives do spin up together, it will result in large power consumption. To reduce the power consumption, driver provide an option to make a small group of drives (say 3 or 4 drives together) to do the spin up. The delay between two spin up group and no of drives to spin up (group) can be programmed by the customer in seeprom and driver will use it to control the spinup.

---
 drivers/scsi/pm8001/pm8001_defs.h |   3 +
 drivers/scsi/pm8001/pm8001_hwi.c  |  14 ++++-
 drivers/scsi/pm8001/pm8001_init.c |  53 +++++++++++++++-
 drivers/scsi/pm8001/pm8001_sas.c  |  36 ++++++++++-
 drivers/scsi/pm8001/pm8001_sas.h  |  13 ++++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 125 +++++++++++++++++++++++++++++++++-----
 6 files changed, 221 insertions(+), 23 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +3 -0
index 1c7f15fd69ce..fd700ce5e80c 100644
@@ -101,6 +101,9 @@ enum port_type {
 #define USI_MAX_MEMCNT		(PI + PM8001_MAX_SPCV_OUTB_NUM)
 #define	CONFIG_SCSI_PM8001_MAX_DMA_SG	528
 #define PM8001_MAX_DMA_SG	CONFIG_SCSI_PM8001_MAX_DMA_SG
+#define SPINUP_DELAY_OFFSET		0x890 /* 0x890 - delay */
+#define SPINUP_GROUP_OFFSET		0x892 /* 0x892 - group */
+#define PM80XX_MAX_SPINUP_DELAY	10000 /* 10000 ms */
 enum memory_region_num {
 	AAP1 = 0x0, /* application acceleration processor */
 	IOP,	    /* IO processor */
drivers/scsi/pm8001/pm8001_hwi.c +12 -2
index fb9848e1d481..6378c8e8d6b2 100644
@@ -3237,7 +3237,7 @@ int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
 		(struct local_phy_ctl_resp *)(piomb + 4);
 	u32 status = le32_to_cpu(pPayload->status);
 	u32 phy_id = le32_to_cpu(pPayload->phyop_phyid) & ID_BITS;
-	u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS;
+	u32 phy_op = (le32_to_cpu(pPayload->phyop_phyid) & OP_BITS) >> 8;
 	tag = le32_to_cpu(pPayload->tag);
 	if (status != 0) {
 		PM8001_MSG_DBG(pm8001_ha,
@@ -3248,6 +3248,13 @@ int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			pm8001_printk("%x phy execute %x phy op success!\n",
 			phy_id, phy_op));
 		pm8001_ha->phy[phy_id].reset_success = true;
+		if (phy_op == PHY_NOTIFY_ENABLE_SPINUP &&
+			!pm8001_ha->reset_in_progress){
+			/* Notify the sas layer to discover
+			 * the the whole sas domain
+			 */
+			pm8001_bytes_dmaed(pm8001_ha, phy_id);
+		}
 	}
 	if (pm8001_ha->phy[phy_id].enable_completion) {
 		complete(pm8001_ha->phy[phy_id].enable_completion);
@@ -3643,7 +3650,10 @@ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_SUPPORTED\n"));
 		break;
 	}
-	complete(pm8001_dev->dcompletion);
+	if (pm8001_dev->dcompletion) {
+		complete(pm8001_dev->dcompletion);
+		pm8001_dev->dcompletion = NULL;
+	}
 	ccb->task = NULL;
 	ccb->ccb_tag = 0xFFFFFFFF;
 	pm8001_tag_free(pm8001_ha, htag);
drivers/scsi/pm8001/pm8001_init.c +50 -3

89 lines not on this page · raw message

drivers/scsi/pm8001/pm8001_sas.c +34 -2
index b7cbc312843e..cf1c5e68953b 100644
@@ -265,14 +265,39 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 void pm8001_scan_start(struct Scsi_Host *shost)
 {
 	int i;
+	unsigned long lock_flags;
 	struct pm8001_hba_info *pm8001_ha;
 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+	DECLARE_COMPLETION(comp);
 	pm8001_ha = sha->lldd_ha;
 	/* SAS_RE_INITIALIZATION not available in SPCv/ve */
 	if (pm8001_ha->chip_id == chip_8001)
 		PM8001_CHIP_DISP->sas_re_init_req(pm8001_ha);
-	for (i = 0; i < pm8001_ha->chip->n_phy; ++i)
-		PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i);
+
+	if (pm8001_ha->pdev->device == 0x8001 ||
+		pm8001_ha->pdev->device == 0x8081 ||
+		(pm8001_ha->spinup_interval != 0)) {
+		for (i = 0; i < pm8001_ha->chip->n_phy; ++i)
+			PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i);
+	} else {
+		for (i = 0; i < pm8001_ha->chip->n_phy; ++i) {
+			spin_lock_irqsave(&pm8001_ha->lock, lock_flags);
+			pm8001_ha->phy_started = i;
+			pm8001_ha->scan_completion = &comp;
+			pm8001_ha->phystart_timedout = 1;
+			spin_unlock_irqrestore(&pm8001_ha->lock, lock_flags);
+			PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i);
+			wait_for_completion_timeout(&comp,
+				msecs_to_jiffies(500));
+			if (pm8001_ha->phystart_timedout)
+				PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+				"Timeout happened for phyid = %d\n", i));
+		}
+		spin_lock_irqsave(&pm8001_ha->lock, lock_flags);
+		pm8001_ha->phy_started = -1;
+		pm8001_ha->scan_completion = NULL;
+		spin_unlock_irqrestore(&pm8001_ha->lock, lock_flags);
+	}
 }
 
 int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time)
@@ -662,6 +687,13 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
 			flag = 1; /* directly sata */
 		}
 	} /*register this device to HBA*/
+
+	if (pm8001_ha->phy_started == pm8001_device->attached_phy) {
+		if (pm8001_ha->scan_completion != NULL) {
+			pm8001_ha->phystart_timedout = 0;
+			complete(pm8001_ha->scan_completion);
+		}
+	}
 	PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
 	PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
 	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
drivers/scsi/pm8001/pm8001_sas.h +13 -0
index 488af79dec47..d2d73cba7f41 100644
@@ -261,6 +261,7 @@ struct pm8001_port {
 	u8			port_attached;
 	u16			wide_port_phymap;
 	u8			port_state;
+	u8			port_id;
 	struct list_head	list;
 };
 
@@ -566,6 +567,17 @@ struct pm8001_hba_info {
 	u32			reset_in_progress;
 	u32			non_fatal_count;
 	u32			non_fatal_read_length;
+	bool			staggered_spinup;
+	struct completion	*scan_completion;
+	u32			phy_started;
+	u16			phystart_timedout;
+	int			spinup_group;
+	int			spinup_interval;
+	int			phy_up[PM8001_MAX_PHYS];
+	struct timer_list	spinup_timer;
+	int			phy_head;
+	int			phy_tail;
+	spinlock_t		phy_q_lock;
 };
 
 struct pm8001_work {
@@ -684,6 +696,7 @@ void pm8001_open_reject_retry(
 int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
 	dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo,
 	u32 mem_size, u32 align);
+void pm8001_spinup_timedout(struct timer_list *t);
 
 void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha);
 int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
drivers/scsi/pm8001/pm80xx_hwi.c +109 -16

201 lines not on this page · raw message

Signature · 1 line
2.16.3
#5 lore raw

Re: [PATCH V5 2/2] pm80xx : Staggered spin up support.

Quoted 9 lines · Deepak Ukey

From: Viswas G <[email protected]>

As a part of drive discovery, driver will initaite the drive spin up. If all drives do spin up together, it will result in large power consumption. To reduce the power consumption, driver provide an option to make a small group of drives (say 3 or 4 drives together) to do the spin up. The delay between two spin up group and no of drives to spin up (group) can be programmed by the customer in seeprom and driver will use it to control the spinup.

Isn't this something we should implement in libsas instead?