Message ID | 20200413094938.6182-3-deepak.ukey@microchip.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | pm80xx : Updates for the driver version 0.1.39. | expand |
On Mon, Apr 13, 2020 at 11:40 AM Deepak Ukey <deepak.ukey@microchip.com> wrote: > > From: Viswas G <Viswas.G@microchip.com> > > 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. > > Signed-off-by: Viswas G <Viswas.G@microchip.com> > Signed-off-by: Radha Ramachandran <radha@google.com> > Signed-off-by: Deepak Ukey <Deepak.Ukey@microchip.com> > --- > 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 | 37 ++++++++++- > drivers/scsi/pm8001/pm8001_sas.h | 14 +++++ > drivers/scsi/pm8001/pm80xx_hwi.c | 125 +++++++++++++++++++++++++++++++++----- > 6 files changed, 223 insertions(+), 23 deletions(-) > > diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h > index 1c7f15fd69ce..fd700ce5e80c 100644 > --- a/drivers/scsi/pm8001/pm8001_defs.h > +++ b/drivers/scsi/pm8001/pm8001_defs.h > @@ -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 */ > diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c > index fb9848e1d481..6378c8e8d6b2 100644 > --- a/drivers/scsi/pm8001/pm8001_hwi.c > +++ b/drivers/scsi/pm8001/pm8001_hwi.c > @@ -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); > diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c > index 68005d0cb33d..6cbb8fa74456 100644 > --- a/drivers/scsi/pm8001/pm8001_init.c > +++ b/drivers/scsi/pm8001/pm8001_init.c > @@ -55,6 +55,12 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n" > " 4: Link rate 6.0G\n" > " 8: Link rate 12.0G\n"); > > +bool staggered_spinup; > +module_param(staggered_spinup, bool, 0644); > +MODULE_PARM_DESC(staggered_spinup, "enable the staggered spinup feature.\n" > + " 0/N: false\n" > + " 1/Y: true\n"); > + > static struct scsi_transport_template *pm8001_stt; > > /** > @@ -164,7 +170,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) > > if (!pm8001_ha) > return; > - > + del_timer(&pm8001_ha->spinup_timer); > for (i = 0; i < USI_MAX_MEMCNT; i++) { > if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { > dma_free_coherent(&pm8001_ha->pdev->dev, > @@ -486,6 +492,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, > pm8001_ha->shost = shost; > pm8001_ha->id = pm8001_id++; > pm8001_ha->logging_level = logging_level; > + pm8001_ha->staggered_spinup = staggered_spinup; > pm8001_ha->non_fatal_count = 0; > if (link_rate >= 1 && link_rate <= 15) > pm8001_ha->link_rate = (link_rate << 8); > @@ -620,7 +627,8 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, > * Currently we just set the fixed SAS address to our HBA,for manufacture, > * it should read from the EEPROM > */ > -static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) > +static void pm8001_init_sas_add_and_spinup_config > + (struct pm8001_hba_info *pm8001_ha) > { > u8 i, j; > u8 sas_add[8]; > @@ -706,6 +714,45 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) > memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, > SAS_ADDR_SIZE); > #endif > + > + /* For spinning up drives in group */ > + pm8001_ha->phy_head = -1; > + pm8001_ha->phy_tail = -1; > + > + for (i = 0; i < PM8001_MAX_PHYS; i++) > + pm8001_ha->phy_up[i] = 0xff; > + > + timer_setup(&pm8001_ha->spinup_timer, > + (void *)pm8001_spinup_timedout, 0); > + > + if (pm8001_ha->staggered_spinup == true) { > + /* spinup interval in unit of 100 ms */ > + pm8001_ha->spinup_interval = > + payload.func_specific[SPINUP_DELAY_OFFSET] * 100; > + pm8001_ha->spinup_group = > + payload.func_specific[SPINUP_GROUP_OFFSET]; > + } else { > + pm8001_ha->spinup_interval = 0; > + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; > + } > + > + if (pm8001_ha->spinup_interval > PM80XX_MAX_SPINUP_DELAY) { > + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( > + "Spinup delay from Seeprom is %d ms, reset to %d ms\n", > + pm8001_ha->spinup_interval * 100, PM80XX_MAX_SPINUP_DELAY)); > + pm8001_ha->spinup_interval = PM80XX_MAX_SPINUP_DELAY; > + } > + > + if (pm8001_ha->spinup_group > pm8001_ha->chip->n_phy) { > + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( > + "Spinup group from Seeprom is %d, reset to %d\n", > + pm8001_ha->spinup_group, pm8001_ha->chip->n_phy)); > + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; > + } > + > + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > + "Spinup interval : %d Spinup group %d\n", > + pm8001_ha->spinup_interval, pm8001_ha->spinup_group)); > } > > /* > @@ -1104,7 +1151,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, > pm80xx_set_thermal_config(pm8001_ha); > } > > - pm8001_init_sas_add(pm8001_ha); > + pm8001_init_sas_add_and_spinup_config(pm8001_ha); > /* phy setting support for motherboard controller */ > if (pm8001_configure_phy_settings(pm8001_ha)) > goto err_out_shost; > diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c > index 3a69d8d1d52e..806845203602 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.c > +++ b/drivers/scsi/pm8001/pm8001_sas.c > @@ -267,12 +267,38 @@ void pm8001_scan_start(struct Scsi_Host *shost) > int i; > 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, > + pm8001_ha->lock_flags); > + pm8001_ha->phy_started = i; > + pm8001_ha->scan_completion = ∁ > + pm8001_ha->phystart_timedout = 1; > + spin_unlock_irqrestore(&pm8001_ha->lock, > + pm8001_ha->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, pm8001_ha->lock_flags); > + pm8001_ha->phy_started = -1; > + pm8001_ha->scan_completion = NULL; > + spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags); > + } > } > > int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time) > @@ -663,6 +689,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); > diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h > index cba4e9b95c58..df02c6cd116a 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.h > +++ b/drivers/scsi/pm8001/pm8001_sas.h > @@ -261,6 +261,7 @@ struct pm8001_port { > u8 port_attached; > u16 wide_port_phymap; > u8 port_state; > + u8 port_id; > struct list_head list; > }; > > @@ -503,6 +504,7 @@ struct pm8001_hba_info { > unsigned long flags; > spinlock_t lock;/* host-wide lock */ > spinlock_t bitmap_lock; > + unsigned long lock_flags; This seems fine, only one question: why do you need this lock_flags in hba? > struct pci_dev *pdev;/* our device */ > struct device *dev; > struct pm8001_hba_memspace io_mem[6]; > @@ -566,6 +568,17 @@ struct pm8001_hba_info { > u32 non_fatal_read_length; > struct completion *phyprofile_completion; > struct phy_prof_resp phy_profile_resp; > + 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 +697,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, > diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c > index 0f4f18b0e480..0040bb4e1b71 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.c > +++ b/drivers/scsi/pm8001/pm80xx_hwi.c > @@ -46,6 +46,72 @@ > #define SMP_DIRECT 1 > #define SMP_INDIRECT 2 > > +static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, > + u32 phyId, u32 phy_op); > + > +void pm8001_queue_phyup(struct pm8001_hba_info *pm8001_ha, int phy_id) > +{ > + int i; > + > + if (pm8001_ha->phy_head == -1) { > + pm8001_ha->phy_head = pm8001_ha->phy_tail = 0; > + } else { > + /* If the phy id is already queued , discard the phy up */ > + for (i = 0; i < pm8001_ha->chip->n_phy; i++) > + if (pm8001_ha->phy_up[i] == phy_id) > + return; > + pm8001_ha->phy_tail = > + (pm8001_ha->phy_tail + 1) % PM8001_MAX_PHYS; > + } > + pm8001_ha->phy_up[pm8001_ha->phy_tail] = phy_id; > +} > + > +void pm8001_spinup_timedout(struct timer_list *t) > +{ > + struct pm8001_hba_info *pm8001_ha = > + from_timer(pm8001_ha, t, spinup_timer); > + struct pm8001_phy *phy; > + unsigned long flags; > + int i = 0, phy_id = 0xff; > + > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + > + do { > + if (i++ >= pm8001_ha->spinup_group && pm8001_ha->spinup_group) > + break; > + > + if (pm8001_ha->phy_head == -1 || pm8001_ha->reset_in_progress) > + break; /* No phys to spinup */ > + > + phy_id = pm8001_ha->phy_up[pm8001_ha->phy_head]; > + /* Processed phy id, make it invalid 0xff for > + * checking repeated phy ups > + */ > + pm8001_ha->phy_up[pm8001_ha->phy_head] = 0xff; > + if (pm8001_ha->phy_head == pm8001_ha->phy_tail) { > + pm8001_ha->phy_head = pm8001_ha->phy_tail = -1; > + } else { > + pm8001_ha->phy_head = > + (pm8001_ha->phy_head+1) % PM8001_MAX_PHYS; > + } > + > + if (phy_id == 0xff) > + break; > + phy = &pm8001_ha->phy[phy_id]; > + if (phy->phy_type & PORT_TYPE_SAS) { > + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, > + PHY_NOTIFY_ENABLE_SPINUP); > + } else { > + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, > + PHY_LINK_RESET); > + } > + } while (1); > + > + if (pm8001_ha->phy_head != -1 && pm8001_ha->spinup_group) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); > +} > > int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) > { > @@ -3302,11 +3368,12 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > port->port_state = portstate; > port->wide_port_phymap |= (1U << phy_id); > phy->phy_state = PHY_STATE_LINK_UP_SPCV; > + phy->port = port; > PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > "portid:%d; phyid:%d; linkrate:%d; " > "portstate:%x; devicetype:%x\n", > port_id, phy_id, link_rate, portstate, deviceType)); > - > + port->port_id = port_id; > switch (deviceType) { > case SAS_PHY_UNUSED: > PM8001_MSG_DBG(pm8001_ha, > @@ -3314,8 +3381,12 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > break; > case SAS_END_DEVICE: > PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); > - pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, > - PHY_NOTIFY_ENABLE_SPINUP); > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + pm8001_queue_phyup(pm8001_ha, phy_id); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); > + if (!timer_pending(&pm8001_ha->spinup_timer)) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); > port->port_attached = 1; > pm8001_get_lrate_mode(phy, link_rate); > break; > @@ -3351,9 +3422,10 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; > pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); > spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); > - if (pm8001_ha->flags == PM8001F_RUN_TIME) > - msleep(200);/*delay a moment to wait disk to spinup*/ > - pm8001_bytes_dmaed(pm8001_ha, phy_id); > + if (!pm8001_ha->reset_in_progress) { > + if (deviceType != SAS_END_DEVICE) > + pm8001_bytes_dmaed(pm8001_ha, phy_id); > + } > } > > /** > @@ -3388,11 +3460,17 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > port->port_state = portstate; > phy->phy_state = PHY_STATE_LINK_UP_SPCV; > port->port_attached = 1; > + phy->port = port; > + port->port_id = port_id; > pm8001_get_lrate_mode(phy, link_rate); > phy->phy_type |= PORT_TYPE_SATA; > phy->phy_attached = 1; > phy->sas_phy.oob_mode = SATA_OOB_MODE; > - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); > + if (!pm8001_ha->reset_in_progress) { > + sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); > + } else > + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > + "HW_EVENT_PHY_UP: not notified to host\n")); > spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); > memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), > sizeof(struct dev_to_host_fis)); > @@ -3401,7 +3479,8 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > phy->identify.device_type = SAS_SATA_DEV; > pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); > spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); > - pm8001_bytes_dmaed(pm8001_ha, phy_id); > + if (!pm8001_ha->reset_in_progress) > + pm8001_bytes_dmaed(pm8001_ha, phy_id); > } > > /** > @@ -3497,12 +3576,14 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) > status, phy_id)); > if (status == 0) { > phy->phy_state = PHY_LINK_DOWN; > - if (pm8001_ha->flags == PM8001F_RUN_TIME && > - phy->enable_completion != NULL) { > - complete(phy->enable_completion); > - phy->enable_completion = NULL; > - } > } > + > + if (pm8001_ha->flags == PM8001F_RUN_TIME && > + phy->enable_completion != NULL) { > + complete(phy->enable_completion); > + phy->enable_completion = NULL; > + } > + > return 0; > > } > @@ -3580,7 +3661,14 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) > case HW_EVENT_SATA_SPINUP_HOLD: > PM8001_MSG_DBG(pm8001_ha, > pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); > - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + pm8001_queue_phyup(pm8001_ha, phy_id); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); > + > + /* Start the timer if not started */ > + if (!timer_pending(&pm8001_ha->spinup_timer)) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); > break; > case HW_EVENT_PHY_DOWN: > PM8001_MSG_DBG(pm8001_ha, > @@ -4889,7 +4977,7 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) > PM8001_INIT_DBG(pm8001_ha, > pm8001_printk("PHY START REQ for phy_id %d\n", phy_id)); > > - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | > + payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_ENABLE | > LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); > /* SSC Disable and SAS Analog ST configuration */ > /** > @@ -4951,6 +5039,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, > u16 ITNT = 2000; > struct domain_device *dev = pm8001_dev->sas_device; > struct domain_device *parent_dev = dev->parent; > + struct pm8001_phy *phy; > + struct pm8001_port *port; > circularQ = &pm8001_ha->inbnd_q_tbl[0]; > > memset(&payload, 0, sizeof(payload)); > @@ -4982,8 +5072,11 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, > linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? > pm8001_dev->sas_device->linkrate : dev->port->linkrate; > > + phy = &pm8001_ha->phy[phy_id]; > + port = phy->port; > + > payload.phyid_portid = > - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0xFF) | > + cpu_to_le32(((port->port_id) & 0xFF) | > ((phy_id & 0xFF) << 8)); > > payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) | > -- > 2.16.3 >
> From: Viswas G <Viswas.G@microchip.com> > > 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. > > Signed-off-by: Viswas G <Viswas.G@microchip.com> > Signed-off-by: Radha Ramachandran <radha@google.com> > Signed-off-by: Deepak Ukey <Deepak.Ukey@microchip.com> > --- > 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 | 37 ++++++++++- > drivers/scsi/pm8001/pm8001_sas.h | 14 +++++ > drivers/scsi/pm8001/pm80xx_hwi.c | 125 > +++++++++++++++++++++++++++++++++----- > 6 files changed, 223 insertions(+), 23 deletions(-) > > diff --git a/drivers/scsi/pm8001/pm8001_defs.h > b/drivers/scsi/pm8001/pm8001_defs.h > index 1c7f15fd69ce..fd700ce5e80c 100644 > --- a/drivers/scsi/pm8001/pm8001_defs.h > +++ b/drivers/scsi/pm8001/pm8001_defs.h > @@ -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 */ > diff --git a/drivers/scsi/pm8001/pm8001_hwi.c > b/drivers/scsi/pm8001/pm8001_hwi.c > index fb9848e1d481..6378c8e8d6b2 100644 > --- a/drivers/scsi/pm8001/pm8001_hwi.c > +++ b/drivers/scsi/pm8001/pm8001_hwi.c > @@ -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); diff --git > a/drivers/scsi/pm8001/pm8001_init.c > b/drivers/scsi/pm8001/pm8001_init.c > index 68005d0cb33d..6cbb8fa74456 100644 > --- a/drivers/scsi/pm8001/pm8001_init.c > +++ b/drivers/scsi/pm8001/pm8001_init.c > @@ -55,6 +55,12 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n" > " 4: Link rate 6.0G\n" > " 8: Link rate 12.0G\n"); > > +bool staggered_spinup; > +module_param(staggered_spinup, bool, 0644); > +MODULE_PARM_DESC(staggered_spinup, "enable the staggered spinup feature.\n" > + " 0/N: false\n" > + " 1/Y: true\n"); > + > static struct scsi_transport_template *pm8001_stt; > > /** > @@ -164,7 +170,7 @@ static void pm8001_free(struct pm8001_hba_info > *pm8001_ha) > > if (!pm8001_ha) > return; > - > + del_timer(&pm8001_ha->spinup_timer); > for (i = 0; i < USI_MAX_MEMCNT; i++) { > if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { > dma_free_coherent(&pm8001_ha->pdev->dev, > @@ -486,6 +492,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, > pm8001_ha->shost = shost; > pm8001_ha->id = pm8001_id++; > pm8001_ha->logging_level = logging_level; > + pm8001_ha->staggered_spinup = staggered_spinup; > pm8001_ha->non_fatal_count = 0; > if (link_rate >= 1 && link_rate <= 15) > pm8001_ha->link_rate = (link_rate << 8); @@ -620,7 > +627,8 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, > * Currently we just set the fixed SAS address to our HBA,for manufacture, > * it should read from the EEPROM > */ > -static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) > +static void pm8001_init_sas_add_and_spinup_config > + (struct pm8001_hba_info *pm8001_ha) > { > u8 i, j; > u8 sas_add[8]; > @@ -706,6 +714,45 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) > memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, > SAS_ADDR_SIZE); > #endif > + > + /* For spinning up drives in group */ > + pm8001_ha->phy_head = -1; > + pm8001_ha->phy_tail = -1; > + > + for (i = 0; i < PM8001_MAX_PHYS; i++) > + pm8001_ha->phy_up[i] = 0xff; > + > + timer_setup(&pm8001_ha->spinup_timer, > + (void *)pm8001_spinup_timedout, 0); > + > + if (pm8001_ha->staggered_spinup == true) { > + /* spinup interval in unit of 100 ms */ > + pm8001_ha->spinup_interval = > + payload.func_specific[SPINUP_DELAY_OFFSET] * 100; > + pm8001_ha->spinup_group = > + payload.func_specific[SPINUP_GROUP_OFFSET]; > + } else { > + pm8001_ha->spinup_interval = 0; > + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; > + } > + > + if (pm8001_ha->spinup_interval > PM80XX_MAX_SPINUP_DELAY) { > + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( > + "Spinup delay from Seeprom is %d ms, reset to %d ms\n", > + pm8001_ha->spinup_interval * 100, PM80XX_MAX_SPINUP_DELAY)); > + pm8001_ha->spinup_interval = PM80XX_MAX_SPINUP_DELAY; > + } > + > + if (pm8001_ha->spinup_group > pm8001_ha->chip->n_phy) { > + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( > + "Spinup group from Seeprom is %d, reset to %d\n", > + pm8001_ha->spinup_group, pm8001_ha->chip->n_phy)); > + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; > + } > + > + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > + "Spinup interval : %d Spinup group %d\n", > + pm8001_ha->spinup_interval, pm8001_ha->spinup_group)); > } > > /* > @@ -1104,7 +1151,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, > pm80xx_set_thermal_config(pm8001_ha); > } > > - pm8001_init_sas_add(pm8001_ha); > + pm8001_init_sas_add_and_spinup_config(pm8001_ha); > /* phy setting support for motherboard controller */ > if (pm8001_configure_phy_settings(pm8001_ha)) > goto err_out_shost; > diff --git a/drivers/scsi/pm8001/pm8001_sas.c > b/drivers/scsi/pm8001/pm8001_sas.c > index 3a69d8d1d52e..806845203602 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.c > +++ b/drivers/scsi/pm8001/pm8001_sas.c > @@ -267,12 +267,38 @@ void pm8001_scan_start(struct Scsi_Host *shost) > int i; > 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, > + pm8001_ha->lock_flags); > + pm8001_ha->phy_started = i; > + pm8001_ha->scan_completion = ∁ > + pm8001_ha->phystart_timedout = 1; > + spin_unlock_irqrestore(&pm8001_ha->lock, > + pm8001_ha->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, pm8001_ha->lock_flags); > + pm8001_ha->phy_started = -1; > + pm8001_ha->scan_completion = NULL; > + spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags); > + } > } > > int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time) > @@ -663,6 +689,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); diff --git > a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h > index cba4e9b95c58..df02c6cd116a 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.h > +++ b/drivers/scsi/pm8001/pm8001_sas.h > @@ -261,6 +261,7 @@ struct pm8001_port { > u8 port_attached; > u16 wide_port_phymap; > u8 port_state; > + u8 port_id; > struct list_head list; > }; > > @@ -503,6 +504,7 @@ struct pm8001_hba_info { > unsigned long flags; > spinlock_t lock;/* host-wide lock */ > spinlock_t bitmap_lock; > + unsigned long lock_flags; This seems fine, only one question: why do you need this lock_flags in hba? [DU] Thanks for comment. I will remove the lok_flags from hba structure and add it locally. > struct pci_dev *pdev;/* our device */ > struct device *dev; > struct pm8001_hba_memspace io_mem[6]; @@ -566,6 +568,17 @@ > struct pm8001_hba_info { > u32 non_fatal_read_length; > struct completion *phyprofile_completion; > struct phy_prof_resp phy_profile_resp; > + 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 +697,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, diff --git > a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c > index 0f4f18b0e480..0040bb4e1b71 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.c > +++ b/drivers/scsi/pm8001/pm80xx_hwi.c > @@ -46,6 +46,72 @@ > #define SMP_DIRECT 1 > #define SMP_INDIRECT 2 > > +static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, > + u32 phyId, u32 phy_op); > + > +void pm8001_queue_phyup(struct pm8001_hba_info *pm8001_ha, int > +phy_id) { > + int i; > + > + if (pm8001_ha->phy_head == -1) { > + pm8001_ha->phy_head = pm8001_ha->phy_tail = 0; > + } else { > + /* If the phy id is already queued , discard the phy up */ > + for (i = 0; i < pm8001_ha->chip->n_phy; i++) > + if (pm8001_ha->phy_up[i] == phy_id) > + return; > + pm8001_ha->phy_tail = > + (pm8001_ha->phy_tail + 1) % PM8001_MAX_PHYS; > + } > + pm8001_ha->phy_up[pm8001_ha->phy_tail] = phy_id; } > + > +void pm8001_spinup_timedout(struct timer_list *t) { > + struct pm8001_hba_info *pm8001_ha = > + from_timer(pm8001_ha, t, spinup_timer); > + struct pm8001_phy *phy; > + unsigned long flags; > + int i = 0, phy_id = 0xff; > + > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + > + do { > + if (i++ >= pm8001_ha->spinup_group && pm8001_ha->spinup_group) > + break; > + > + if (pm8001_ha->phy_head == -1 || pm8001_ha->reset_in_progress) > + break; /* No phys to spinup */ > + > + phy_id = pm8001_ha->phy_up[pm8001_ha->phy_head]; > + /* Processed phy id, make it invalid 0xff for > + * checking repeated phy ups > + */ > + pm8001_ha->phy_up[pm8001_ha->phy_head] = 0xff; > + if (pm8001_ha->phy_head == pm8001_ha->phy_tail) { > + pm8001_ha->phy_head = pm8001_ha->phy_tail = -1; > + } else { > + pm8001_ha->phy_head = > + (pm8001_ha->phy_head+1) % PM8001_MAX_PHYS; > + } > + > + if (phy_id == 0xff) > + break; > + phy = &pm8001_ha->phy[phy_id]; > + if (phy->phy_type & PORT_TYPE_SAS) { > + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, > + PHY_NOTIFY_ENABLE_SPINUP); > + } else { > + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, > + PHY_LINK_RESET); > + } > + } while (1); > + > + if (pm8001_ha->phy_head != -1 && pm8001_ha->spinup_group) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); } > > int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 > shift_value) { @@ -3302,11 +3368,12 @@ hw_event_sas_phy_up(struct > pm8001_hba_info *pm8001_ha, void *piomb) > port->port_state = portstate; > port->wide_port_phymap |= (1U << phy_id); > phy->phy_state = PHY_STATE_LINK_UP_SPCV; > + phy->port = port; > PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > "portid:%d; phyid:%d; linkrate:%d; " > "portstate:%x; devicetype:%x\n", > port_id, phy_id, link_rate, portstate, deviceType)); > - > + port->port_id = port_id; > switch (deviceType) { > case SAS_PHY_UNUSED: > PM8001_MSG_DBG(pm8001_ha, @@ -3314,8 +3381,12 @@ > hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > break; > case SAS_END_DEVICE: > PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); > - pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, > - PHY_NOTIFY_ENABLE_SPINUP); > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + pm8001_queue_phyup(pm8001_ha, phy_id); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); > + if (!timer_pending(&pm8001_ha->spinup_timer)) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + > + msecs_to_jiffies(pm8001_ha->spinup_interval)); > port->port_attached = 1; > pm8001_get_lrate_mode(phy, link_rate); > break; > @@ -3351,9 +3422,10 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; > pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); > spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); > - if (pm8001_ha->flags == PM8001F_RUN_TIME) > - msleep(200);/*delay a moment to wait disk to spinup*/ > - pm8001_bytes_dmaed(pm8001_ha, phy_id); > + if (!pm8001_ha->reset_in_progress) { > + if (deviceType != SAS_END_DEVICE) > + pm8001_bytes_dmaed(pm8001_ha, phy_id); > + } > } > > /** > @@ -3388,11 +3460,17 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > port->port_state = portstate; > phy->phy_state = PHY_STATE_LINK_UP_SPCV; > port->port_attached = 1; > + phy->port = port; > + port->port_id = port_id; > pm8001_get_lrate_mode(phy, link_rate); > phy->phy_type |= PORT_TYPE_SATA; > phy->phy_attached = 1; > phy->sas_phy.oob_mode = SATA_OOB_MODE; > - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); > + if (!pm8001_ha->reset_in_progress) { > + sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); > + } else > + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( > + "HW_EVENT_PHY_UP: not notified to host\n")); > spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); > memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), > sizeof(struct dev_to_host_fis)); @@ -3401,7 +3479,8 @@ > hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) > phy->identify.device_type = SAS_SATA_DEV; > pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); > spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); > - pm8001_bytes_dmaed(pm8001_ha, phy_id); > + if (!pm8001_ha->reset_in_progress) > + pm8001_bytes_dmaed(pm8001_ha, phy_id); > } > > /** > @@ -3497,12 +3576,14 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) > status, phy_id)); > if (status == 0) { > phy->phy_state = PHY_LINK_DOWN; > - if (pm8001_ha->flags == PM8001F_RUN_TIME && > - phy->enable_completion != NULL) { > - complete(phy->enable_completion); > - phy->enable_completion = NULL; > - } > } > + > + if (pm8001_ha->flags == PM8001F_RUN_TIME && > + phy->enable_completion != NULL) { > + complete(phy->enable_completion); > + phy->enable_completion = NULL; > + } > + > return 0; > > } > @@ -3580,7 +3661,14 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) > case HW_EVENT_SATA_SPINUP_HOLD: > PM8001_MSG_DBG(pm8001_ha, > pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); > - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); > + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); > + pm8001_queue_phyup(pm8001_ha, phy_id); > + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); > + > + /* Start the timer if not started */ > + if (!timer_pending(&pm8001_ha->spinup_timer)) > + mod_timer(&pm8001_ha->spinup_timer, > + jiffies + > + msecs_to_jiffies(pm8001_ha->spinup_interval)); > break; > case HW_EVENT_PHY_DOWN: > PM8001_MSG_DBG(pm8001_ha, @@ -4889,7 +4977,7 @@ > pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) > PM8001_INIT_DBG(pm8001_ha, > pm8001_printk("PHY START REQ for phy_id %d\n", > phy_id)); > > - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | > + payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_ENABLE | > LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); > /* SSC Disable and SAS Analog ST configuration */ > /** > @@ -4951,6 +5039,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, > u16 ITNT = 2000; > struct domain_device *dev = pm8001_dev->sas_device; > struct domain_device *parent_dev = dev->parent; > + struct pm8001_phy *phy; > + struct pm8001_port *port; > circularQ = &pm8001_ha->inbnd_q_tbl[0]; > > memset(&payload, 0, sizeof(payload)); @@ -4982,8 +5072,11 @@ > static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, > linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? > pm8001_dev->sas_device->linkrate : > dev->port->linkrate; > > + phy = &pm8001_ha->phy[phy_id]; > + port = phy->port; > + > payload.phyid_portid = > - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0xFF) | > + cpu_to_le32(((port->port_id) & 0xFF) | > ((phy_id & 0xFF) << 8)); > > payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & > 0x01) | > -- > 2.16.3 >
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 1c7f15fd69ce..fd700ce5e80c 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -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 */ diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index fb9848e1d481..6378c8e8d6b2 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -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); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 68005d0cb33d..6cbb8fa74456 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -55,6 +55,12 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n" " 4: Link rate 6.0G\n" " 8: Link rate 12.0G\n"); +bool staggered_spinup; +module_param(staggered_spinup, bool, 0644); +MODULE_PARM_DESC(staggered_spinup, "enable the staggered spinup feature.\n" + " 0/N: false\n" + " 1/Y: true\n"); + static struct scsi_transport_template *pm8001_stt; /** @@ -164,7 +170,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) if (!pm8001_ha) return; - + del_timer(&pm8001_ha->spinup_timer); for (i = 0; i < USI_MAX_MEMCNT; i++) { if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { dma_free_coherent(&pm8001_ha->pdev->dev, @@ -486,6 +492,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->shost = shost; pm8001_ha->id = pm8001_id++; pm8001_ha->logging_level = logging_level; + pm8001_ha->staggered_spinup = staggered_spinup; pm8001_ha->non_fatal_count = 0; if (link_rate >= 1 && link_rate <= 15) pm8001_ha->link_rate = (link_rate << 8); @@ -620,7 +627,8 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, * Currently we just set the fixed SAS address to our HBA,for manufacture, * it should read from the EEPROM */ -static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) +static void pm8001_init_sas_add_and_spinup_config + (struct pm8001_hba_info *pm8001_ha) { u8 i, j; u8 sas_add[8]; @@ -706,6 +714,45 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, SAS_ADDR_SIZE); #endif + + /* For spinning up drives in group */ + pm8001_ha->phy_head = -1; + pm8001_ha->phy_tail = -1; + + for (i = 0; i < PM8001_MAX_PHYS; i++) + pm8001_ha->phy_up[i] = 0xff; + + timer_setup(&pm8001_ha->spinup_timer, + (void *)pm8001_spinup_timedout, 0); + + if (pm8001_ha->staggered_spinup == true) { + /* spinup interval in unit of 100 ms */ + pm8001_ha->spinup_interval = + payload.func_specific[SPINUP_DELAY_OFFSET] * 100; + pm8001_ha->spinup_group = + payload.func_specific[SPINUP_GROUP_OFFSET]; + } else { + pm8001_ha->spinup_interval = 0; + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; + } + + if (pm8001_ha->spinup_interval > PM80XX_MAX_SPINUP_DELAY) { + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( + "Spinup delay from Seeprom is %d ms, reset to %d ms\n", + pm8001_ha->spinup_interval * 100, PM80XX_MAX_SPINUP_DELAY)); + pm8001_ha->spinup_interval = PM80XX_MAX_SPINUP_DELAY; + } + + if (pm8001_ha->spinup_group > pm8001_ha->chip->n_phy) { + PM8001_DISC_DBG(pm8001_ha, pm8001_printk( + "Spinup group from Seeprom is %d, reset to %d\n", + pm8001_ha->spinup_group, pm8001_ha->chip->n_phy)); + pm8001_ha->spinup_group = pm8001_ha->chip->n_phy; + } + + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( + "Spinup interval : %d Spinup group %d\n", + pm8001_ha->spinup_interval, pm8001_ha->spinup_group)); } /* @@ -1104,7 +1151,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm80xx_set_thermal_config(pm8001_ha); } - pm8001_init_sas_add(pm8001_ha); + pm8001_init_sas_add_and_spinup_config(pm8001_ha); /* phy setting support for motherboard controller */ if (pm8001_configure_phy_settings(pm8001_ha)) goto err_out_shost; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 3a69d8d1d52e..806845203602 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -267,12 +267,38 @@ void pm8001_scan_start(struct Scsi_Host *shost) int i; 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, + pm8001_ha->lock_flags); + pm8001_ha->phy_started = i; + pm8001_ha->scan_completion = ∁ + pm8001_ha->phystart_timedout = 1; + spin_unlock_irqrestore(&pm8001_ha->lock, + pm8001_ha->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, pm8001_ha->lock_flags); + pm8001_ha->phy_started = -1; + pm8001_ha->scan_completion = NULL; + spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags); + } } int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time) @@ -663,6 +689,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); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index cba4e9b95c58..df02c6cd116a 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -261,6 +261,7 @@ struct pm8001_port { u8 port_attached; u16 wide_port_phymap; u8 port_state; + u8 port_id; struct list_head list; }; @@ -503,6 +504,7 @@ struct pm8001_hba_info { unsigned long flags; spinlock_t lock;/* host-wide lock */ spinlock_t bitmap_lock; + unsigned long lock_flags; struct pci_dev *pdev;/* our device */ struct device *dev; struct pm8001_hba_memspace io_mem[6]; @@ -566,6 +568,17 @@ struct pm8001_hba_info { u32 non_fatal_read_length; struct completion *phyprofile_completion; struct phy_prof_resp phy_profile_resp; + 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 +697,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, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 0f4f18b0e480..0040bb4e1b71 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -46,6 +46,72 @@ #define SMP_DIRECT 1 #define SMP_INDIRECT 2 +static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, + u32 phyId, u32 phy_op); + +void pm8001_queue_phyup(struct pm8001_hba_info *pm8001_ha, int phy_id) +{ + int i; + + if (pm8001_ha->phy_head == -1) { + pm8001_ha->phy_head = pm8001_ha->phy_tail = 0; + } else { + /* If the phy id is already queued , discard the phy up */ + for (i = 0; i < pm8001_ha->chip->n_phy; i++) + if (pm8001_ha->phy_up[i] == phy_id) + return; + pm8001_ha->phy_tail = + (pm8001_ha->phy_tail + 1) % PM8001_MAX_PHYS; + } + pm8001_ha->phy_up[pm8001_ha->phy_tail] = phy_id; +} + +void pm8001_spinup_timedout(struct timer_list *t) +{ + struct pm8001_hba_info *pm8001_ha = + from_timer(pm8001_ha, t, spinup_timer); + struct pm8001_phy *phy; + unsigned long flags; + int i = 0, phy_id = 0xff; + + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); + + do { + if (i++ >= pm8001_ha->spinup_group && pm8001_ha->spinup_group) + break; + + if (pm8001_ha->phy_head == -1 || pm8001_ha->reset_in_progress) + break; /* No phys to spinup */ + + phy_id = pm8001_ha->phy_up[pm8001_ha->phy_head]; + /* Processed phy id, make it invalid 0xff for + * checking repeated phy ups + */ + pm8001_ha->phy_up[pm8001_ha->phy_head] = 0xff; + if (pm8001_ha->phy_head == pm8001_ha->phy_tail) { + pm8001_ha->phy_head = pm8001_ha->phy_tail = -1; + } else { + pm8001_ha->phy_head = + (pm8001_ha->phy_head+1) % PM8001_MAX_PHYS; + } + + if (phy_id == 0xff) + break; + phy = &pm8001_ha->phy[phy_id]; + if (phy->phy_type & PORT_TYPE_SAS) { + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, + PHY_NOTIFY_ENABLE_SPINUP); + } else { + PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, + PHY_LINK_RESET); + } + } while (1); + + if (pm8001_ha->phy_head != -1 && pm8001_ha->spinup_group) + mod_timer(&pm8001_ha->spinup_timer, + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); +} int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) { @@ -3302,11 +3368,12 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) port->port_state = portstate; port->wide_port_phymap |= (1U << phy_id); phy->phy_state = PHY_STATE_LINK_UP_SPCV; + phy->port = port; PM8001_MSG_DBG(pm8001_ha, pm8001_printk( "portid:%d; phyid:%d; linkrate:%d; " "portstate:%x; devicetype:%x\n", port_id, phy_id, link_rate, portstate, deviceType)); - + port->port_id = port_id; switch (deviceType) { case SAS_PHY_UNUSED: PM8001_MSG_DBG(pm8001_ha, @@ -3314,8 +3381,12 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) break; case SAS_END_DEVICE: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); - pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, - PHY_NOTIFY_ENABLE_SPINUP); + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); + pm8001_queue_phyup(pm8001_ha, phy_id); + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); + if (!timer_pending(&pm8001_ha->spinup_timer)) + mod_timer(&pm8001_ha->spinup_timer, + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; @@ -3351,9 +3422,10 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); - if (pm8001_ha->flags == PM8001F_RUN_TIME) - msleep(200);/*delay a moment to wait disk to spinup*/ - pm8001_bytes_dmaed(pm8001_ha, phy_id); + if (!pm8001_ha->reset_in_progress) { + if (deviceType != SAS_END_DEVICE) + pm8001_bytes_dmaed(pm8001_ha, phy_id); + } } /** @@ -3388,11 +3460,17 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPCV; port->port_attached = 1; + phy->port = port; + port->port_id = port_id; pm8001_get_lrate_mode(phy, link_rate); phy->phy_type |= PORT_TYPE_SATA; phy->phy_attached = 1; phy->sas_phy.oob_mode = SATA_OOB_MODE; - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); + if (!pm8001_ha->reset_in_progress) { + sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); + } else + PM8001_MSG_DBG(pm8001_ha, pm8001_printk( + "HW_EVENT_PHY_UP: not notified to host\n")); spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), sizeof(struct dev_to_host_fis)); @@ -3401,7 +3479,8 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) phy->identify.device_type = SAS_SATA_DEV; pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); - pm8001_bytes_dmaed(pm8001_ha, phy_id); + if (!pm8001_ha->reset_in_progress) + pm8001_bytes_dmaed(pm8001_ha, phy_id); } /** @@ -3497,12 +3576,14 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) status, phy_id)); if (status == 0) { phy->phy_state = PHY_LINK_DOWN; - if (pm8001_ha->flags == PM8001F_RUN_TIME && - phy->enable_completion != NULL) { - complete(phy->enable_completion); - phy->enable_completion = NULL; - } } + + if (pm8001_ha->flags == PM8001F_RUN_TIME && + phy->enable_completion != NULL) { + complete(phy->enable_completion); + phy->enable_completion = NULL; + } + return 0; } @@ -3580,7 +3661,14 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) case HW_EVENT_SATA_SPINUP_HOLD: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); + spin_lock_irqsave(&pm8001_ha->phy_q_lock, flags); + pm8001_queue_phyup(pm8001_ha, phy_id); + spin_unlock_irqrestore(&pm8001_ha->phy_q_lock, flags); + + /* Start the timer if not started */ + if (!timer_pending(&pm8001_ha->spinup_timer)) + mod_timer(&pm8001_ha->spinup_timer, + jiffies + msecs_to_jiffies(pm8001_ha->spinup_interval)); break; case HW_EVENT_PHY_DOWN: PM8001_MSG_DBG(pm8001_ha, @@ -4889,7 +4977,7 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) PM8001_INIT_DBG(pm8001_ha, pm8001_printk("PHY START REQ for phy_id %d\n", phy_id)); - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | + payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_ENABLE | LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); /* SSC Disable and SAS Analog ST configuration */ /** @@ -4951,6 +5039,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; struct domain_device *parent_dev = dev->parent; + struct pm8001_phy *phy; + struct pm8001_port *port; circularQ = &pm8001_ha->inbnd_q_tbl[0]; memset(&payload, 0, sizeof(payload)); @@ -4982,8 +5072,11 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? pm8001_dev->sas_device->linkrate : dev->port->linkrate; + phy = &pm8001_ha->phy[phy_id]; + port = phy->port; + payload.phyid_portid = - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0xFF) | + cpu_to_le32(((port->port_id) & 0xFF) | ((phy_id & 0xFF) << 8)); payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) |