diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-02 17:03:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-02 17:03:53 -0700 |
commit | 79f51b7b9c4719303f758ae8406c4e5997ed6aa3 (patch) | |
tree | 33ca1c3ee11848e75d90f811038fcd149e69d258 /drivers/scsi | |
parent | e109f506074152b7241bcbd3949a099e776cb802 (diff) | |
parent | ff275db92c935858454b721f0d960fff421634d3 (diff) | |
download | linux-79f51b7b9c4719303f758ae8406c4e5997ed6aa3.tar.bz2 |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This series has a huge amount of churn because it pulls in Mauro's doc
update changing all our txt files to rst ones.
Excluding that, we have the usual driver updates (qla2xxx, ufs, lpfc,
zfcp, ibmvfc, pm80xx, aacraid), a treewide update for scnprintf and
some other minor updates.
The major core change is Hannes moving functions out of the aacraid
driver and into the core"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (223 commits)
scsi: aic7xxx: aic97xx: Remove FreeBSD-specific code
scsi: ufs: Do not rely on prefetched data
scsi: dc395x: remove dc395x_bios_param
scsi: libiscsi: Fix error count for active session
scsi: hpsa: correct race condition in offload enabled
scsi: message: fusion: Replace zero-length array with flexible-array member
scsi: qedi: Add PCI shutdown handler support
scsi: qedi: Add MFW error recovery process
scsi: ufs: Enable block layer runtime PM for well-known logical units
scsi: ufs-qcom: Override devfreq parameters
scsi: ufshcd: Let vendor override devfreq parameters
scsi: ufshcd: Update the set frequency to devfreq
scsi: ufs: Resume ufs host before accessing ufs device
scsi: ufs-mediatek: customize the delay for enabling host
scsi: ufs: make HCE polling more compact to improve initialization latency
scsi: ufs: allow custom delay prior to host enabling
scsi: ufs-mediatek: use common delay function
scsi: ufs: introduce common and flexible delay function
scsi: ufs: use an enum for host capabilities
scsi: ufs: fix uninitialized tx_lanes in ufshcd_disable_tx_lcc()
...
Diffstat (limited to 'drivers/scsi')
117 files changed, 5059 insertions, 2855 deletions
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 186259417449..b5b3154e2c28 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3654,7 +3654,7 @@ static bool __init blogic_parse(char **str, char *keyword) selected host adapter. The BusLogic Driver Probing Options are described in - <file:Documentation/scsi/BusLogic.txt>. + <file:Documentation/scsi/BusLogic.rst>. */ static int __init blogic_parseopts(char *options) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 1b6eaf8da5fa..17feff174f57 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -33,7 +33,7 @@ config SCSI Channel, and FireWire storage. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. + <file:Documentation/scsi/scsi.rst>. The module will be called scsi_mod. However, do not compile this as a module if your root file system @@ -79,7 +79,7 @@ config BLK_DEV_SD CD-ROMs. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. + <file:Documentation/scsi/scsi.rst>. The module will be called sd_mod. Do not compile this driver as a module if your root file system @@ -94,11 +94,11 @@ config CHR_DEV_ST If you want to use a SCSI tape drive under Linux, say Y and read the SCSI-HOWTO, available from <http://www.tldp.org/docs.html#howto>, and - <file:Documentation/scsi/st.txt> in the kernel source. This is NOT + <file:Documentation/scsi/st.rst> in the kernel source. This is NOT for SCSI CD-ROMs. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. The module will be called st. + <file:Documentation/scsi/scsi.rst>. The module will be called st. config BLK_DEV_SR tristate "SCSI CDROM support" @@ -112,18 +112,9 @@ config BLK_DEV_SR Make sure to say Y or M to "ISO 9660 CD-ROM file system support". To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. + <file:Documentation/scsi/scsi.rst>. The module will be called sr_mod. -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - config CHR_DEV_SG tristate "SCSI generic support" depends on SCSI @@ -142,10 +133,10 @@ config CHR_DEV_SG quality digital reader of audio CDs (<http://www.xiph.org/paranoia/>). For other devices, it's possible that you'll have to write the driver software yourself. Please read the file - <file:Documentation/scsi/scsi-generic.txt> for more information. + <file:Documentation/scsi/scsi-generic.rst> for more information. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. The module will be called sg. + <file:Documentation/scsi/scsi.rst>. The module will be called sg. If unsure, say N. @@ -158,12 +149,12 @@ config CHR_DEV_SCH don't need this for those tiny 6-slot cdrom changers. Media changers are listed as "Type: Medium Changer" in /proc/scsi/scsi. If you have such hardware and want to use it with linux, say Y - here. Check <file:Documentation/scsi/scsi-changer.txt> for details. + here. Check <file:Documentation/scsi/scsi-changer.rst> for details. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read <file:Documentation/kbuild/modules.rst> and - <file:Documentation/scsi/scsi.txt>. The module will be called ch.o. + <file:Documentation/scsi/scsi.rst>. The module will be called ch.o. If unsure, say N. config SCSI_ENCLOSURE @@ -392,7 +383,7 @@ config SCSI_AHA152X It is explained in section 3.3 of the SCSI-HOWTO, available from <http://www.tldp.org/docs.html#howto>. You might also want to - read the file <file:Documentation/scsi/aha152x.txt>. + read the file <file:Documentation/scsi/aha152x.rst>. To compile this driver as a module, choose M here: the module will be called aha152x. @@ -430,7 +421,7 @@ config SCSI_AACRAID help This driver supports a variety of Dell, HP, Adaptec, IBM and ICP storage products. For a list of supported products, refer - to <file:Documentation/scsi/aacraid.txt>. + to <file:Documentation/scsi/aacraid.rst>. To compile this driver as a module, choose M here: the module will be called aacraid. @@ -457,7 +448,7 @@ config SCSI_DPT_I2O help This driver supports all of Adaptec's I2O based RAID controllers as well as the DPT SmartRaid V cards. This is an Adaptec maintained - driver by Deanna Bonds. See <file:Documentation/scsi/dpti.txt>. + driver by Deanna Bonds. See <file:Documentation/scsi/dpti.rst>. To compile this driver as a module, choose M here: the module will be called dpt_i2o. @@ -511,8 +502,8 @@ config SCSI_BUSLOGIC This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from <http://www.tldp.org/docs.html#howto>, and the files - <file:Documentation/scsi/BusLogic.txt> and - <file:Documentation/scsi/FlashPoint.txt> for more information. + <file:Documentation/scsi/BusLogic.rst> and + <file:Documentation/scsi/FlashPoint.rst> for more information. Note that support for FlashPoint is only available for 32-bit x86 configurations. @@ -613,7 +604,7 @@ config FCOE_FNIC This is support for the Cisco PCI-Express FCoE HBA. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. + <file:Documentation/scsi/scsi.rst>. The module will be called fnic. config SCSI_SNIC @@ -623,7 +614,7 @@ config SCSI_SNIC This is support for the Cisco PCI-Express SCSI HBA. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. + <file:Documentation/scsi/scsi.rst>. The module will be called snic. config SCSI_SNIC_DEBUG_FS @@ -813,7 +804,7 @@ config SCSI_PPA newer drives)", below. For more information about this driver and how to use it you should - read the file <file:Documentation/scsi/ppa.txt>. You should also read + read the file <file:Documentation/scsi/ppa.rst>. You should also read the SCSI-HOWTO, which is available from <http://www.tldp.org/docs.html#howto>. If you use this driver, you will still be able to use the parallel port for other tasks, @@ -840,7 +831,7 @@ config SCSI_IMM here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. For more information about this driver and how to use it you should - read the file <file:Documentation/scsi/ppa.txt>. You should also read + read the file <file:Documentation/scsi/ppa.rst>. You should also read the SCSI-HOWTO, which is available from <http://www.tldp.org/docs.html#howto>. If you use this driver, you will still be able to use the parallel port for other tasks, @@ -930,7 +921,7 @@ config SCSI_SYM53C8XX_2 language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI controllers; you need to use the Fusion MPT driver for that. - Please read <file:Documentation/scsi/sym53c8xx_2.txt> for more + Please read <file:Documentation/scsi/sym53c8xx_2.rst> for more information. config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE @@ -1127,7 +1118,7 @@ config SCSI_QLOGIC_FAS SCSI support"), below. Information about this driver is contained in - <file:Documentation/scsi/qlogicfas.txt>. You should also read the + <file:Documentation/scsi/qlogicfas.rst>. You should also read the SCSI-HOWTO, available from <http://www.tldp.org/docs.html#howto>. @@ -1197,7 +1188,7 @@ config SCSI_DC395x This driver works, but is still in experimental status. So better have a bootable disk and a backup in case of emergency. - Documentation can be found in <file:Documentation/scsi/dc395x.txt>. + Documentation can be found in <file:Documentation/scsi/dc395x.rst>. To compile this driver as a module, choose M here: the module will be called dc395x. diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 33dbc051bff9..eb72ac8136c3 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -798,6 +798,11 @@ static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) return 0; } +static void aac_probe_container_scsi_done(struct scsi_cmnd *scsi_cmnd) +{ + aac_probe_container_callback1(scsi_cmnd); +} + int aac_probe_container(struct aac_dev *dev, int cid) { struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); @@ -810,7 +815,7 @@ int aac_probe_container(struct aac_dev *dev, int cid) return -ENOMEM; } scsicmd->list.next = NULL; - scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1; + scsicmd->scsi_done = aac_probe_container_scsi_done; scsicmd->device = scsidev; scsidev->sdev_state = 0; @@ -2601,9 +2606,7 @@ static int aac_write(struct scsi_cmnd * scsicmd) static void synchronize_callback(void *context, struct fib *fibptr) { struct aac_synchronize_reply *synchronizereply; - struct scsi_cmnd *cmd; - - cmd = context; + struct scsi_cmnd *cmd = context; if (!aac_valid_context(cmd, fibptr)) return; @@ -2644,77 +2647,8 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) int status; struct fib *cmd_fibcontext; struct aac_synchronize *synchronizecmd; - struct scsi_cmnd *cmd; struct scsi_device *sdev = scsicmd->device; - int active = 0; struct aac_dev *aac; - u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; - unsigned long flags; - - /* - * Wait for all outstanding queued commands to complete to this - * specific target (block). - */ - spin_lock_irqsave(&sdev->list_lock, flags); - list_for_each_entry(cmd, &sdev->cmd_list, list) - if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) { - u64 cmnd_lba; - u32 cmnd_count; - - if (cmd->cmnd[0] == WRITE_6) { - cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) | - (cmd->cmnd[2] << 8) | - cmd->cmnd[3]; - cmnd_count = cmd->cmnd[4]; - if (cmnd_count == 0) - cmnd_count = 256; - } else if (cmd->cmnd[0] == WRITE_16) { - cmnd_lba = ((u64)cmd->cmnd[2] << 56) | - ((u64)cmd->cmnd[3] << 48) | - ((u64)cmd->cmnd[4] << 40) | - ((u64)cmd->cmnd[5] << 32) | - ((u64)cmd->cmnd[6] << 24) | - (cmd->cmnd[7] << 16) | - (cmd->cmnd[8] << 8) | - cmd->cmnd[9]; - cmnd_count = (cmd->cmnd[10] << 24) | - (cmd->cmnd[11] << 16) | - (cmd->cmnd[12] << 8) | - cmd->cmnd[13]; - } else if (cmd->cmnd[0] == WRITE_12) { - cmnd_lba = ((u64)cmd->cmnd[2] << 24) | - (cmd->cmnd[3] << 16) | - (cmd->cmnd[4] << 8) | - cmd->cmnd[5]; - cmnd_count = (cmd->cmnd[6] << 24) | - (cmd->cmnd[7] << 16) | - (cmd->cmnd[8] << 8) | - cmd->cmnd[9]; - } else if (cmd->cmnd[0] == WRITE_10) { - cmnd_lba = ((u64)cmd->cmnd[2] << 24) | - (cmd->cmnd[3] << 16) | - (cmd->cmnd[4] << 8) | - cmd->cmnd[5]; - cmnd_count = (cmd->cmnd[7] << 8) | - cmd->cmnd[8]; - } else - continue; - if (((cmnd_lba + cmnd_count) < lba) || - (count && ((lba + count) < cmnd_lba))) - continue; - ++active; - break; - } - - spin_unlock_irqrestore(&sdev->list_lock, flags); - - /* - * Yield the processor (requeue for later) - */ - if (active) - return SCSI_MLQUEUE_DEVICE_BUSY; aac = (struct aac_dev *)sdev->host->hostdata; if (aac->in_reset) @@ -2723,8 +2657,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) /* * Allocate and initialize a Fib */ - if (!(cmd_fibcontext = aac_fib_alloc(aac))) - return SCSI_MLQUEUE_HOST_BUSY; + cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd); aac_fib_init(cmd_fibcontext); diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index f75878d773cf..355b16f0b145 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -272,36 +272,35 @@ static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, q->entries = qsize; } +static bool wait_for_io_iter(struct scsi_cmnd *cmd, void *data, bool rsvd) +{ + int *active = data; + + if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) + *active = *active + 1; + return true; +} static void aac_wait_for_io_completion(struct aac_dev *aac) { - unsigned long flagv = 0; - int i = 0; + int i = 0, active; for (i = 60; i; --i) { - struct scsi_device *dev; - struct scsi_cmnd *command; - int active = 0; - - __shost_for_each_device(dev, aac->scsi_host_ptr) { - spin_lock_irqsave(&dev->list_lock, flagv); - list_for_each_entry(command, &dev->cmd_list, list) { - if (command->SCp.phase == AAC_OWNER_FIRMWARE) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flagv); - if (active) - break; - } + active = 0; + scsi_host_busy_iter(aac->scsi_host_ptr, + wait_for_io_iter, &active); /* * We can exit If all the commands are complete */ if (active == 0) break; + dev_info(&aac->pdev->dev, + "Wait for %d commands to complete\n", active); ssleep(1); } + if (active) + dev_err(&aac->pdev->dev, + "%d outstanding commands during shutdown\n", active); } /** diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 5a8a999606ea..4725e4c763cf 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -729,7 +729,7 @@ int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback, hbacmd->request_id = cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); fibptr->flags |= FIB_CONTEXT_FLAG_SCSI_CMD; - } else if (command != HBA_IU_TYPE_SCSI_TM_REQ) + } else return -EINVAL; @@ -1476,10 +1476,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) { int index, quirks; int retval; - struct Scsi_Host *host; - struct scsi_device *dev; - struct scsi_cmnd *command; - struct scsi_cmnd *command_list; + struct Scsi_Host *host = aac->scsi_host_ptr; int jafo = 0; int bled; u64 dmamask; @@ -1495,8 +1492,6 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) * - The card is dead, or will be very shortly ;-/ so no new * commands are completing in the interrupt service. */ - host = aac->scsi_host_ptr; - scsi_block_requests(host); aac_adapter_disable_int(aac); if (aac->thread && aac->thread->pid != current->pid) { spin_unlock_irq(host->host_lock); @@ -1607,39 +1602,11 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) * This is where the assumption that the Adapter is quiesced * is important. */ - command_list = NULL; - __shost_for_each_device(dev, host) { - unsigned long flags; - spin_lock_irqsave(&dev->list_lock, flags); - list_for_each_entry(command, &dev->cmd_list, list) - if (command->SCp.phase == AAC_OWNER_FIRMWARE) { - command->SCp.buffer = (struct scatterlist *)command_list; - command_list = command; - } - spin_unlock_irqrestore(&dev->list_lock, flags); - } - while ((command = command_list)) { - command_list = (struct scsi_cmnd *)command->SCp.buffer; - command->SCp.buffer = NULL; - command->result = DID_OK << 16 - | COMMAND_COMPLETE << 8 - | SAM_STAT_TASK_SET_FULL; - command->SCp.phase = AAC_OWNER_ERROR_HANDLER; - command->scsi_done(command); - } - /* - * Any Device that was already marked offline needs to be marked - * running - */ - __shost_for_each_device(dev, host) { - if (!scsi_device_online(dev)) - scsi_device_set_state(dev, SDEV_RUNNING); - } - retval = 0; + scsi_host_complete_all_commands(host, DID_RESET); + retval = 0; out: aac->in_reset = 0; - scsi_unblock_requests(host); /* * Issue bus rescan to catch any configuration that might have @@ -1660,7 +1627,7 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) { unsigned long flagv = 0; int retval; - struct Scsi_Host * host; + struct Scsi_Host *host = aac->scsi_host_ptr; int bled; if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) @@ -1678,8 +1645,7 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) * target (block maximum 60 seconds). Although not necessary, * it does make us a good storage citizen. */ - host = aac->scsi_host_ptr; - scsi_block_requests(host); + scsi_host_block(host); /* Quiesce build, flush cache, write through mode */ if (forced < 2) @@ -1690,6 +1656,8 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) retval = _aac_reset_adapter(aac, bled, reset_type); spin_unlock_irqrestore(host->host_lock, flagv); + retval = scsi_host_unblock(host, SDEV_RUNNING); + if ((forced < 2) && (retval == -ENODEV)) { /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */ struct fib * fibctx = aac_fib_alloc(aac); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 0443b74390cf..83a60b0a8cd8 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -623,54 +623,56 @@ static int aac_ioctl(struct scsi_device *sdev, unsigned int cmd, return aac_do_ioctl(dev, cmd, arg); } -static int get_num_of_incomplete_fibs(struct aac_dev *aac) +struct fib_count_data { + int mlcnt; + int llcnt; + int ehcnt; + int fwcnt; + int krlcnt; +}; + +static bool fib_count_iter(struct scsi_cmnd *scmnd, void *data, bool reserved) { + struct fib_count_data *fib_count = data; - unsigned long flags; - struct scsi_device *sdev = NULL; + switch (scmnd->SCp.phase) { + case AAC_OWNER_FIRMWARE: + fib_count->fwcnt++; + break; + case AAC_OWNER_ERROR_HANDLER: + fib_count->ehcnt++; + break; + case AAC_OWNER_LOWLEVEL: + fib_count->llcnt++; + break; + case AAC_OWNER_MIDLEVEL: + fib_count->mlcnt++; + break; + default: + fib_count->krlcnt++; + break; + } + return true; +} + +/* Called during SCSI EH, so we don't need to block requests */ +static int get_num_of_incomplete_fibs(struct aac_dev *aac) +{ struct Scsi_Host *shost = aac->scsi_host_ptr; - struct scsi_cmnd *scmnd = NULL; struct device *ctrl_dev; + struct fib_count_data fcnt = { }; - int mlcnt = 0; - int llcnt = 0; - int ehcnt = 0; - int fwcnt = 0; - int krlcnt = 0; - - __shost_for_each_device(sdev, shost) { - spin_lock_irqsave(&sdev->list_lock, flags); - list_for_each_entry(scmnd, &sdev->cmd_list, list) { - switch (scmnd->SCp.phase) { - case AAC_OWNER_FIRMWARE: - fwcnt++; - break; - case AAC_OWNER_ERROR_HANDLER: - ehcnt++; - break; - case AAC_OWNER_LOWLEVEL: - llcnt++; - break; - case AAC_OWNER_MIDLEVEL: - mlcnt++; - break; - default: - krlcnt++; - break; - } - } - spin_unlock_irqrestore(&sdev->list_lock, flags); - } + scsi_host_busy_iter(shost, fib_count_iter, &fcnt); ctrl_dev = &aac->pdev->dev; - dev_info(ctrl_dev, "outstanding cmd: midlevel-%d\n", mlcnt); - dev_info(ctrl_dev, "outstanding cmd: lowlevel-%d\n", llcnt); - dev_info(ctrl_dev, "outstanding cmd: error handler-%d\n", ehcnt); - dev_info(ctrl_dev, "outstanding cmd: firmware-%d\n", fwcnt); - dev_info(ctrl_dev, "outstanding cmd: kernel-%d\n", krlcnt); + dev_info(ctrl_dev, "outstanding cmd: midlevel-%d\n", fcnt.mlcnt); + dev_info(ctrl_dev, "outstanding cmd: lowlevel-%d\n", fcnt.llcnt); + dev_info(ctrl_dev, "outstanding cmd: error handler-%d\n", fcnt.ehcnt); + dev_info(ctrl_dev, "outstanding cmd: firmware-%d\n", fcnt.fwcnt); + dev_info(ctrl_dev, "outstanding cmd: kernel-%d\n", fcnt.krlcnt); - return mlcnt + llcnt + ehcnt + fwcnt; + return fcnt.mlcnt + fcnt.llcnt + fcnt.ehcnt + fcnt.fwcnt; } static int aac_eh_abort(struct scsi_cmnd* cmd) @@ -732,7 +734,11 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) status = aac_hba_send(HBA_IU_TYPE_SCSI_TM_REQ, fib, (fib_callback) aac_hba_callback, (void *) cmd); - + if (status != -EINPROGRESS) { + aac_fib_complete(fib); + aac_fib_free(fib); + return ret; + } /* Wait up to 15 secs for completion */ for (count = 0; count < 15; ++count) { if (cmd->SCp.sent_command) { @@ -911,11 +917,11 @@ static int aac_eh_dev_reset(struct scsi_cmnd *cmd) info = &aac->hba_map[bus][cid]; - if (info->devtype != AAC_DEVTYPE_NATIVE_RAW && - info->reset_state > 0) + if (!(info->devtype == AAC_DEVTYPE_NATIVE_RAW && + !(info->reset_state > 0))) return FAILED; - pr_err("%s: Host adapter reset request. SCSI hang ?\n", + pr_err("%s: Host device reset request. SCSI hang ?\n", AAC_DRIVERNAME); fib = aac_fib_alloc(aac); @@ -930,7 +936,12 @@ static int aac_eh_dev_reset(struct scsi_cmnd *cmd) status = aac_hba_send(command, fib, (fib_callback) aac_tmf_callback, (void *) info); - + if (status != -EINPROGRESS) { + info->reset_state = 0; + aac_fib_complete(fib); + aac_fib_free(fib); + return ret; + } /* Wait up to 15 seconds for completion */ for (count = 0; count < 15; ++count) { if (info->reset_state == 0) { @@ -969,11 +980,11 @@ static int aac_eh_target_reset(struct scsi_cmnd *cmd) info = &aac->hba_map[bus][cid]; - if (info->devtype != AAC_DEVTYPE_NATIVE_RAW && - info->reset_state > 0) + if (!(info->devtype == AAC_DEVTYPE_NATIVE_RAW && + !(info->reset_state > 0))) return FAILED; - pr_err("%s: Host adapter reset request. SCSI hang ?\n", + pr_err("%s: Host target reset request. SCSI hang ?\n", AAC_DRIVERNAME); fib = aac_fib_alloc(aac); @@ -990,6 +1001,13 @@ static int aac_eh_target_reset(struct scsi_cmnd *cmd) (fib_callback) aac_tmf_callback, (void *) info); + if (status != -EINPROGRESS) { + info->reset_state = 0; + aac_fib_complete(fib); + aac_fib_free(fib); + return ret; + } + /* Wait up to 15 seconds for completion */ for (count = 0; count < 15; ++count) { if (info->reset_state <= 0) { @@ -1042,7 +1060,7 @@ static int aac_eh_bus_reset(struct scsi_cmnd* cmd) } } - pr_err("%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVERNAME); + pr_err("%s: Host bus reset request. SCSI hang ?\n", AAC_DRIVERNAME); /* * Check the health of the controller @@ -1270,20 +1288,21 @@ static ssize_t aac_show_flags(struct device *cdev, if (nblank(dprintk(x))) len = snprintf(buf, PAGE_SIZE, "dprintk\n"); #ifdef AAC_DETAILED_STATUS_INFO - len += snprintf(buf + len, PAGE_SIZE - len, - "AAC_DETAILED_STATUS_INFO\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "AAC_DETAILED_STATUS_INFO\n"); #endif if (dev->raw_io_interface && dev->raw_io_64) - len += snprintf(buf + len, PAGE_SIZE - len, - "SAI_READ_CAPACITY_16\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "SAI_READ_CAPACITY_16\n"); if (dev->jbod) - len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "SUPPORTED_JBOD\n"); if (dev->supplement_adapter_info.supported_options2 & AAC_OPTION_POWER_MANAGEMENT) - len += snprintf(buf + len, PAGE_SIZE - len, - "SUPPORTED_POWER_MANAGEMENT\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "SUPPORTED_POWER_MANAGEMENT\n"); if (dev->msi) - len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n"); return len; } @@ -1676,7 +1695,6 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) shost->irq = pdev->irq; shost->unique_id = unique_id; shost->max_cmd_len = 16; - shost->use_cmd_list = 1; if (aac_cfg_major == AAC_CHARDEV_NEEDS_REINIT) aac_init_char(); @@ -1895,7 +1913,7 @@ static int aac_suspend(struct pci_dev *pdev, pm_message_t state) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct aac_dev *aac = (struct aac_dev *)shost->hostdata; - scsi_block_requests(shost); + scsi_host_block(shost); aac_cancel_rescan_worker(aac); aac_send_shutdown(aac); @@ -1931,7 +1949,7 @@ static int aac_resume(struct pci_dev *pdev) * aac_send_shutdown() to block ioctls from upperlayer */ aac->adapter_shutdown = 0; - scsi_unblock_requests(shost); + scsi_host_unblock(shost, SDEV_RUNNING); return 0; @@ -1946,7 +1964,8 @@ fail_device: static void aac_shutdown(struct pci_dev *dev) { struct Scsi_Host *shost = pci_get_drvdata(dev); - scsi_block_requests(shost); + + scsi_host_block(shost); __aac_shutdown((struct aac_dev *)shost->hostdata); } @@ -1978,26 +1997,6 @@ static void aac_remove_one(struct pci_dev *pdev) } } -static void aac_flush_ios(struct aac_dev *aac) -{ - int i; - struct scsi_cmnd *cmd; - - for (i = 0; i < aac->scsi_host_ptr->can_queue; i++) { - cmd = (struct scsi_cmnd *)aac->fibs[i].callback_data; - if (cmd && (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) { - scsi_dma_unmap(cmd); - - if (aac->handle_pci_error) - cmd->result = DID_NO_CONNECT << 16; - else - cmd->result = DID_RESET << 16; - - cmd->scsi_done(cmd); - } - } -} - static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev, enum pci_channel_state error) { @@ -2012,9 +2011,9 @@ static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev, case pci_channel_io_frozen: aac->handle_pci_error = 1; - scsi_block_requests(aac->scsi_host_ptr); + scsi_host_block(shost); aac_cancel_rescan_worker(aac); - aac_flush_ios(aac); + scsi_host_complete_all_commands(shost, DID_NO_CONNECT); aac_release_resources(aac); pci_disable_pcie_error_reporting(pdev); @@ -2024,7 +2023,7 @@ static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev, case pci_channel_io_perm_failure: aac->handle_pci_error = 1; - aac_flush_ios(aac); + scsi_host_complete_all_commands(shost, DID_NO_CONNECT); return PCI_ERS_RESULT_DISCONNECT; } @@ -2065,7 +2064,6 @@ fail_device: static void aac_pci_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct scsi_device *sdev = NULL; struct aac_dev *aac = (struct aac_dev *)shost_priv(shost); if (aac_adapter_ioremap(aac, aac->base_size)) { @@ -2092,10 +2090,7 @@ static void aac_pci_resume(struct pci_dev *pdev) aac->adapter_shutdown = 0; aac->handle_pci_error = 0; - shost_for_each_device(sdev, shost) - if (sdev->sdev_state == SDEV_OFFLINE) - sdev->sdev_state = SDEV_RUNNING; - scsi_unblock_requests(aac->scsi_host_ptr); + scsi_host_unblock(shost, SDEV_RUNNING); aac_scan_host(aac); pci_save_state(pdev); diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index a242a62caaa1..c2c7850ff7b4 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -316,7 +316,7 @@ typedef struct asc_sg_head { ushort queue_cnt; ushort entry_to_copy; ushort res; - ASC_SG_LIST sg_list[0]; + ASC_SG_LIST sg_list[]; } ASC_SG_HEAD; typedef struct asc_scsi_q { diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index eb466c2e1839..90f97df1c42a 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -220,7 +220,7 @@ * ************************************************************************** - see Documentation/scsi/aha152x.txt for configuration details + see Documentation/scsi/aha152x.rst for configuration details **************************************************************************/ @@ -1249,7 +1249,7 @@ static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev "aha152x: unable to verify geometry for disk with >1GB.\n" " Using default translation. Please verify yourself.\n" " Perhaps you need to enable extended translation in the driver.\n" - " See Documentation/scsi/aha152x.txt for details.\n"); + " See Documentation/scsi/aha152x.rst for details.\n"); } } else { info_array[0] = info[0]; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index da4150c17781..5a227c03895f 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -592,7 +592,6 @@ static int aha1740_probe (struct device *dev) DMA_BIDIRECTIONAL); if (!host->ecb_dma_addr) { printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n"); - scsi_host_put (shpnt); goto err_host_put; } diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index 16743fb9eead..d4c50b8fce29 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -32,7 +32,7 @@ config AIC79XX_CMDS_PER_DEVICE on some devices. The upper bound is 253. 0 disables tagged queueing. Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic79xx.txt for details. + "tag_info" option. See Documentation/scsi/aic79xx.rst for details. config AIC79XX_RESET_DELAY_MS int "Initial bus reset delay in milli-seconds" diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 3546b8cc401f..9d027549d698 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -37,7 +37,7 @@ config AIC7XXX_CMDS_PER_DEVICE on some devices. The upper bound is 253. 0 disables tagged queueing. Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic7xxx.txt for details. + "tag_info" option. See Documentation/scsi/aic7xxx.rst for details. config AIC7XXX_RESET_DELAY_MS int "Initial bus reset delay in milli-seconds" diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 7e5044bf05c0..a336a458c978 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -3107,19 +3107,6 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) printerror = 0; } else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_BUS_DEV_RESET, TRUE)) { -#ifdef __FreeBSD__ - /* - * Don't mark the user's request for this BDR - * as completing with CAM_BDR_SENT. CAM3 - * specifies CAM_REQ_CMP. - */ - if (scb != NULL - && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV - && ahd_match_scb(ahd, scb, target, 'A', - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR)) - ahd_set_transaction_status(scb, CAM_REQ_CMP); -#endif ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD, CAM_BDR_SENT, "Bus Device Reset", /*verbose_level*/0); @@ -6067,22 +6054,17 @@ ahd_alloc(void *platform_arg, char *name) { struct ahd_softc *ahd; -#ifndef __FreeBSD__ ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC); if (!ahd) { printk("aic7xxx: cannot malloc softc!\n"); kfree(name); return NULL; } -#else - ahd = device_get_softc((device_t)platform_arg); -#endif + memset(ahd, 0, sizeof(*ahd)); ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); if (ahd->seep_config == NULL) { -#ifndef __FreeBSD__ kfree(ahd); -#endif kfree(name); return (NULL); } @@ -6206,9 +6188,7 @@ ahd_free(struct ahd_softc *ahd) kfree(ahd->seep_config); if (ahd->saved_stack != NULL) kfree(ahd->saved_stack); -#ifndef __FreeBSD__ kfree(ahd); -#endif return; } diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 259d9c20bf25..57be9609d504 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -41,7 +41,7 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr -** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt +** Firmware Specification, see Documentation/scsi/arcmsr_spec.rst ******************************************************************************* */ #include <linux/module.h> diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index c2c79a37a9ef..30914c8f29cc 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -41,7 +41,7 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr -** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt +** Firmware Specification, see Documentation/scsi/arcmsr_spec.rst ******************************************************************************* */ #include <linux/module.h> diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index d4febaadfaa3..a2d69b287c7b 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1178,12 +1178,12 @@ beiscsi_active_session_disp(struct device *dev, struct device_attribute *attr, if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { avlbl_cids = BEISCSI_ULP_AVLBL_CID(phba, ulp_num); total_cids = BEISCSI_GET_CID_COUNT(phba, ulp_num); - len += snprintf(buf+len, PAGE_SIZE - len, - "ULP%d : %d\n", ulp_num, - (total_cids - avlbl_cids)); + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, + (total_cids - avlbl_cids)); } else - len += snprintf(buf+len, PAGE_SIZE - len, - "ULP%d : %d\n", ulp_num, 0); + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, 0); } return len; @@ -1208,12 +1208,12 @@ beiscsi_free_session_disp(struct device *dev, struct device_attribute *attr, for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) - len += snprintf(buf+len, PAGE_SIZE - len, - "ULP%d : %d\n", ulp_num, - BEISCSI_ULP_AVLBL_CID(phba, ulp_num)); + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, + BEISCSI_ULP_AVLBL_CID(phba, ulp_num)); else - len += snprintf(buf+len, PAGE_SIZE - len, - "ULP%d : %d\n", ulp_num, 0); + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, 0); } return len; diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index ed5f4a6ae270..cb74ab1ae5a4 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -44,7 +44,6 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER); -static DEFINE_MUTEX(ch_mutex); static int init = 1; module_param(init, int, 0444); MODULE_PARM_DESC(init, \ @@ -569,6 +568,7 @@ static void ch_destroy(struct kref *ref) { scsi_changer *ch = container_of(ref, scsi_changer, ref); + ch->device = NULL; kfree(ch->dt); kfree(ch); } @@ -590,20 +590,22 @@ ch_open(struct inode *inode, struct file *file) scsi_changer *ch; int minor = iminor(inode); - mutex_lock(&ch_mutex); spin_lock(&ch_index_lock); ch = idr_find(&ch_index_idr, minor); - if (NULL == ch || scsi_device_get(ch->device)) { + if (ch == NULL || !kref_get_unless_zero(&ch->ref)) { spin_unlock(&ch_index_lock); - mutex_unlock(&ch_mutex); return -ENXIO; } - kref_get(&ch->ref); spin_unlock(&ch_index_lock); - + if (scsi_device_get(ch->device)) { + kref_put(&ch->ref, ch_destroy); + return -ENXIO; + } + /* Synchronize with ch_probe() */ + mutex_lock(&ch->lock); file->private_data = ch; - mutex_unlock(&ch_mutex); + mutex_unlock(&ch->lock); return 0; } @@ -938,7 +940,16 @@ static int ch_probe(struct device *dev) ch->minor = ret; sprintf(ch->name,"ch%d",ch->minor); + ret = scsi_device_get(sd); + if (ret) { + sdev_printk(KERN_WARNING, sd, "ch%d: failed to get device\n", + ch->minor); + goto remove_idr; + } + mutex_init(&ch->lock); + kref_init(&ch->ref); + ch->device = sd; class_dev = device_create(ch_sysfs_class, dev, MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch, "s%s", ch->name); @@ -946,24 +957,27 @@ static int ch_probe(struct device *dev) sdev_printk(KERN_WARNING, sd, "ch%d: device_create failed\n", ch->minor); ret = PTR_ERR(class_dev); - goto remove_idr; + goto put_device; } - mutex_init(&ch->lock); - kref_init(&ch->ref); - ch->device = sd; + mutex_lock(&ch->lock); ret = ch_readconfig(ch); - if (ret) + if (ret) { + mutex_unlock(&ch->lock); goto destroy_dev; + } if (init) ch_init_elem(ch); + mutex_unlock(&ch->lock); dev_set_drvdata(dev, ch); sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); return 0; destroy_dev: device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); +put_device: + scsi_device_put(sd); remove_idr: idr_remove(&ch_index_idr, ch->minor); free_ch: @@ -977,9 +991,11 @@ static int ch_remove(struct device *dev) spin_lock(&ch_index_lock); idr_remove(&ch_index_idr, ch->minor); + dev_set_drvdata(dev, NULL); spin_unlock(&ch_index_lock); device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); + scsi_device_put(ch->device); kref_put(&ch->ref, ch_destroy); return 0; } diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 13fbb2eab842..e95f5b3bef4d 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -61,7 +61,6 @@ #include <asm/io.h> #include <scsi/scsi.h> -#include <scsi/scsicam.h> /* needed for scsicam_bios_param */ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> @@ -1053,38 +1052,6 @@ complete: static DEF_SCSI_QCMD(dc395x_queue_command) -/* - * Return the disk geometry for the given SCSI device. - */ -static int dc395x_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info) -{ -#ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP - int heads, sectors, cylinders; - struct AdapterCtlBlk *acb; - int size = capacity; - - dprintkdbg(DBG_0, "dc395x_bios_param..............\n"); - acb = (struct AdapterCtlBlk *)sdev->host->hostdata; - heads = 64; - sectors = 32; - cylinders = size / (heads * sectors); - - if ((acb->gmode2 & NAC_GREATER_1G) && (cylinders > 1024)) { - heads = 255; - sectors = 63; - cylinders = size / (heads * sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return 0; -#else - return scsicam_bios_param(bdev, capacity, info); -#endif -} - - static void dump_register_info(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { @@ -4622,7 +4589,6 @@ static struct scsi_host_template dc395x_driver_template = { .show_info = dc395x_show_info, .name = DC395X_BANNER " " DC395X_VERSION, .queuecommand = dc395x_queue_command, - .bios_param = dc395x_bios_param, .slave_alloc = dc395x_slave_alloc, .slave_destroy = dc395x_slave_destroy, .can_queue = DC395x_MAX_CAN_QUEUE, diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h index 6bc33f4f020d..25e9251f8c78 100644 --- a/drivers/scsi/dpt/dpti_ioctl.h +++ b/drivers/scsi/dpt/dpti_ioctl.h @@ -5,7 +5,7 @@ begin : Thu Sep 7 2000 copyright : (C) 2001 by Adaptec - See Documentation/scsi/dpti.txt for history, notes, license info + See Documentation/scsi/dpti.rst for history, notes, license info and credits ***************************************************************************/ diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index abc74fd474dc..02dff3a684e0 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -8,7 +8,7 @@ July 30, 2001 First version being submitted for inclusion in the kernel. V2.4 - See Documentation/scsi/dpti.txt for history, notes, license info + See Documentation/scsi/dpti.rst for history, notes, license info and credits ***************************************************************************/ @@ -817,7 +817,7 @@ static int adpt_hba_reset(adpt_hba* pHba) } pHba->state &= ~DPTI_STATE_RESET; - adpt_fail_posted_scbs(pHba); + scsi_host_complete_all_commands(pHba->host, DID_RESET); return 0; /* return success */ } @@ -2173,7 +2173,7 @@ static irqreturn_t adpt_isr(int irq, void *dev_id) readl(reply + 12) - 1); if(cmd != NULL){ scsi_dma_unmap(cmd); - adpt_i2o_to_scsi(reply, cmd); + adpt_i2o_scsi_complete(reply, cmd); } } writel(m, pHba->reply_port); @@ -2335,13 +2335,12 @@ static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht) host->unique_id = (u32)sys_tbl_pa + pHba->unit; host->sg_tablesize = pHba->sg_tablesize; host->can_queue = pHba->post_fifo_size; - host->use_cmd_list = 1; return 0; } -static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd) +static void adpt_i2o_scsi_complete(void __iomem *reply, struct scsi_cmnd *cmd) { adpt_hba* pHba; u32 hba_status; @@ -2459,7 +2458,6 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd) if(cmd->scsi_done != NULL){ cmd->scsi_done(cmd); } - return cmd->result; } @@ -2647,23 +2645,6 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) return 0; } -static void adpt_fail_posted_scbs(adpt_hba* pHba) -{ - struct scsi_cmnd* cmd = NULL; - struct scsi_device* d = NULL; - - shost_for_each_device(d, pHba->host) { - unsigned long flags; - spin_lock_irqsave(&d->list_lock, flags); - list_for_each_entry(cmd, &d->cmd_list, list) { - cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1); - cmd->scsi_done(cmd); - } - spin_unlock_irqrestore(&d->list_lock, flags); - } -} - - /*============================================================================ * Routines from i2o subsystem *============================================================================ diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 42b1e28b5884..8a079e8d7f65 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -5,7 +5,7 @@ begin : Thu Sep 7 2000 copyright : (C) 2001 by Adaptec - See Documentation/scsi/dpti.txt for history, notes, license info + See Documentation/scsi/dpti.rst for history, notes, license info and credits ***************************************************************************/ @@ -286,7 +286,7 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba); static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba); static s32 adpt_i2o_hrt_get(adpt_hba* pHba); static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice); -static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd); +static void adpt_i2o_scsi_complete(void __iomem *reply, struct scsi_cmnd *cmd); static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht); static s32 adpt_hba_reset(adpt_hba* pHba); static s32 adpt_i2o_reset_hba(adpt_hba* pHba); @@ -295,7 +295,6 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba); static s32 adpt_send_nop(adpt_hba*pHba,u32 m); static void adpt_i2o_delete_hba(adpt_hba* pHba); static void adpt_inquiry(adpt_hba* pHba); -static void adpt_fail_posted_scbs(adpt_hba* pHba); static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u64 lun); static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ; static int adpt_i2o_online_hba(adpt_hba* pHba); diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index a0d01aea28f7..9d52d83161ed 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -138,7 +138,7 @@ int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt) * Dump trace buffer entry to memory file * and increment read index @rd_idx */ - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, (trace_max_pages * PAGE_SIZE * 3) - len, "%16llu.%09lu %-50s %8x %8x %16llx %16llx " "%16llx %16llx %16llx\n", (u64)val.tv_sec, @@ -180,7 +180,7 @@ int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt) * Dump trace buffer entry to memory file * and increment read index @rd_idx */ - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, (trace_max_pages * PAGE_SIZE * 3) - len, "%16llu.%09lu %-50s %8x %8x %16llx %16llx " "%16llx %16llx %16llx\n", (u64)val.tv_sec, @@ -220,12 +220,12 @@ int fnic_get_stats_data(struct stats_debug_info *debug, struct timespec64 val1, val2; ktime_get_real_ts64(&val1); - len = snprintf(debug->debug_buffer + len, buf_size - len, + len = scnprintf(debug->debug_buffer + len, buf_size - len, "------------------------------------------\n" "\t\tTime\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Current time : [%lld:%ld]\n" "Last stats reset time: [%lld:%09ld]\n" "Last stats read time: [%lld:%ld]\n" @@ -243,11 +243,11 @@ int fnic_get_stats_data(struct stats_debug_info *debug, stats->stats_timestamps.last_read_time = val1; - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "------------------------------------------\n" "\t\tIO Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Active IOs: %lld\nMaximum Active IOs: %lld\n" "Number of IOs: %lld\nNumber of IO Completions: %lld\n" "Number of IO Failures: %lld\nNumber of IO NOT Found: %lld\n" @@ -280,16 +280,16 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->io_stats.io_btw_10000_to_30000_msec), (u64)atomic64_read(&stats->io_stats.io_greater_than_30000_msec)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\nCurrent Max IO time : %lld\n", (u64)atomic64_read(&stats->io_stats.current_max_io_time)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tAbort Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Aborts: %lld\n" "Number of Abort Failures: %lld\n" "Number of Abort Driver Timeouts: %lld\n" @@ -318,12 +318,12 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->abts_stats.abort_issued_btw_50_to_60_sec), (u64)atomic64_read(&stats->abts_stats.abort_issued_greater_than_60_sec)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tTerminate Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Terminates: %lld\n" "Maximum Terminates: %lld\n" "Number of Terminate Driver Timeouts: %lld\n" @@ -337,12 +337,12 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->term_stats.terminate_io_not_found), (u64)atomic64_read(&stats->term_stats.terminate_failures)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tReset Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Device Resets: %lld\n" "Number of Device Reset Failures: %lld\n" "Number of Device Reset Aborts: %lld\n" @@ -368,12 +368,12 @@ int fnic_get_stats_data(struct stats_debug_info *debug, &stats->reset_stats.fnic_reset_completions), (u64)atomic64_read(&stats->reset_stats.fnic_reset_failures)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tFirmware Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Active FW Requests %lld\n" "Maximum FW Requests: %lld\n" "Number of FW out of resources: %lld\n" @@ -383,12 +383,12 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->fw_stats.fw_out_of_resources), (u64)atomic64_read(&stats->fw_stats.io_fw_errs)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tVlan Discovery Statistics\n" "------------------------------------------\n"); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Number of Vlan Discovery Requests Sent %lld\n" "Vlan Response Received with no FCF VLAN ID: %lld\n" "No solicitations recvd after vlan set, expiry count: %lld\n" @@ -398,7 +398,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->vlan_stats.sol_expiry_count), (u64)atomic64_read(&stats->vlan_stats.flogi_rejects)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\n------------------------------------------\n" "\t\tOther Important Statistics\n" "------------------------------------------\n"); @@ -406,7 +406,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, jiffies_to_timespec64(stats->misc_stats.last_isr_time, &val1); jiffies_to_timespec64(stats->misc_stats.last_ack_time, &val2); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Last ISR time: %llu (%8llu.%09lu)\n" "Last ACK time: %llu (%8llu.%09lu)\n" "Max ISR jiffies: %llu\n" @@ -452,7 +452,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->misc_stats.rport_not_ready), (u64)atomic64_read(&stats->misc_stats.frame_errors)); - len += snprintf(debug->debug_buffer + len, buf_size - len, + len += scnprintf(debug->debug_buffer + len, buf_size - len, "Firmware reported port speed: %llu\n", (u64)atomic64_read( &stats->misc_stats.current_port_speed)); @@ -742,7 +742,7 @@ int fnic_fc_trace_get_data(fnic_dbgfs_t *fnic_dbgfs_prt, u8 rdata_flag) rd_idx = fc_trace_entries.rd_idx; wr_idx = fc_trace_entries.wr_idx; if (rdata_flag == 0) { - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, (fnic_fc_trace_max_pages * PAGE_SIZE * 3) - len, "Time Stamp (UTC)\t\t" "Host No: F Type: len: FCoE_FRAME:\n"); @@ -762,11 +762,11 @@ int fnic_fc_trace_get_data(fnic_dbgfs_t *fnic_dbgfs_prt, u8 rdata_flag) } else { fc_trace = (char *)tdata; for (j = 0; j < FC_TRC_SIZE_BYTES; j++) { - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, (fnic_fc_trace_max_pages * PAGE_SIZE * 3) - len, "%02x", fc_trace[j] & 0xff); } /* for loop */ - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, (fnic_fc_trace_max_pages * PAGE_SIZE * 3) - len, "\n"); } @@ -810,7 +810,7 @@ void copy_and_format_trace_data(struct fc_trace_hdr *tdata, time64_to_tm(tdata->time_stamp.tv_sec, 0, &tm); fmt = "%02d:%02d:%04ld %02d:%02d:%02d.%09lu ns%8x %c%8x\t"; - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, fmt, tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, @@ -823,25 +823,25 @@ void copy_and_format_trace_data(struct fc_trace_hdr *tdata, for (j = 0; j < min_t(u8, tdata->frame_len, (u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE)); j++) { if (tdata->frame_type == FNIC_FC_LE) { - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, "%c", fc_trace[j]); } else { - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, "%02x", fc_trace[j] & 0xff); - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, " "); if (j == ethhdr_len || j == ethhdr_len + fcoehdr_len || j == ethhdr_len + fcoehdr_len + fchdr_len || (i > 3 && j%fchdr_len == 0)) { - len += snprintf(fnic_dbgfs_prt->buffer + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, "\n\t\t\t\t\t\t\t\t"); i++; } } /* end of else*/ } /* End of for loop*/ - len += snprintf(fnic_dbgfs_prt->buffer + len, + len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, "\n"); *orig_len = len; } diff --git a/drivers/scsi/fnic/vnic_devcmd.h b/drivers/scsi/fnic/vnic_devcmd.h index c5dde556dc7c..c20d30e36dfc 100644 --- a/drivers/scsi/fnic/vnic_devcmd.h +++ b/drivers/scsi/fnic/vnic_devcmd.h @@ -442,7 +442,7 @@ struct vnic_devcmd_notify { struct vnic_devcmd_provinfo { u8 oui[3]; u8 type; - u8 data[0]; + u8 data[]; }; /* diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 2ab774e62e40..2cc676e3df6a 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -20,7 +20,7 @@ * Added ISAPNP support for DTC436 adapters, * Thomas Sailer, sailer@ife.ee.ethz.ch * - * See Documentation/scsi/g_NCR5380.txt for more info. + * See Documentation/scsi/g_NCR5380.rst for more info. */ #include <asm/io.h> diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 381d849726ac..c764312f9ba0 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -193,7 +193,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) for (i = 1; i < MAX_RES_ARGS; i++) { if (reserve_list[i] == 0xff) break; - hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]); + hlen += scnprintf(hrec + hlen, 161 - hlen, ",%d", reserve_list[i]); } } seq_printf(m, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index a2debe0c8185..374885aa8d77 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2938,6 +2938,7 @@ static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, { u32 cache_dw_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * HISI_SAS_IOST_ITCT_CACHE_NUM; + struct device *dev = hisi_hba->dev; u32 *buf = cache; u32 i, val; @@ -2950,7 +2951,7 @@ static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, } if (val != 0xffffffff) { - pr_err("Issue occur when reading IOST/ITCT cache!\n"); + dev_err(dev, "Issue occurred in reading IOST/ITCT cache!\n"); return; } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 1d669e47b692..7ec91c3a66ca 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -650,3 +650,68 @@ void scsi_flush_work(struct Scsi_Host *shost) flush_workqueue(shost->work_q); } EXPORT_SYMBOL_GPL(scsi_flush_work); + +static bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd) +{ + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + int status = *(int *)data; + + scsi_dma_unmap(scmd); + scmd->result = status << 16; + scmd->scsi_done(scmd); + return true; +} + +/** + * scsi_host_complete_all_commands - Terminate all running commands + * @shost: Scsi Host on which commands should be terminated + * @status: Status to be set for the terminated commands + * + * There is no protection against modification of the number + * of outstanding commands. It is the responsibility of the + * caller to ensure that concurrent I/O submission and/or + * completion is stopped when calling this function. + */ +void scsi_host_complete_all_commands(struct Scsi_Host *shost, int status) +{ + blk_mq_tagset_busy_iter(&shost->tag_set, complete_all_cmds_iter, + &status); +} +EXPORT_SYMBOL_GPL(scsi_host_complete_all_commands); + +struct scsi_host_busy_iter_data { + bool (*fn)(struct scsi_cmnd *, void *, bool); + void *priv; +}; + +static bool __scsi_host_busy_iter_fn(struct request *req, void *priv, + bool reserved) +{ + struct scsi_host_busy_iter_data *iter_data = priv; + struct scsi_cmnd *sc = blk_mq_rq_to_pdu(req); + + return iter_data->fn(sc, iter_data->priv, reserved); +} + +/** + * scsi_host_busy_iter - Iterate over all busy commands + * @shost: Pointer to Scsi_Host. + * @fn: Function to call on each busy command + * @priv: Data pointer passed to @fn + * + * If locking against concurrent command completions is required + * ithas to be provided by the caller + **/ +void scsi_host_busy_iter(struct Scsi_Host *shost, + bool (*fn)(struct scsi_cmnd *, void *, bool), + void *priv) +{ + struct scsi_host_busy_iter_data iter_data = { + .fn = fn, + .priv = priv, + }; + + blk_mq_tagset_busy_iter(&shost->tag_set, __scsi_host_busy_iter_fn, + &iter_data); +} +EXPORT_SYMBOL_GPL(scsi_host_busy_iter); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1a4ddfacb458..1e9302e99d05 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -504,6 +504,12 @@ static ssize_t host_store_rescan(struct device *dev, return count; } +static void hpsa_turn_off_ioaccel_for_device(struct hpsa_scsi_dev_t *device) +{ + device->offload_enabled = 0; + device->offload_to_be_enabled = 0; +} + static ssize_t host_show_firmware_revision(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1738,8 +1744,7 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, __func__, h->scsi_host->host_no, logical_drive->bus, logical_drive->target, logical_drive->lun); - logical_drive->offload_enabled = 0; - logical_drive->offload_to_be_enabled = 0; + hpsa_turn_off_ioaccel_for_device(logical_drive); logical_drive->queue_depth = 8; } } @@ -2499,8 +2504,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, IOACCEL2_SERV_RESPONSE_FAILURE) { if (c2->error_data.status == IOACCEL2_STATUS_SR_IOACCEL_DISABLED) { - dev->offload_enabled = 0; - dev->offload_to_be_enabled = 0; + hpsa_turn_off_ioaccel_for_device(dev); } if (dev->in_reset) { @@ -3670,10 +3674,17 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h, this_device->offload_config = !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT); if (this_device->offload_config) { - this_device->offload_to_be_enabled = + bool offload_enabled = !!(ioaccel_status & OFFLOAD_ENABLED_BIT); - if (hpsa_get_raid_map(h, scsi3addr, this_device)) - this_device->offload_to_be_enabled = 0; + /* + * Check to see if offload can be enabled. + */ + if (offload_enabled) { + rc = hpsa_get_raid_map(h, scsi3addr, this_device); + if (rc) /* could not load raid_map */ + goto out; + this_device->offload_to_be_enabled = 1; + } } out: @@ -3996,8 +4007,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, } else { this_device->raid_level = RAID_UNKNOWN; this_device->offload_config = 0; - this_device->offload_enabled = 0; - this_device->offload_to_be_enabled = 0; + hpsa_turn_off_ioaccel_for_device(this_device); this_device->hba_ioaccel_enabled = 0; this_device->volume_offline = 0; this_device->queue_depth = h->nr_cmds; @@ -5230,8 +5240,12 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, /* Handles load balance across RAID 1 members. * (2-drive R1 and R10 with even # of drives.) * Appropriate for SSDs, not optimal for HDDs + * Ensure we have the correct raid_map. */ - BUG_ON(le16_to_cpu(map->layout_map_count) != 2); + if (le16_to_cpu(map->layout_map_count) != 2) { + hpsa_turn_off_ioaccel_for_device(dev); + return IO_ACCEL_INELIGIBLE; + } if (dev->offload_to_mirror) map_index += le16_to_cpu(map->data_disks_per_row); dev->offload_to_mirror = !dev->offload_to_mirror; @@ -5239,8 +5253,12 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, case HPSA_RAID_ADM: /* Handles N-way mirrors (R1-ADM) * and R10 with # of drives divisible by 3.) + * Ensure we have the correct raid_map. */ - BUG_ON(le16_to_cpu(map->layout_map_count) != 3); + if (le16_to_cpu(map->layout_map_count) != 3) { + hpsa_turn_off_ioaccel_for_device(dev); + return IO_ACCEL_INELIGIBLE; + } offload_to_mirror = dev->offload_to_mirror; raid_map_helper(map, offload_to_mirror, @@ -5265,7 +5283,10 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, r5or6_blocks_per_row = le16_to_cpu(map->strip_size) * le16_to_cpu(map->data_disks_per_row); - BUG_ON(r5or6_blocks_per_row == 0); + if (r5or6_blocks_per_row == 0) { + hpsa_turn_off_ioaccel_for_device(dev); + return IO_ACCEL_INELIGIBLE; + } stripesize = r5or6_blocks_per_row * le16_to_cpu(map->layout_map_count); #if BITS_PER_LONG == 32 @@ -8285,7 +8306,7 @@ static int detect_controller_lockup(struct ctlr_info *h) * * Called from monitor controller worker (hpsa_event_monitor_worker) * - * A Volume (or Volumes that comprise an Array set may be undergoing a + * A Volume (or Volumes that comprise an Array set) may be undergoing a * transformation, so we will be turning off ioaccel for all volumes that * make up the Array. */ @@ -8308,6 +8329,9 @@ static void hpsa_set_ioaccel_status(struct ctlr_info *h) * Run through current device list used during I/O requests. */ for (i = 0; i < h->ndevices; i++) { + int offload_to_be_enabled = 0; + int offload_config = 0; + device = h->dev[i]; if (!device) @@ -8325,25 +8349,35 @@ static void hpsa_set_ioaccel_status(struct ctlr_info *h) continue; ioaccel_status = buf[IOACCEL_STATUS_BYTE]; - device->offload_config = + + /* + * Check if offload is still configured on + */ + offload_config = !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT); - if (device->offload_config) - device->offload_to_be_enabled = + /* + * If offload is configured on, check to see if ioaccel + * needs to be enabled. + */ + if (offload_config) + offload_to_be_enabled = !!(ioaccel_status & OFFLOAD_ENABLED_BIT); /* + * If ioaccel is to be re-enabled, re-enable later during the + * scan operation so the driver can get a fresh raidmap + * before turning ioaccel back on. + */ + if (offload_to_be_enabled) + continue; + + /* * Immediately turn off ioaccel for any volume the * controller tells us to. Some of the reasons could be: * transformation - change to the LVs of an Array. * degraded volume - component failure - * - * If ioaccel is to be re-enabled, re-enable later during the - * scan operation so the driver can get a fresh raidmap - * before turning ioaccel back on. - * */ - if (!device->offload_to_be_enabled) - device->offload_enabled = 0; + hpsa_turn_off_ioaccel_for_device(device); } kfree(buf); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index df897df5cafe..7da9e060b270 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -133,6 +133,7 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); static void ibmvfc_tgt_query_target(struct ibmvfc_target *); static void ibmvfc_npiv_logout(struct ibmvfc_host *); +static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *); static const char *unknown_error = "unknown error"; @@ -413,22 +414,44 @@ static const char *ibmvfc_get_fc_type(u16 status) * @tgt: ibmvfc target struct * @action: action to perform * + * Returns: + * 0 if action changed / non-zero if not changed **/ -static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, +static int ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, enum ibmvfc_target_action action) { + int rc = -EINVAL; + switch (tgt->action) { + case IBMVFC_TGT_ACTION_LOGOUT_RPORT: + if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT || + action == IBMVFC_TGT_ACTION_DEL_RPORT) { + tgt->action = action; + rc = 0; + } + break; + case IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT: + if (action == IBMVFC_TGT_ACTION_DEL_RPORT) { + tgt->action = action; + rc = 0; + } + break; case IBMVFC_TGT_ACTION_DEL_RPORT: - if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) + if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) { tgt->action = action; + rc = 0; + } case IBMVFC_TGT_ACTION_DELETED_RPORT: break; default: - if (action == IBMVFC_TGT_ACTION_DEL_RPORT) + if (action >= IBMVFC_TGT_ACTION_LOGOUT_RPORT) tgt->add_rport = 0; tgt->action = action; + rc = 0; break; } + + return rc; } /** @@ -537,6 +560,19 @@ static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) } /** + * ibmvfc_del_tgt - Schedule cleanup and removal of the target + * @tgt: ibmvfc target struct + * @job_step: job step to perform + * + **/ +static void ibmvfc_del_tgt(struct ibmvfc_target *tgt) +{ + if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) + tgt->job_step = ibmvfc_tgt_implicit_logout_and_del; + wake_up(&tgt->vhost->work_wait_q); +} + +/** * ibmvfc_link_down - Handle a link down event from the adapter * @vhost: ibmvfc host struct * @state: ibmvfc host state to enter @@ -550,7 +586,7 @@ static void ibmvfc_link_down(struct ibmvfc_host *vhost, ENTER; scsi_block_requests(vhost->host); list_for_each_entry(tgt, &vhost->targets, queue) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); ibmvfc_set_host_state(vhost, state); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); vhost->events_to_log |= IBMVFC_AE_LINKDOWN; @@ -583,7 +619,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost) vhost->async_crq.cur = 0; list_for_each_entry(tgt, &vhost->targets, queue) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); scsi_block_requests(vhost->host); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); vhost->job_step = ibmvfc_npiv_login; @@ -1500,7 +1536,7 @@ static void ibmvfc_relogin(struct scsi_device *sdev) list_for_each_entry(tgt, &vhost->targets, queue) { if (rport == tgt->rport) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); break; } } @@ -2686,7 +2722,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO) tgt->logo_rcvd = 1; if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); ibmvfc_reinit_host(vhost); } } @@ -3220,8 +3256,8 @@ static void ibmvfc_tasklet(void *data) static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, void (*job_step) (struct ibmvfc_target *)) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); - tgt->job_step = job_step; + if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT)) + tgt->job_step = job_step; wake_up(&tgt->vhost->work_wait_q); } @@ -3237,7 +3273,7 @@ static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, void (*job_step) (struct ibmvfc_target *)) { if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); wake_up(&tgt->vhost->work_wait_q); return 0; } else @@ -3312,13 +3348,13 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; tgt->add_rport = 1; } else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); } else if (prli_rsp[index].retry) ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); } else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); break; case IBMVFC_MAD_DRIVER_FAILED: break; @@ -3335,7 +3371,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), @@ -3434,7 +3470,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), @@ -3515,33 +3551,28 @@ static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) break; } - if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); - else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && - tgt->scsi_id != tgt->new_scsi_id) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); kref_put(&tgt->kref, ibmvfc_release_tgt); wake_up(&vhost->work_wait_q); } /** - * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target + * __ibmvfc_tgt_get_implicit_logout_evt - Allocate and init an event for implicit logout * @tgt: ibmvfc target struct * + * Returns: + * Allocated and initialized ibmvfc_event struct **/ -static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) +static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_target *tgt, + void (*done) (struct ibmvfc_event *)) { struct ibmvfc_implicit_logout *mad; struct ibmvfc_host *vhost = tgt->vhost; struct ibmvfc_event *evt; - if (vhost->discovery_threads >= disc_threads) - return; - kref_get(&tgt->kref); evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); + ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT); evt->tgt = tgt; mad = &evt->iu.implicit_logout; memset(mad, 0, sizeof(*mad)); @@ -3549,6 +3580,25 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT); mad->common.length = cpu_to_be16(sizeof(*mad)); mad->old_scsi_id = cpu_to_be64(tgt->scsi_id); + return evt; +} + +/** + * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target + * @tgt: ibmvfc target struct + * + **/ +static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) +{ + struct ibmvfc_host *vhost = tgt->vhost; + struct ibmvfc_event *evt; + + if (vhost->discovery_threads >= disc_threads) + return; + + vhost->discovery_threads++; + evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt, + ibmvfc_tgt_implicit_logout_done); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); if (ibmvfc_send_event(evt, vhost, default_timeout)) { @@ -3560,6 +3610,53 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) } /** + * ibmvfc_tgt_implicit_logout_and_del_done - Completion handler for Implicit Logout MAD + * @evt: ibmvfc event struct + * + **/ +static void ibmvfc_tgt_implicit_logout_and_del_done(struct ibmvfc_event *evt) +{ + struct ibmvfc_target *tgt = evt->tgt; + struct ibmvfc_host *vhost = evt->vhost; + struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; + u32 status = be16_to_cpu(mad->common.status); + + vhost->discovery_threads--; + ibmvfc_free_event(evt); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + + tgt_dbg(tgt, "Implicit Logout %s\n", (status == IBMVFC_MAD_SUCCESS) ? "succeeded" : "failed"); + kref_put(&tgt->kref, ibmvfc_release_tgt); + wake_up(&vhost->work_wait_q); +} + +/** + * ibmvfc_tgt_implicit_logout_and_del - Initiate an Implicit Logout for specified target + * @tgt: ibmvfc target struct + * + **/ +static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *tgt) +{ + struct ibmvfc_host *vhost = tgt->vhost; + struct ibmvfc_event *evt; + + if (vhost->discovery_threads >= disc_threads) + return; + + vhost->discovery_threads++; + evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt, + ibmvfc_tgt_implicit_logout_and_del_done); + + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT); + if (ibmvfc_send_event(evt, vhost, default_timeout)) { + vhost->discovery_threads--; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + kref_put(&tgt->kref, ibmvfc_release_tgt); + } else + tgt_dbg(tgt, "Sent Implicit Logout\n"); +} + +/** * ibmvfc_adisc_needs_plogi - Does device need PLOGI? * @mad: ibmvfc passthru mad struct * @tgt: ibmvfc target struct @@ -3600,13 +3697,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) case IBMVFC_MAD_SUCCESS: tgt_dbg(tgt, "ADISC succeeded\n"); if (ibmvfc_adisc_needs_plogi(mad, tgt)) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); break; case IBMVFC_MAD_DRIVER_FAILED: break; case IBMVFC_MAD_FAILED: default: - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); fc_reason = (be32_to_cpu(mad->fc_iu.response[1]) & 0x00ff0000) >> 16; fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8; tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", @@ -3799,9 +3896,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) switch (status) { case IBMVFC_MAD_SUCCESS: tgt_dbg(tgt, "Query Target succeeded\n"); - tgt->new_scsi_id = be64_to_cpu(rsp->scsi_id); if (be64_to_cpu(rsp->scsi_id) != tgt->scsi_id) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); + ibmvfc_del_tgt(tgt); else ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); break; @@ -3815,11 +3911,11 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) if ((be16_to_cpu(rsp->status) & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && be16_to_cpu(rsp->error) == IBMVFC_UNABLE_TO_PERFORM_REQ && be16_to_cpu(rsp->fc_explain) == IBMVFC_PORT_NAME_NOT_REG) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_del_tgt(tgt); tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), @@ -3896,7 +3992,6 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); memset(tgt, 0, sizeof(*tgt)); tgt->scsi_id = scsi_id; - tgt->new_scsi_id = scsi_id; tgt->vhost = vhost; tgt->need_login = 1; tgt->cancel_key = vhost->task_set++; @@ -4189,6 +4284,25 @@ static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) } /** + * ibmvfc_dev_logo_to_do - Is there target logout work to do? + * @vhost: ibmvfc host struct + * + * Returns: + * 1 if work to do / 0 if not + **/ +static int ibmvfc_dev_logo_to_do(struct ibmvfc_host *vhost) +{ + struct ibmvfc_target *tgt; + + list_for_each_entry(tgt, &vhost->targets, queue) { + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT || + tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT) + return 1; + } + return 0; +} + +/** * __ibmvfc_work_to_do - Is there task level work to do? (no locking) * @vhost: ibmvfc host struct * @@ -4217,11 +4331,20 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) return 0; return 1; + case IBMVFC_HOST_ACTION_TGT_DEL: + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: + if (vhost->discovery_threads == disc_threads) + return 0; + list_for_each_entry(tgt, &vhost->targets, queue) + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) + return 1; + list_for_each_entry(tgt, &vhost->targets, queue) + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT) + return 0; + return 1; case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_ALLOC_TGTS: - case IBMVFC_HOST_ACTION_TGT_DEL: - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_QUERY: case IBMVFC_HOST_ACTION_RESET: case IBMVFC_HOST_ACTION_REENABLE: @@ -4391,6 +4514,18 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: list_for_each_entry(tgt, &vhost->targets, queue) { + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) { + tgt->job_step(tgt); + break; + } + } + + if (ibmvfc_dev_logo_to_do(vhost)) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return; + } + + list_for_each_entry(tgt, &vhost->targets, queue) { if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { tgt_dbg(tgt, "Deleting rport\n"); rport = tgt->rport; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 7da89f4d26b2..907889f1fa9d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -596,6 +596,8 @@ enum ibmvfc_target_action { IBMVFC_TGT_ACTION_NONE = 0, IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT_WAIT, + IBMVFC_TGT_ACTION_LOGOUT_RPORT, + IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT, IBMVFC_TGT_ACTION_DEL_RPORT, IBMVFC_TGT_ACTION_DELETED_RPORT, }; @@ -604,7 +606,6 @@ struct ibmvfc_target { struct list_head queue; struct ibmvfc_host *vhost; u64 scsi_id; - u64 new_scsi_id; struct fc_rport *rport; int target_id; enum ibmvfc_target_action action; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index cd8db1349871..d48a8fa997b9 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1299,9 +1299,9 @@ static char *__ipr_format_res_path(u8 *res_path, char *buffer, int len) char *p = buffer; *p = '\0'; - p += snprintf(p, buffer + len - p, "%02X", res_path[0]); + p += scnprintf(p, buffer + len - p, "%02X", res_path[0]); for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) - p += snprintf(p, buffer + len - p, "-%02X", res_path[i]); + p += scnprintf(p, buffer + len - p, "-%02X", res_path[i]); return buffer; } @@ -1322,7 +1322,7 @@ static char *ipr_format_res_path(struct ipr_ioa_cfg *ioa_cfg, char *p = buffer; *p = '\0'; - p += snprintf(p, buffer + len - p, "%d/", ioa_cfg->host->host_no); + p += scnprintf(p, buffer + len - p, "%d/", ioa_cfg->host->host_no); __ipr_format_res_path(res_path, p, len - (buffer - p)); return buffer; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index b97aa9ac2ffe..9a0d3d729320 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -451,12 +451,12 @@ struct ipr_config_table_hdr64 { struct ipr_config_table { struct ipr_config_table_hdr hdr; - struct ipr_config_table_entry dev[0]; + struct ipr_config_table_entry dev[]; }__attribute__((packed, aligned (4))); struct ipr_config_table64 { struct ipr_config_table_hdr64 hdr64; - struct ipr_config_table_entry64 dev[0]; + struct ipr_config_table_entry64 dev[]; }__attribute__((packed, aligned (8))); struct ipr_config_table_entry_wrapper { @@ -792,7 +792,7 @@ struct ipr_mode_page28 { struct ipr_mode_page_hdr hdr; u8 num_entries; u8 entry_length; - struct ipr_dev_bus_entry bus[0]; + struct ipr_dev_bus_entry bus[]; }__attribute__((packed)); struct ipr_mode_page24 { diff --git a/drivers/scsi/isci/sas.h b/drivers/scsi/isci/sas.h index dc26b4aea99e..15d8f3631ab7 100644 --- a/drivers/scsi/isci/sas.h +++ b/drivers/scsi/isci/sas.h @@ -201,7 +201,7 @@ struct smp_req { u8 func; /* byte 1 */ u8 alloc_resp_len; /* byte 2 */ u8 req_len; /* byte 3 */ - u8 req_data[0]; + u8 req_data[]; } __packed; /* diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 70b99c0e2e67..874dd4beed10 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2771,7 +2771,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, "must be a power of 2.\n", total_cmds); total_cmds = rounddown_pow_of_two(total_cmds); if (total_cmds < ISCSI_TOTAL_CMDS_MIN) - return NULL; + goto dec_session_count; printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n", total_cmds); } @@ -3153,13 +3153,18 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) switch (flag) { case STOP_CONN_RECOVER: + cls_conn->state = ISCSI_CONN_FAILED; + break; case STOP_CONN_TERM: - iscsi_start_session_recovery(session, conn, flag); + cls_conn->state = ISCSI_CONN_DOWN; break; default: iscsi_conn_printk(KERN_ERR, conn, "invalid stop flag %d\n", flag); + return; } + + iscsi_start_session_recovery(session, conn, flag); } EXPORT_SYMBOL_GPL(iscsi_conn_stop); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 04d73e2be373..357fdec06bae 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -262,7 +262,6 @@ struct lpfc_stats { uint32_t elsRcvPRLI; uint32_t elsRcvLIRR; uint32_t elsRcvRLS; - uint32_t elsRcvRPS; uint32_t elsRcvRPL; uint32_t elsRcvRRQ; uint32_t elsRcvRTV; @@ -749,6 +748,7 @@ struct lpfc_hba { * capability */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ +#define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; @@ -1353,3 +1353,32 @@ lpfc_sli4_mod_hba_eq_delay(struct lpfc_hba *phba, struct lpfc_queue *eq, writel(reg_data.word0, phba->sli4_hba.u.if_type2.EQDregaddr); eq->q_mode = delay; } + + +/* + * Macro that declares tables and a routine to perform enum type to + * ascii string lookup. + * + * Defines a <key,value> table for an enum. Uses xxx_INIT defines for + * the enum to populate the table. Macro defines a routine (named + * by caller) that will search all elements of the table for the key + * and return the name string if found or "Unrecognized" if not found. + */ +#define DECLARE_ENUM2STR_LOOKUP(routine, enum_name, enum_init) \ +static struct { \ + enum enum_name value; \ + char *name; \ +} fc_##enum_name##_e2str_names[] = enum_init; \ +static const char *routine(enum enum_name table_key) \ +{ \ + int i; \ + char *name = "Unrecognized"; \ + \ + for (i = 0; i < ARRAY_SIZE(fc_##enum_name##_e2str_names); i++) {\ + if (fc_##enum_name##_e2str_names[i].value == table_key) {\ + name = fc_##enum_name##_e2str_names[i].name; \ + break; \ + } \ + } \ + return name; \ +} diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 46f56f30f77e..4317c9ce7eca 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -3869,9 +3869,6 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1, /* # lun_queue_depth: This parameter is used to limit the number of outstanding # commands per FCP LUN. Value range is [1,512]. Default value is 30. -# If this parameter value is greater than 1/8th the maximum number of exchanges -# supported by the HBA port, then the lun queue depth will be reduced to -# 1/8th the maximum number of exchanges. */ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512, "Max number of FCP commands we can queue to a specific LUN"); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 25d3dd39bc05..a450477a7e00 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -140,9 +140,10 @@ int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); -int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); +int lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_fabric_reglogin(struct lpfc_vport *); +int lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 58b35a1442c1..2aa578d20f8c 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -2073,8 +2073,8 @@ lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); @@ -2090,8 +2090,8 @@ lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); /* This string MUST be consistent with other FC platforms * supported by Broadcom. @@ -2115,8 +2115,8 @@ lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, phba->SerialNumber, sizeof(ae->un.AttrString)); @@ -2137,8 +2137,8 @@ lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, phba->ModelName, sizeof(ae->un.AttrString)); @@ -2158,8 +2158,8 @@ lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, phba->ModelDesc, sizeof(ae->un.AttrString)); @@ -2181,8 +2181,8 @@ lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t i, j, incr, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); /* Convert JEDEC ID to ascii for hardware version */ incr = vp->rev.biuRev; @@ -2211,8 +2211,8 @@ lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, lpfc_release_version, sizeof(ae->un.AttrString)); @@ -2233,8 +2233,8 @@ lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); if (phba->sli_rev == LPFC_SLI_REV4) lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1); @@ -2258,8 +2258,8 @@ lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1); len = strnlen(ae->un.AttrString, @@ -2278,8 +2278,8 @@ lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s", init_utsname()->sysname, @@ -2301,7 +2301,7 @@ lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE); size = FOURBYTES + sizeof(uint32_t); @@ -2317,8 +2317,8 @@ lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); len = lpfc_vport_symbolic_node_name(vport, ae->un.AttrString, 256); @@ -2336,7 +2336,7 @@ lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; /* Nothing is defined for this currently */ ae->un.AttrInt = cpu_to_be32(0); @@ -2353,7 +2353,7 @@ lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; /* Each driver instance corresponds to a single port */ ae->un.AttrInt = cpu_to_be32(1); @@ -2370,8 +2370,8 @@ lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrWWN, &vport->fabric_nodename, sizeof(struct lpfc_name)); @@ -2389,8 +2389,8 @@ lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strlcat(ae->un.AttrString, phba->BIOSVersion, sizeof(ae->un.AttrString)); @@ -2410,7 +2410,7 @@ lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; /* Driver doesn't have access to this information */ ae->un.AttrInt = cpu_to_be32(0); @@ -2427,8 +2427,8 @@ lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, "EMULEX", sizeof(ae->un.AttrString)); @@ -2450,10 +2450,9 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 32); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ @@ -2476,7 +2475,7 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = 0; if (!(phba->hba_flag & HBA_FCOE_MODE)) { @@ -2530,7 +2529,7 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; if (!(phba->hba_flag & HBA_FCOE_MODE)) { switch (phba->fc_linkspeed) { @@ -2600,7 +2599,7 @@ lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; hsp = (struct serv_parm *)&vport->fc_sparam; ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb & 0x0F) << 8) | @@ -2620,8 +2619,8 @@ lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "/sys/class/scsi_host/host%d", shost->host_no); @@ -2641,8 +2640,8 @@ lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); scnprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s", vport->phba->os_host_name); @@ -2662,8 +2661,8 @@ lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); @@ -2680,8 +2679,8 @@ lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName, sizeof(struct lpfc_name)); @@ -2698,8 +2697,8 @@ lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256); len += (len & 3) ? (4 - (len & 3)) : 4; @@ -2717,7 +2716,7 @@ lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT); else @@ -2735,7 +2734,7 @@ lpfc_fdmi_port_attr_class(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3); size = FOURBYTES + sizeof(uint32_t); ad->AttrLen = cpu_to_be16(size); @@ -2750,8 +2749,8 @@ lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrWWN, &vport->fabric_portname, sizeof(struct lpfc_name)); @@ -2768,10 +2767,9 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 32); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ @@ -2792,7 +2790,7 @@ lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; /* Link Up - operational */ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE); size = FOURBYTES + sizeof(uint32_t); @@ -2808,7 +2806,7 @@ lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; vport->fdmi_num_disc = lpfc_find_map_node(vport); ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc); size = FOURBYTES + sizeof(uint32_t); @@ -2824,7 +2822,7 @@ lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = cpu_to_be32(vport->fc_myDID); size = FOURBYTES + sizeof(uint32_t); ad->AttrLen = cpu_to_be16(size); @@ -2839,8 +2837,8 @@ lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, "Smart SAN Initiator", sizeof(ae->un.AttrString)); @@ -2860,8 +2858,8 @@ lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); @@ -2881,8 +2879,8 @@ lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, "Smart SAN Version 2.0", sizeof(ae->un.AttrString)); @@ -2903,8 +2901,8 @@ lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae = &ad->AttrValue; + memset(ae, 0, sizeof(*ae)); strncpy(ae->un.AttrString, phba->ModelName, sizeof(ae->un.AttrString)); @@ -2923,7 +2921,7 @@ lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; /* SRIOV (type 3) is not supported */ if (vport->vpi) @@ -2943,7 +2941,7 @@ lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = cpu_to_be32(0); size = FOURBYTES + sizeof(uint32_t); ad->AttrLen = cpu_to_be16(size); @@ -2958,7 +2956,7 @@ lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, struct lpfc_fdmi_attr_entry *ae; uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ae = &ad->AttrValue; ae->un.AttrInt = cpu_to_be32(1); size = FOURBYTES + sizeof(uint32_t); ad->AttrLen = cpu_to_be16(size); @@ -3106,7 +3104,8 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Registered Port List */ /* One entry (port) per adapter */ rh->rpl.EntryCnt = cpu_to_be32(1); - memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName, + memcpy(&rh->rpl.pe.PortName, + &phba->pport->fc_sparam.portName, sizeof(struct lpfc_name)); /* point to the HBA attribute block */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 42a2bf38eaea..80d1e661b0d4 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -3008,10 +3008,9 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * This routine is a generic completion callback function for ELS commands. * Specifically, it is the callback function which does not need to perform * any command specific operations. It is currently used by the ELS command - * issuing routines for the ELS State Change Request (SCR), - * lpfc_issue_els_scr(), and the ELS Fibre Channel Address Resolution - * Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). Other than - * certain debug loggings, this callback function simply invokes the + * issuing routines for RSCN, lpfc_issue_els_rscn, and the ELS Fibre Channel + * Address Resolution Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). + * Other than certain debug loggings, this callback function simply invokes the * lpfc_els_chk_latt() routine to check whether link went down during the * discovery process. **/ @@ -3025,14 +3024,117 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "ELS cmd cmpl: status:x%x/x%x did:x%x", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->un.elsreq64.remoteID); + + /* ELS cmd tag <ulpIoTag> completes */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n", + irsp->ulpIoTag, irsp->ulpStatus, + irsp->un.ulpWord[4], irsp->ulpTimeout); + + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(vport); + lpfc_els_free_iocb(phba, cmdiocb); +} + +/** + * lpfc_cmpl_els_disc_cmd - Completion callback function for Discovery ELS cmd + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + * This routine is a generic completion callback function for Discovery ELS cmd. + * Currently used by the ELS command issuing routines for the ELS State Change + * Request (SCR), lpfc_issue_els_scr() and the ELS RDF, lpfc_issue_els_rdf(). + * These commands will be retried once only for ELS timeout errors. + **/ +static void +lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + IOCB_t *irsp; + struct lpfc_els_rdf_rsp *prdf; + struct lpfc_dmabuf *pcmd, *prsp; + u32 *pdata; + u32 cmd; + + irsp = &rspiocb->iocb; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "ELS cmd cmpl: status:x%x/x%x did:x%x", irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.elsreq64.remoteID); /* ELS cmd tag <ulpIoTag> completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n", + "0217 ELS cmd tag x%x completes Data: x%x x%x x%x " + "x%x\n", irsp->ulpIoTag, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout); + irsp->un.ulpWord[4], irsp->ulpTimeout, + cmdiocb->retry); + + pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; + if (!pcmd) + goto out; + + pdata = (u32 *)pcmd->virt; + if (!pdata) + goto out; + cmd = *pdata; + + /* Only 1 retry for ELS Timeout only */ + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT && + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_SEQUENCE_TIMEOUT)) { + cmdiocb->retry++; + if (cmdiocb->retry <= 1) { + switch (cmd) { + case ELS_CMD_SCR: + lpfc_issue_els_scr(vport, cmdiocb->retry); + break; + case ELS_CMD_RDF: + cmdiocb->context1 = NULL; /* save ndlp refcnt */ + lpfc_issue_els_rdf(vport, cmdiocb->retry); + break; + } + goto out; + } + phba->fc_stat.elsRetryExceeded++; + } + if (irsp->ulpStatus) { + /* ELS discovery cmd completes with error */ + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "4203 ELS cmd x%x error: x%x x%X\n", cmd, + irsp->ulpStatus, irsp->un.ulpWord[4]); + goto out; + } + + /* The RDF response doesn't have any impact on the running driver + * but the notification descriptors are dumped here for support. + */ + if (cmd == ELS_CMD_RDF) { + int i; + + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + prdf = (struct lpfc_els_rdf_rsp *)prsp->virt; + if (!prdf) + goto out; + + for (i = 0; i < ELS_RDF_REG_TAG_CNT && + i < be32_to_cpu(prdf->reg_d1.reg_desc.count); i++) + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "4677 Fabric RDF Notification Grant Data: " + "0x%08x\n", + be32_to_cpu( + prdf->reg_d1.desc_tags[i])); + } + +out: /* Check to see if link went down during discovery */ lpfc_els_chk_latt(vport); lpfc_els_free_iocb(phba, cmdiocb); @@ -3042,11 +3144,10 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /** * lpfc_issue_els_scr - Issue a scr to an node on a vport * @vport: pointer to a host virtual N_Port data structure. - * @nportid: N_Port identifier to the remote node. - * @retry: number of retries to the command IOCB. + * @retry: retry counter for the command IOCB. * * This routine issues a State Change Request (SCR) to a fabric node - * on a @vport. The remote node @nportid is passed into the function. It + * on a @vport. The remote node is Fabric Controller (0xfffffd). It * first search the @vport node list to find the matching ndlp. If no such * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() @@ -3062,7 +3163,7 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * 1 - Failed to issue scr command **/ int -lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) +lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; @@ -3072,9 +3173,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) cmdsize = (sizeof(uint32_t) + sizeof(SCR)); - ndlp = lpfc_findnode_did(vport, nportid); + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); if (!ndlp) { - ndlp = lpfc_nlp_init(vport, nportid); + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); @@ -3109,7 +3210,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) ndlp->nlp_DID, 0, 0); phba->fc_stat.elsXmitSCR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; + elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following @@ -3339,6 +3440,102 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) /* This will cause the callback-function lpfc_cmpl_els_cmd to * trigger the release of the node. */ + /* Don't release reference count as RDF is likely outstanding */ + return 0; +} + +/** + * lpfc_issue_els_rdf - Register for diagnostic functions from the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command IOCB. + * + * This routine issues an ELS RDF to the Fabric Controller to register + * for diagnostic functions. + * + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp + * will be incremented by 1 for holding the ndlp and the reference to ndlp + * will be stored into the context1 field of the IOCB for the completion + * callback function to the RDF ELS command. + * + * Return code + * 0 - Successfully issued rdf command + * 1 - Failed to issue rdf command + **/ +int +lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_els_rdf_req *prdf; + struct lpfc_nodelist *ndlp; + uint16_t cmdsize; + + cmdsize = sizeof(*prdf); + + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); + if (!ndlp) { + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); + if (!ndlp) + return -ENODEV; + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return -ENODEV; + } + + /* RDF ELS is not required on an NPIV VN_Port. */ + if (vport->port_type == LPFC_NPIV_PORT) { + lpfc_nlp_put(ndlp); + return -EACCES; + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_RDF); + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + return -ENOMEM; + } + + /* Configure the payload for the supported FPIN events. */ + prdf = (struct lpfc_els_rdf_req *) + (((struct lpfc_dmabuf *)elsiocb->context2)->virt); + memset(prdf, 0, cmdsize); + prdf->rdf.fpin_cmd = ELS_RDF; + prdf->rdf.desc_len = cpu_to_be32(sizeof(struct lpfc_els_rdf_req) - + sizeof(struct fc_els_rdf)); + prdf->reg_d1.reg_desc.desc_tag = cpu_to_be32(ELS_DTAG_FPIN_REGISTER); + prdf->reg_d1.reg_desc.desc_len = cpu_to_be32( + FC_TLV_DESC_LENGTH_FROM_SZ(prdf->reg_d1)); + prdf->reg_d1.reg_desc.count = cpu_to_be32(ELS_RDF_REG_TAG_CNT); + prdf->reg_d1.desc_tags[0] = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RDF: did:x%x", + ndlp->nlp_DID, 0, 0); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6444 Xmit RDF to remote NPORT x%x\n", + ndlp->nlp_DID); + + elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; + } + + /* An RDF was issued - this put ensures the ndlp is cleaned up + * when the RDF completes. + */ lpfc_nlp_put(ndlp); return 0; } @@ -7135,108 +7332,12 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } /** - * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for the MBX_READ_LNK_STAT - * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It - * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics - * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - **/ -static void -lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - IOCB_t *icmd; - RPS_RSP *rps_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint16_t status; - uint16_t oxid; - uint16_t rxid; - uint32_t cmdsize; - - mb = &pmb->u.mb; - - ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff); - oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff); - pmb->ctx_ndlp = NULL; - pmb->ctx_buf = NULL; - - if (mb->mbxStatus) { - mempool_free(pmb, phba->mbox_mem_pool); - return; - } - - cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - /* Decrement the ndlp reference count from previous mbox command */ - lpfc_nlp_put(ndlp); - - if (!elsiocb) - return; - - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - rps_rsp = (RPS_RSP *)pcmd; - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) - status = 0x10; - else - status = 0x8; - if (phba->pport->fc_flag & FC_FABRIC) - status |= 0x4; - - rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = cpu_to_be16(status); - rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - /* Xmit ELS RPS ACC response tag <ulpIoTag> */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); - return; -} - -/** * lpfc_els_rcv_rls - Process an unsolicited rls iocb * @vport: pointer to a host virtual N_Port data structure. * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Port Status (RPL) IOCB received as an + * This routine processes Read Link Status (RLS) IOCB received as an * ELS unsolicited event. It first checks the remote port state. If the * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE * state, it invokes the lpfc_els_rsl_reject() routine to send the reject @@ -7258,7 +7359,7 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RLS request and done with it */ goto reject_out; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); @@ -7306,7 +7407,7 @@ reject_out: * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp * will be incremented by 1 for holding the ndlp and the reference to ndlp * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. + * callback function to the RTV Accept Response ELS IOCB command. * * Return codes * 0 - Successfully processed rtv iocb (currently always return 0) @@ -7325,7 +7426,7 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RTV request and done with it */ goto reject_out; cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); @@ -7378,84 +7479,7 @@ reject_out: return 0; } -/* lpfc_els_rcv_rps - Process an unsolicited rps iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port Status (RPS) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsp_reject() routine to send the reject - * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command - * for reading the HBA link statistics. It is for the callback function, - * lpfc_els_rsp_rps_acc(), set to the MBX_READ_LNK_STAT mailbox command - * to actually sending out RPS Accept (ACC) response. - * - * Return codes - * 0 - Successfully processed rps iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t *lp; - uint8_t flag; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; - RPS *rps; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - flag = (be32_to_cpu(*lp++) & 0xf); - rps = (RPS *) lp; - - if ((flag == 0) || - ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) || - ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname, - sizeof(struct lpfc_name)) == 0))) { - - printk("Fix me....\n"); - dump_stack(); - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); - if (mbox) { - lpfc_read_lnk_stat(phba, mbox); - mbox->ctx_buf = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - /* Mbox completion will send ELS Response */ - return 0; - /* Decrement reference count used for the failed mbox - * command. - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - } - } - -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/* lpfc_issue_els_rrq - Process an unsolicited rps iocb +/* lpfc_issue_els_rrq - Process an unsolicited rrq iocb * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. * @did: DID of the target. @@ -8310,6 +8334,90 @@ lpfc_send_els_event(struct lpfc_vport *vport, } +DECLARE_ENUM2STR_LOOKUP(lpfc_get_tlv_dtag_nm, fc_ls_tlv_dtag, + FC_LS_TLV_DTAG_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_li_event_nm, fc_fpin_li_event_types, + FC_FPIN_LI_EVT_TYPES_INIT); + +/** + * lpfc_els_rcv_fpin_li - Process an FPIN Link Integrity Event. + * @vport: Pointer to vport object. + * @lnk_not: Pointer to the Link Integrity Notification Descriptor. + * + * This function processes a link integrity FPIN event by + * logging a message + **/ +static void +lpfc_els_rcv_fpin_li(struct lpfc_vport *vport, struct fc_tlv_desc *tlv) +{ + struct fc_fn_li_desc *li = (struct fc_fn_li_desc *)tlv; + const char *li_evt_str; + u32 li_evt; + + li_evt = be16_to_cpu(li->event_type); + li_evt_str = lpfc_get_fpin_li_event_nm(li_evt); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "4680 FPIN Link Integrity %s (x%x) " + "Detecting PN x%016llx Attached PN x%016llx " + "Duration %d mSecs Count %d Port Cnt %d\n", + li_evt_str, li_evt, + be64_to_cpu(li->detecting_wwpn), + be64_to_cpu(li->attached_wwpn), + be32_to_cpu(li->event_threshold), + be32_to_cpu(li->event_count), + be32_to_cpu(li->pname_count)); +} + +static void +lpfc_els_rcv_fpin(struct lpfc_vport *vport, struct fc_els_fpin *fpin, + u32 fpin_length) +{ + struct fc_tlv_desc *tlv; + const char *dtag_nm; + uint32_t desc_cnt = 0, bytes_remain; + u32 dtag; + + /* FPINs handled only if we are in the right discovery state */ + if (vport->port_state < LPFC_DISC_AUTH) + return; + + /* make sure there is the full fpin header */ + if (fpin_length < sizeof(struct fc_els_fpin)) + return; + + tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0]; + bytes_remain = fpin_length - offsetof(struct fc_els_fpin, fpin_desc); + bytes_remain = min_t(u32, bytes_remain, be32_to_cpu(fpin->desc_len)); + + /* process each descriptor */ + while (bytes_remain >= FC_TLV_DESC_HDR_SZ && + bytes_remain >= FC_TLV_DESC_SZ_FROM_LENGTH(tlv)) { + + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + lpfc_els_rcv_fpin_li(vport, tlv); + break; + default: + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "4678 skipped FPIN descriptor[%d]: " + "tag x%x (%s)\n", + desc_cnt, dtag, dtag_nm); + break; + } + + desc_cnt++; + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + } + + fc_host_fpin_rcv(lpfc_shost_from_vport(vport), fpin_length, + (char *)fpin); +} + /** * lpfc_els_unsol_buffer - Process an unsolicited event data buffer * @phba: pointer to lpfc hba data structure. @@ -8331,7 +8439,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; - uint32_t *payload; + uint32_t *payload, payload_len; uint32_t cmd, did, newnode; uint8_t rjt_exp, rjt_err = 0, init_link = 0; IOCB_t *icmd = &elsiocb->iocb; @@ -8342,6 +8450,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, newnode = 0; payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + payload_len = elsiocb->iocb.unsli3.rcvsli3.acc_len; cmd = *payload; if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) lpfc_post_buffer(phba, pring, 1); @@ -8632,16 +8741,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (newnode) lpfc_nlp_put(ndlp); break; - case ELS_CMD_RPS: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPS: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRPS++; - lpfc_els_rcv_rps(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV RPL: did:x%x/ste:x%x flg:x%x", @@ -8697,12 +8796,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_INVALID_OX_RX; break; case ELS_CMD_FPIN: - /* - * Received FPIN from fabric - pass it to the - * transport FPIN handler. - */ - fc_host_fpin_rcv(shost, elsiocb->iocb.unsli3.rcvsli3.acc_len, - (char *)payload); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV FPIN: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + lpfc_els_rcv_fpin(vport, (struct fc_els_fpin *)payload, + payload_len); + + /* There are no replies, so no rjt codes */ break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dcc8999c6a68..789eecbf32eb 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1163,13 +1163,16 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } /* Start discovery by sending a FLOGI. port_state is identically - * LPFC_FLOGI while waiting for FLOGI cmpl + * LPFC_FLOGI while waiting for FLOGI cmpl. Check if sending + * the FLOGI is being deferred till after MBX_READ_SPARAM completes. */ - if (vport->port_state != LPFC_FLOGI) - lpfc_initial_flogi(vport); - else if (vport->fc_flag & FC_PT2PT) - lpfc_disc_start(vport); - + if (vport->port_state != LPFC_FLOGI) { + if (!(phba->hba_flag & HBA_DEFER_FLOGI)) + lpfc_initial_flogi(vport); + } else { + if (vport->fc_flag & FC_PT2PT) + lpfc_disc_start(vport); + } return; out: @@ -3094,6 +3097,14 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); + + /* Check if sending the FLOGI is being deferred to after we get + * up to date CSPs from MBX_READ_SPARAM. + */ + if (phba->hba_flag & HBA_DEFER_FLOGI) { + lpfc_initial_flogi(vport); + phba->hba_flag &= ~HBA_DEFER_FLOGI; + } return; out: @@ -3224,6 +3235,23 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } lpfc_linkup(phba); + sparam_mbox = NULL; + + if (!(phba->hba_flag & HBA_FCOE_MODE)) { + cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!cfglink_mbox) + goto out; + vport->port_state = LPFC_LOCAL_CFG_LINK; + lpfc_config_link(phba, cfglink_mbox); + cfglink_mbox->vport = vport; + cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; + rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(cfglink_mbox, phba->mbox_mem_pool); + goto out; + } + } + sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!sparam_mbox) goto out; @@ -3244,20 +3272,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) goto out; } - if (!(phba->hba_flag & HBA_FCOE_MODE)) { - cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!cfglink_mbox) - goto out; - vport->port_state = LPFC_LOCAL_CFG_LINK; - lpfc_config_link(phba, cfglink_mbox); - cfglink_mbox->vport = vport; - cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(cfglink_mbox, phba->mbox_mem_pool); - goto out; - } - } else { + if (phba->hba_flag & HBA_FCOE_MODE) { vport->port_state = LPFC_VPORT_UNKNOWN; /* * Add the driver's default FCF record at FCF index 0 now. This @@ -3314,6 +3329,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } /* Reset FCF roundrobin bmask for new discovery */ lpfc_sli4_clear_fcf_rr_bmask(phba); + } else { + if (phba->bbcredit_support && phba->cfg_enable_bbcr && + !(phba->link_flag & LS_LOOPBACK_MODE)) + phba->hba_flag |= HBA_DEFER_FLOGI; } /* Prepare for LINK up registrations */ @@ -4070,7 +4089,9 @@ out: FC_TYPE_NVME); /* Issue SCR just before NameServer GID_FT Query */ - lpfc_issue_els_scr(vport, SCR_DID, 0); + lpfc_issue_els_scr(vport, 0); + + lpfc_issue_els_rdf(vport, 0); } vport->fc_ns_retry = 0; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 436cdc8c5ef4..ae51c0dbba0a 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -22,7 +22,7 @@ #define FDMI_DID 0xfffffaU #define NameServer_DID 0xfffffcU -#define SCR_DID 0xfffffdU +#define Fabric_Cntl_DID 0xfffffdU #define Fabric_DID 0xfffffeU #define Bcast_DID 0xffffffU #define Mask_DID 0xffffffU @@ -588,6 +588,7 @@ struct fc_vft_header { #define ELS_CMD_RRQ 0x12000000 #define ELS_CMD_REC 0x13000000 #define ELS_CMD_RDP 0x18000000 +#define ELS_CMD_RDF 0x19000000 #define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_NVMEPRLI 0x20140018 #define ELS_CMD_PRLO 0x21100014 @@ -597,7 +598,6 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52000000 #define ELS_CMD_FARP 0x54000000 #define ELS_CMD_FARPR 0x55000000 -#define ELS_CMD_RPS 0x56000000 #define ELS_CMD_RPL 0x57000000 #define ELS_CMD_FAN 0x60000000 #define ELS_CMD_RSCN 0x61040000 @@ -630,6 +630,7 @@ struct fc_vft_header { #define ELS_CMD_RRQ 0x12 #define ELS_CMD_REC 0x13 #define ELS_CMD_RDP 0x18 +#define ELS_CMD_RDF 0x19 #define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_NVMEPRLI 0x18001420 #define ELS_CMD_PRLO 0x14001021 @@ -639,7 +640,6 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52 #define ELS_CMD_FARP 0x54 #define ELS_CMD_FARPR 0x55 -#define ELS_CMD_RPS 0x56 #define ELS_CMD_RPL 0x57 #define ELS_CMD_FAN 0x60 #define ELS_CMD_RSCN 0x0461 @@ -919,24 +919,6 @@ typedef struct _RNID { /* Structure is in Big Endian format */ } un; } __packed RNID; -typedef struct _RPS { /* Structure is in Big Endian format */ - union { - uint32_t portNum; - struct lpfc_name portName; - } un; -} RPS; - -typedef struct _RPS_RSP { /* Structure is in Big Endian format */ - uint16_t rsvd1; - uint16_t portStatus; - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; -} RPS_RSP; - struct RLS { /* Structure is in Big Endian format */ uint32_t rls; #define rls_rsvd_SHIFT 24 @@ -1340,25 +1322,8 @@ struct fc_rdp_res_frame { /* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */ #define SLI_CT_FDMI_Subtypes 0x10 /* Management Service Subtype */ -/* - * Registered Port List Format - */ -struct lpfc_fdmi_reg_port_list { - uint32_t EntryCnt; - uint32_t pe; /* Variable-length array */ -}; - - /* Definitions for HBA / Port attribute entries */ -struct lpfc_fdmi_attr_def { /* Defined in TLV format */ - /* Structure is in Big Endian format */ - uint32_t AttrType:16; - uint32_t AttrLen:16; - uint32_t AttrValue; /* Marks start of Value (ATTRIBUTE_ENTRY) */ -}; - - /* Attribute Entry */ struct lpfc_fdmi_attr_entry { union { @@ -1369,7 +1334,13 @@ struct lpfc_fdmi_attr_entry { } un; }; -#define LPFC_FDMI_MAX_AE_SIZE sizeof(struct lpfc_fdmi_attr_entry) +struct lpfc_fdmi_attr_def { /* Defined in TLV format */ + /* Structure is in Big Endian format */ + uint32_t AttrType:16; + uint32_t AttrLen:16; + /* Marks start of Value (ATTRIBUTE_ENTRY) */ + struct lpfc_fdmi_attr_entry AttrValue; +} __packed; /* * HBA Attribute Block @@ -1394,12 +1365,19 @@ struct lpfc_fdmi_hba_ident { }; /* + * Registered Port List Format + */ +struct lpfc_fdmi_reg_port_list { + uint32_t EntryCnt; + struct lpfc_fdmi_port_entry pe; +} __packed; + +/* * Register HBA(RHBA) */ struct lpfc_fdmi_reg_hba { struct lpfc_fdmi_hba_ident hi; - struct lpfc_fdmi_reg_port_list rpl; /* variable-length array */ -/* struct lpfc_fdmi_attr_block ab; */ + struct lpfc_fdmi_reg_port_list rpl; }; /* diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 9a064b96e570..10c5d1c3122e 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -20,6 +20,8 @@ * included with this package. * *******************************************************************/ +#include <uapi/scsi/fc/fc_els.h> + /* Macros to deal with bit fields. Each bit field must have 3 #defines * associated with it (_SHIFT, _MASK, and _WORD). * EG. For a bit field that is in the 7th bit of the "field4" field of a @@ -4795,6 +4797,23 @@ struct send_frame_wqe { uint32_t fc_hdr_wd5; /* word 15 */ }; +#define ELS_RDF_REG_TAG_CNT 1 +struct lpfc_els_rdf_reg_desc { + struct fc_df_desc_fpin_reg reg_desc; /* descriptor header */ + __be32 desc_tags[ELS_RDF_REG_TAG_CNT]; + /* tags in reg_desc */ +}; + +struct lpfc_els_rdf_req { + struct fc_els_rdf rdf; /* hdr up to descriptors */ + struct lpfc_els_rdf_reg_desc reg_d1; /* 1st descriptor */ +}; + +struct lpfc_els_rdf_rsp { + struct fc_els_rdf_resp rdf_resp; /* hdr up to descriptors */ + struct lpfc_els_rdf_reg_desc reg_d1; /* 1st descriptor */ +}; + union lpfc_wqe { uint32_t words[16]; struct lpfc_wqe_generic generic; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5a605773dd0a..9d03e9b71efb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -512,21 +512,12 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_sli_read_link_ste(phba); /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - i = (mb->un.varRdConfig.max_xri + 1); - if (phba->cfg_hba_queue_depth > i) { + if (phba->cfg_hba_queue_depth > mb->un.varRdConfig.max_xri) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "3359 HBA queue depth changed from %d to %d\n", - phba->cfg_hba_queue_depth, i); - phba->cfg_hba_queue_depth = i; - } - - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - i = (mb->un.varRdConfig.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > i) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3360 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, i); - phba->pport->cfg_lun_queue_depth = i; + phba->cfg_hba_queue_depth, + mb->un.varRdConfig.max_xri); + phba->cfg_hba_queue_depth = mb->un.varRdConfig.max_xri; } phba->lmt = mb->un.varRdConfig.lmt; @@ -9235,6 +9226,7 @@ lpfc_sli4_release_hdwq(struct lpfc_hba *phba) /* Free the CQ/WQ corresponding to the Hardware Queue */ lpfc_sli4_queue_free(hdwq[idx].io_cq); lpfc_sli4_queue_free(hdwq[idx].io_wq); + hdwq[idx].hba_eq = NULL; hdwq[idx].io_cq = NULL; hdwq[idx].io_wq = NULL; if (phba->cfg_xpsgl && !phba->nvmet_support) @@ -11105,15 +11097,19 @@ found_any: * @cpu: cpu going offline * @eqlist: */ -static void +static int lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, struct list_head *eqlist) { const struct cpumask *maskp; struct lpfc_queue *eq; - cpumask_t tmp; + struct cpumask *tmp; u16 idx; + tmp = kzalloc(cpumask_size(), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { maskp = pci_irq_get_affinity(phba->pcidev, idx); if (!maskp) @@ -11123,7 +11119,7 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * then we don't need to poll the eq attached * to it. */ - if (!cpumask_and(&tmp, maskp, cpumask_of(cpu))) + if (!cpumask_and(tmp, maskp, cpumask_of(cpu))) continue; /* get the cpus that are online and are affini- * tized to this irq vector. If the count is @@ -11131,8 +11127,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * down this vector. Since this cpu has not * gone offline yet, we need >1. */ - cpumask_and(&tmp, maskp, cpu_online_mask); - if (cpumask_weight(&tmp) > 1) + cpumask_and(tmp, maskp, cpu_online_mask); + if (cpumask_weight(tmp) > 1) continue; /* Now that we have an irq to shutdown, get the eq @@ -11143,6 +11139,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, eq = phba->sli4_hba.hba_eq_hdl[idx].eq; list_add(&eq->_poll_list, eqlist); } + kfree(tmp); + return 0; } static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) @@ -11313,7 +11311,9 @@ static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) lpfc_irq_rebalance(phba, cpu, true); - lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + retval = lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + if (retval) + return retval; /* start polling on these eq's */ list_for_each_entry_safe(eq, next, &eqlist, _poll_list) { diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2c7e0b22db2f..0fc9a242bc65 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -671,8 +671,10 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, lpfc_cmd->prot_data_type = 0; #endif tmp = lpfc_get_cmd_rsp_buf_per_hdwq(phba, lpfc_cmd); - if (!tmp) + if (!tmp) { + lpfc_release_io_buf(phba, lpfc_cmd, lpfc_cmd->hdwq); return NULL; + } lpfc_cmd->fcp_cmnd = tmp->fcp_cmnd; lpfc_cmd->fcp_rsp = tmp->fcp_rsp; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 64002b0cb02d..0b26b5c0527e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -7371,15 +7371,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3362 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, rc); - phba->pport->cfg_lun_queue_depth = rc; - } - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_0) { lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY); @@ -9468,6 +9459,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_RDF || *pcmd == ELS_CMD_RSCN_XMT || *pcmd == ELS_CMD_FDISC || *pcmd == ELS_CMD_LOGO || @@ -17950,6 +17942,10 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) list_add_tail(&iocbq->list, &first_iocbq->list); } } + /* Free the sequence's header buffer */ + if (!first_iocbq) + lpfc_in_buf_free(vport->phba, &seq_dmabuf->dbuf); + return first_iocbq; } diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 9563c49f36ab..c4ab006e6ecc 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.6.0.3" +#define LPFC_DRIVER_VERSION "12.6.0.4" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index fd4b5ac6ac5b..babe85d7b537 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2987,9 +2987,10 @@ megasas_dump_sys_regs(void __iomem *reg_set, char *buf) u32 __iomem *reg = (u32 __iomem *)reg_set; for (i = 0; i < sz / sizeof(u32); i++) { - bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE, - "%08x: %08x\n", (i * 4), - readl(®[i])); + bytes_wrote += scnprintf(loc + bytes_wrote, + PAGE_SIZE - bytes_wrote, + "%08x: %08x\n", (i * 4), + readl(®[i])); } return bytes_wrote; } @@ -8224,8 +8225,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, "return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n", __func__, __LINE__, cmd->frame->hdr.cmd, opcode, cmd->cmd_status_drv); - error = -EBUSY; - goto out; + error = -EBUSY; + goto out; } cmd->sync_cmd = 0; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index c597d544eb39..778d5e6ce385 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -207,7 +207,7 @@ struct fw_event_work { u8 ignore; u16 event; struct kref refcount; - char event_data[0] __aligned(4); + char event_data[] __aligned(4); }; static void fw_event_work_free(struct kref *r) diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 519edc796691..327fdd5ee962 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -394,7 +394,7 @@ struct mvs_info { dma_addr_t bulk_buffer_dma1; #define TRASH_BUCKET_SIZE 0x20000 void *dma_pool; - struct mvs_slot_info slot_info[0]; + struct mvs_slot_info slot_info[]; }; struct mvs_prv_info{ diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h index ec8cc2207536..60d5691fc4ab 100644 --- a/drivers/scsi/mvumi.h +++ b/drivers/scsi/mvumi.h @@ -130,7 +130,7 @@ enum { struct mvumi_hotplug_event { u16 size; u8 dummy[2]; - u8 bitmap[0]; + u8 bitmap[]; }; struct mvumi_driver_event { @@ -290,7 +290,7 @@ struct mvumi_rsp_frame { struct mvumi_ob_data { struct list_head list; - unsigned char data[0]; + unsigned char data[]; }; struct version_info { diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 11a2cb844ecb..f88adab3f913 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -2203,7 +2203,7 @@ static struct script script0 __initdata = { ** Possible data corruption during Memory Write and Invalidate. ** This work-around resets the addressing logic prior to the ** start of the first MOVE of a DATA IN phase. - ** (See Documentation/scsi/ncr53c8xx.txt for more information) + ** (See Documentation/scsi/ncr53c8xx.rst for more information) */ SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), 20, diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index dc9b74c9348a..9696b6b5591f 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -36,7 +36,7 @@ config PCMCIA_NINJA_SCSI help If you intend to attach this type of PCMCIA SCSI host adapter to your computer, say Y here and read - <file:Documentation/scsi/NinjaSCSI.txt>. + <file:Documentation/scsi/NinjaSCSI.rst>. Supported cards: diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 7c6be2ec110d..3c9f42779dd0 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -463,7 +463,7 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, pm8001_ha->nvmd_completion = &completion; payload.minor_function = 7; payload.offset = 0; - payload.length = 4096; + payload.rd_length = 4096; payload.func_specific = kzalloc(4096, GFP_KERNEL); if (!payload.func_specific) return -ENOMEM; @@ -554,6 +554,49 @@ static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); +/** + ** non_fatal_log_show - non fatal error logging + ** @cdev:pointer to embedded class device + ** @buf: the buffer returned + ** + ** A sysfs 'read-only' shost attribute. + **/ +static ssize_t non_fatal_log_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + u32 count; + + count = pm80xx_get_non_fatal_dump(cdev, attr, buf); + return count; +} +static DEVICE_ATTR_RO(non_fatal_log); + +static ssize_t non_fatal_count_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + + return snprintf(buf, PAGE_SIZE, "%08x", + pm8001_ha->non_fatal_count); +} + +static ssize_t non_fatal_count_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + int val = 0; + + if (kstrtoint(buf, 16, &val) != 0) + return -EINVAL; + + pm8001_ha->non_fatal_count = val; + return strlen(buf); +} +static DEVICE_ATTR_RW(non_fatal_count); /** ** pm8001_ctl_gsm_log_show - gsm dump collection @@ -631,7 +674,7 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) payload = (struct pm8001_ioctl_payload *)ioctlbuffer; memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, pm8001_ha->fw_image->size); - payload->length = pm8001_ha->fw_image->size; + payload->wr_length = pm8001_ha->fw_image->size; payload->id = 0; payload->minor_function = 0x1; pm8001_ha->nvmd_completion = &completion; @@ -677,7 +720,7 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) IOCTL_BUF_SIZE); for (loopNumber = 0; loopNumber < loopcount; loopNumber++) { payload = (struct pm8001_ioctl_payload *)ioctlbuffer; - payload->length = 1024*16; + payload->wr_length = 1024*16; payload->id = 0; fwControl = (struct fw_control_info *)&payload->func_specific; @@ -829,6 +872,8 @@ struct device_attribute *pm8001_host_attrs[] = { &dev_attr_aap_log, &dev_attr_iop_log, &dev_attr_fatal_log, + &dev_attr_non_fatal_log, + &dev_attr_non_fatal_count, &dev_attr_gsm_log, &dev_attr_max_out_io, &dev_attr_max_devices, diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 48e0624ecc68..1c7f15fd69ce 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -75,7 +75,7 @@ enum port_type { }; /* driver compile-time configuration */ -#define PM8001_MAX_CCB 512 /* max ccbs supported */ +#define PM8001_MAX_CCB 256 /* max ccbs supported */ #define PM8001_MPI_QUEUE 1024 /* maximum mpi queue entries */ #define PM8001_MAX_INB_NUM 1 #define PM8001_MAX_OUTB_NUM 1 @@ -99,7 +99,8 @@ enum port_type { #define OB (CI + PM8001_MAX_SPCV_INB_NUM) #define PI (OB + PM8001_MAX_SPCV_OUTB_NUM) #define USI_MAX_MEMCNT (PI + PM8001_MAX_SPCV_OUTB_NUM) -#define PM8001_MAX_DMA_SG SG_ALL +#define CONFIG_SCSI_PM8001_MAX_DMA_SG 528 +#define PM8001_MAX_DMA_SG CONFIG_SCSI_PM8001_MAX_DMA_SG 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 2328ff1349ac..fb9848e1d481 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4793,7 +4793,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, if (!fw_control_context) return -ENOMEM; fw_control_context->usrAddr = (u8 *)ioctl_payload->func_specific; - fw_control_context->len = ioctl_payload->length; + fw_control_context->len = ioctl_payload->rd_length; circularQ = &pm8001_ha->inbnd_q_tbl[0]; memset(&nvmd_req, 0, sizeof(nvmd_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); @@ -4814,7 +4814,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 | twi_page_size << 8 | TWI_DEVICE); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); nvmd_req.resp_addr_lo = @@ -4823,7 +4823,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, } case C_SEEPROM: { nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); nvmd_req.resp_addr_lo = @@ -4832,7 +4832,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, } case VPD_FLASH: { nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); nvmd_req.resp_addr_lo = @@ -4841,7 +4841,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, } case EXPAN_ROM: { nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); nvmd_req.resp_addr_lo = @@ -4850,7 +4850,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, } case IOP_RDUMP: { nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | IOP_RDUMP); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length); nvmd_req.vpd_offset = cpu_to_le32(ioctl_payload->offset); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); @@ -4890,7 +4890,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, circularQ = &pm8001_ha->inbnd_q_tbl[0]; memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr, &ioctl_payload->func_specific, - ioctl_payload->length); + ioctl_payload->wr_length); memset(&nvmd_req, 0, sizeof(nvmd_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); if (rc) { @@ -4909,7 +4909,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 | twi_page_size << 8 | TWI_DEVICE); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); nvmd_req.resp_addr_lo = @@ -4918,7 +4918,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, } case C_SEEPROM: nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length); nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); @@ -4927,7 +4927,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, break; case VPD_FLASH: nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length); nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); @@ -4936,7 +4936,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, break; case EXPAN_ROM: nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); + nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length); nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); nvmd_req.resp_addr_hi = cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 3c6076e4c6d2..a8f5344fdfda 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -95,7 +95,7 @@ static struct scsi_host_template pm8001_sht = { .bios_param = sas_bios_param, .can_queue = 1, .this_id = -1, - .sg_tablesize = SG_ALL, + .sg_tablesize = PM8001_MAX_DMA_SG, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, @@ -251,6 +251,9 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) return ret; } +static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha); +static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha); + /** * pm8001_alloc - initiate our hba structure and 6 DMAs area. * @pm8001_ha:our hba structure. @@ -483,6 +486,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->non_fatal_count = 0; if (link_rate >= 1 && link_rate <= 15) pm8001_ha->link_rate = (link_rate << 8); else { @@ -635,22 +639,22 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) if (pm8001_ha->chip_id == chip_8001) { if (deviceid == 0x8081 || deviceid == 0x0042) { payload.minor_function = 4; - payload.length = 4096; + payload.rd_length = 4096; } else { payload.minor_function = 0; - payload.length = 128; + payload.rd_length = 128; } } else if ((pm8001_ha->chip_id == chip_8070 || pm8001_ha->chip_id == chip_8072) && pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { payload.minor_function = 4; - payload.length = 4096; + payload.rd_length = 4096; } else { payload.minor_function = 1; - payload.length = 4096; + payload.rd_length = 4096; } payload.offset = 0; - payload.func_specific = kzalloc(payload.length, GFP_KERNEL); + payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL); if (!payload.func_specific) { PM8001_INIT_DBG(pm8001_ha, pm8001_printk("mem alloc fail\n")); return; @@ -720,7 +724,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) /* SAS ADDRESS read from flash / EEPROM */ payload.minor_function = 6; payload.offset = 0; - payload.length = 4096; + payload.rd_length = 4096; payload.func_specific = kzalloc(4096, GFP_KERNEL); if (!payload.func_specific) return -ENOMEM; @@ -893,9 +897,7 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) */ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) { - u32 i = 0, j = 0; u32 number_of_intr; - int flag = 0; int rc; /* SPCv controllers supports 64 msi-x */ @@ -903,11 +905,11 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) number_of_intr = 1; } else { number_of_intr = PM8001_MAX_MSIX_VEC; - flag &= ~IRQF_SHARED; } rc = pci_alloc_irq_vectors(pm8001_ha->pdev, number_of_intr, number_of_intr, PCI_IRQ_MSIX); + number_of_intr = rc; if (rc < 0) return rc; pm8001_ha->number_of_intr = number_of_intr; @@ -915,8 +917,22 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) PM8001_INIT_DBG(pm8001_ha, pm8001_printk( "pci_alloc_irq_vectors request ret:%d no of intr %d\n", rc, pm8001_ha->number_of_intr)); + return 0; +} - for (i = 0; i < number_of_intr; i++) { +static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) +{ + u32 i = 0, j = 0; + int flag = 0, rc = 0; + + if (pm8001_ha->chip_id != chip_8001) + flag &= ~IRQF_SHARED; + + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("pci_enable_msix request number of intr %d\n", + pm8001_ha->number_of_intr)); + + for (i = 0; i < pm8001_ha->number_of_intr; i++) { snprintf(pm8001_ha->intr_drvname[i], sizeof(pm8001_ha->intr_drvname[0]), "%s-%d", pm8001_ha->name, i); @@ -941,6 +957,21 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) } #endif +static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha) +{ + struct pci_dev *pdev; + + pdev = pm8001_ha->pdev; + +#ifdef PM8001_USE_MSIX + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) + return pm8001_setup_msix(pm8001_ha); + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("MSIX not supported!!!\n")); +#endif + return 0; +} + /** * pm8001_request_irq - register interrupt * @chip_info: our ha struct. @@ -954,7 +985,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) #ifdef PM8001_USE_MSIX if (pdev->msix_cap && pci_msi_enabled()) - return pm8001_setup_msix(pm8001_ha); + return pm8001_request_msix(pm8001_ha); else { PM8001_INIT_DBG(pm8001_ha, pm8001_printk("MSIX not supported!!!\n")); @@ -989,6 +1020,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, struct pm8001_hba_info *pm8001_ha; struct Scsi_Host *shost = NULL; const struct pm8001_chip_info *chip; + struct sas_ha_struct *sha; dev_printk(KERN_INFO, &pdev->dev, "pm80xx: driver version %s\n", DRV_VERSION); @@ -1017,12 +1049,12 @@ static int pm8001_pci_probe(struct pci_dev *pdev, goto err_out_regions; } chip = &pm8001_chips[ent->driver_data]; - SHOST_TO_SAS_HA(shost) = - kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); - if (!SHOST_TO_SAS_HA(shost)) { + sha = kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); + if (!sha) { rc = -ENOMEM; goto err_out_free_host; } + SHOST_TO_SAS_HA(shost) = sha; rc = pm8001_prep_sas_ha_init(shost, chip); if (rc) { @@ -1036,7 +1068,14 @@ static int pm8001_pci_probe(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_free; } - list_add_tail(&pm8001_ha->list, &hba_list); + /* Setup Interrupt */ + rc = pm8001_setup_irq(pm8001_ha); + if (rc) { + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "pm8001_setup_irq failed [ret: %d]\n", rc)); + goto err_out_shost; + } + PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); if (rc) { @@ -1048,6 +1087,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, rc = scsi_add_host(shost, &pdev->dev); if (rc) goto err_out_ha_free; + /* Request Interrupt */ rc = pm8001_request_irq(pm8001_ha); if (rc) { PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( @@ -1070,8 +1110,12 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm8001_post_sas_ha_init(shost, chip); rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); - if (rc) + if (rc) { + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "sas_register_ha failed [ret: %d]\n", rc)); goto err_out_shost; + } + list_add_tail(&pm8001_ha->list, &hba_list); scsi_scan_host(pm8001_ha->shost); pm8001_ha->flags = PM8001F_RUN_TIME; return 0; @@ -1081,7 +1125,7 @@ err_out_shost: err_out_ha_free: pm8001_free(pm8001_ha); err_out_free: - kfree(SHOST_TO_SAS_HA(shost)); + kfree(sha); err_out_free_host: scsi_host_put(shost); err_out_regions: diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 93438c8f67da..ae7ba9b3c4bc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -137,10 +137,11 @@ struct pm8001_ioctl_payload { u32 signature; u16 major_function; u16 minor_function; - u16 length; u16 status; u16 offset; u16 id; + u32 wr_length; + u32 rd_length; u8 *func_specific; }; @@ -558,6 +559,8 @@ struct pm8001_hba_info { const struct firmware *fw_image; struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; u32 reset_in_progress; + u32 non_fatal_count; + u32 non_fatal_read_length; }; struct pm8001_work { @@ -741,6 +744,8 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf); +ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, + struct device_attribute *attr, char *buf); ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf); /* ctl shared API */ extern struct device_attribute *pm8001_host_attrs[]; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index d1d95f1a2c6a..4d205ebaee87 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -393,6 +393,136 @@ moreData: (char *)buf; } +/* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma + * location by the firmware. + */ +ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + void __iomem *nonfatal_table_address = pm8001_ha->fatal_tbl_addr; + u32 accum_len = 0; + u32 total_len = 0; + u32 reg_val = 0; + u32 *temp = NULL; + u32 index = 0; + u32 output_length; + unsigned long start = 0; + char *buf_copy = buf; + + temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; + if (++pm8001_ha->non_fatal_count == 1) { + if (pm8001_ha->chip_id == chip_8001) { + snprintf(pm8001_ha->forensic_info.data_buf.direct_data, + PAGE_SIZE, "Not supported for SPC controller"); + return 0; + } + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("forensic_info TYPE_NON_FATAL...\n")); + /* + * Step 1: Write the host buffer parameters in the MPI Fatal and + * Non-Fatal Error Dump Capture Table.This is the buffer + * where debug data will be DMAed to. + */ + pm8001_mw32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_LO_OFFSET, + pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_lo); + + pm8001_mw32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_HI_OFFSET, + pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_hi); + + pm8001_mw32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_LENGTH, SYSFS_OFFSET); + + /* Optionally, set the DUMPCTRL bit to 1 if the host + * keeps sending active I/Os while capturing the non-fatal + * debug data. Otherwise, leave this bit set to zero + */ + pm8001_mw32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); + + /* + * Step 2: Clear Accumulative Length of Debug Data Transferred + * [ACCDDLEN] field in the MPI Fatal and Non-Fatal Error Dump + * Capture Table to zero. + */ + pm8001_mw32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN, 0); + + /* initiallize previous accumulated length to 0 */ + pm8001_ha->forensic_preserved_accumulated_transfer = 0; + pm8001_ha->non_fatal_read_length = 0; + } + + total_len = pm8001_mr32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_TOTAL_LEN); + /* + * Step 3:Clear Fatal/Non-Fatal Debug Data Transfer Status [FDDTSTAT] + * field and then request that the SPCv controller transfer the debug + * data by setting bit 7 of the Inbound Doorbell Set Register. + */ + pm8001_mw32(nonfatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS, 0); + pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, + SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP); + + /* + * Step 4.1: Read back the Inbound Doorbell Set Register (by polling for + * 2 seconds) until register bit 7 is cleared. + * This step only indicates the request is accepted by the controller. + */ + start = jiffies + (2 * HZ); /* 2 sec */ + do { + reg_val = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET) & + SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP; + } while ((reg_val != 0) && time_before(jiffies, start)); + + /* Step 4.2: To check the completion of the transfer, poll the Fatal/Non + * Fatal Debug Data Transfer Status [FDDTSTAT] field for 2 seconds in + * the MPI Fatal and Non-Fatal Error Dump Capture Table. + */ + start = jiffies + (2 * HZ); /* 2 sec */ + do { + reg_val = pm8001_mr32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_STATUS); + } while ((!reg_val) && time_before(jiffies, start)); + + if ((reg_val == 0x00) || + (reg_val == MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED) || + (reg_val > MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE)) { + pm8001_ha->non_fatal_read_length = 0; + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 0xFFFFFFFF); + pm8001_ha->non_fatal_count = 0; + return (buf_copy - buf); + } else if (reg_val == + MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA) { + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 2); + } else if ((reg_val == MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) || + (pm8001_ha->non_fatal_read_length >= total_len)) { + pm8001_ha->non_fatal_read_length = 0; + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 4); + pm8001_ha->non_fatal_count = 0; + } + accum_len = pm8001_mr32(nonfatal_table_address, + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); + output_length = accum_len - + pm8001_ha->forensic_preserved_accumulated_transfer; + + for (index = 0; index < output_length/4; index++) + buf_copy += snprintf(buf_copy, PAGE_SIZE, + "%08x ", *(temp+index)); + + pm8001_ha->non_fatal_read_length += output_length; + + /* store current accumulated length to use in next iteration as + * the previous accumulated length + */ + pm8001_ha->forensic_preserved_accumulated_transfer = accum_len; + return (buf_copy - buf); +} + /** * read_main_config_table - read the configure table and save it. * @pm8001_ha: our hba card information @@ -1438,11 +1568,18 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) if (!pm8001_ha->controller_fatal_error) { /* Check if MPI is in ready state to reset */ if (mpi_uninit_check(pm8001_ha) != 0) { - regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + u32 r0 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); + u32 r1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + u32 r2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); + u32 r3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3); PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "MPI state is not ready scratch1 :0x%x\n", - regval)); - return -1; + "MPI state is not ready scratch: %x:%x:%x:%x\n", + r0, r1, r2, r3)); + /* if things aren't ready but the bootloader is ok then + * try the reset anyway. + */ + if (r1 & SCRATCH_PAD1_BOOTSTATE_MASK) + return -1; } } /* checked for reset register normal state; 0x0 */ @@ -3708,28 +3845,32 @@ static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { + u32 tag; u8 page_code; + int rc = 0; struct set_phy_profile_resp *pPayload = (struct set_phy_profile_resp *)(piomb + 4); u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid); u32 status = le32_to_cpu(pPayload->status); + tag = le32_to_cpu(pPayload->tag); page_code = (u8)((ppc_phyid & 0xFF00) >> 8); if (status) { /* status is FAILED */ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("PhyProfile command failed with status " "0x%08X \n", status)); - return -1; + rc = -1; } else { if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) { PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Invalid page code 0x%X\n", page_code)); - return -1; + rc = -1; } } - return 0; + pm8001_tag_free(pm8001_ha, tag); + return rc; } /** diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index a4f7eb8f50a3..15c962108075 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -623,7 +623,7 @@ struct pmcraid_aen_msg { u32 hostno; u32 length; u8 reserved[8]; - u8 data[0]; + u8 data[]; }; /* Controller state event message type */ diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h index 9513fd320ffd..9498279ae80d 100644 --- a/drivers/scsi/qedi/qedi.h +++ b/drivers/scsi/qedi/qedi.h @@ -36,6 +36,7 @@ struct qedi_endpoint; */ #define QEDI_MODE_NORMAL 0 #define QEDI_MODE_RECOVERY 1 +#define QEDI_MODE_SHUTDOWN 2 #define ISCSI_WQE_SET_PTU_INVALIDATE 1 #define QEDI_MAX_ISCSI_TASK 4096 @@ -278,6 +279,7 @@ struct qedi_ctx { #define QEDI_IOTHREAD_WAKE 2 #define QEDI_IN_RECOVERY 5 #define QEDI_IN_OFFLINE 6 +#define QEDI_IN_SHUTDOWN 7 u8 mac[ETH_ALEN]; u32 src_ip[4]; @@ -331,6 +333,7 @@ struct qedi_ctx { u16 ll2_mtu; struct workqueue_struct *dpc_wq; + struct delayed_work recovery_work; spinlock_t task_idx_lock; /* To protect gbl context */ s32 last_tidx_alloc; diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h index 8ba7c771ce4d..116645c08c71 100644 --- a/drivers/scsi/qedi/qedi_gbl.h +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -73,5 +73,6 @@ void qedi_remove_sysfs_ctx_attr(struct qedi_ctx *qedi); void qedi_clearsq(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn, struct iscsi_task *task); +void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess); #endif diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 8829880a54c3..1f4a5fb00a05 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -392,6 +392,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, qedi_ep->conn = qedi_conn; qedi_conn->ep = qedi_ep; + qedi_conn->iscsi_ep = ep; qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid; qedi_conn->fw_cid = qedi_ep->fw_cid; qedi_conn->cmd_cleanup_req = 0; @@ -782,6 +783,9 @@ static int qedi_task_xmit(struct iscsi_task *task) struct qedi_cmd *cmd = task->dd_data; struct scsi_cmnd *sc = task->sc; + if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags)) + return -ENODEV; + cmd->state = 0; cmd->task = NULL; cmd->use_slowpath = false; @@ -1596,6 +1600,20 @@ void qedi_process_iscsi_error(struct qedi_endpoint *ep, qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); } +void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *session = cls_sess->dd_data; + struct iscsi_conn *conn = session->leadconn; + struct qedi_conn *qedi_conn = conn->dd_data; + + if (iscsi_is_session_online(cls_sess)) + qedi_ep_disconnect(qedi_conn->iscsi_ep); + + qedi_conn_destroy(qedi_conn->cls_conn); + + qedi_session_destroy(cls_sess); +} + void qedi_process_tcp_error(struct qedi_endpoint *ep, struct iscsi_eqe_data *data) { diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h index 67c3b7349271..39dc27c85e3c 100644 --- a/drivers/scsi/qedi/qedi_iscsi.h +++ b/drivers/scsi/qedi/qedi_iscsi.h @@ -149,6 +149,7 @@ struct qedi_conn { struct iscsi_cls_conn *cls_conn; struct qedi_ctx *qedi; struct qedi_endpoint *ep; + struct iscsi_endpoint *iscsi_ep; struct list_head active_cmd_list; spinlock_t list_lock; /* internal conn lock */ u32 active_cmd_count; diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index acb930b8c6a6..b995b19865ca 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -58,6 +58,7 @@ static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid); static void qedi_reset_uio_rings(struct qedi_uio_dev *udev); static void qedi_ll2_free_skbs(struct qedi_ctx *qedi); static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); +static void qedi_recovery_handler(struct work_struct *work); static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) { @@ -1113,6 +1114,20 @@ exit_get_data: return; } +static void qedi_schedule_recovery_handler(void *dev) +{ + struct qedi_ctx *qedi = dev; + + QEDI_ERR(&qedi->dbg_ctx, "Recovery handler scheduled.\n"); + + if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) + return; + + atomic_set(&qedi->link_state, QEDI_LINK_DOWN); + + schedule_delayed_work(&qedi->recovery_work, 0); +} + static void qedi_link_update(void *dev, struct qed_link_output *link) { struct qedi_ctx *qedi = (struct qedi_ctx *)dev; @@ -1130,6 +1145,7 @@ static void qedi_link_update(void *dev, struct qed_link_output *link) static struct qed_iscsi_cb_ops qedi_cb_ops = { { .link_update = qedi_link_update, + .schedule_recovery_handler = qedi_schedule_recovery_handler, .get_protocol_tlv_data = qedi_get_protocol_tlv_data, .get_generic_tlv_data = qedi_get_generic_tlv_data, } @@ -2328,16 +2344,22 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) struct qedi_ctx *qedi = pci_get_drvdata(pdev); int rval; - if (qedi->tmf_thread) { - flush_workqueue(qedi->tmf_thread); - destroy_workqueue(qedi->tmf_thread); - qedi->tmf_thread = NULL; - } + if (mode == QEDI_MODE_SHUTDOWN) + iscsi_host_for_each_session(qedi->shost, + qedi_clear_session_ctx); + + if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { + if (qedi->tmf_thread) { + flush_workqueue(qedi->tmf_thread); + destroy_workqueue(qedi->tmf_thread); + qedi->tmf_thread = NULL; + } - if (qedi->offload_thread) { - flush_workqueue(qedi->offload_thread); - destroy_workqueue(qedi->offload_thread); - qedi->offload_thread = NULL; + if (qedi->offload_thread) { + flush_workqueue(qedi->offload_thread); + destroy_workqueue(qedi->offload_thread); + qedi->offload_thread = NULL; + } } #ifdef CONFIG_DEBUG_FS @@ -2353,8 +2375,7 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) qedi_ops->ll2->stop(qedi->cdev); } - if (mode == QEDI_MODE_NORMAL) - qedi_free_iscsi_pf_param(qedi); + qedi_free_iscsi_pf_param(qedi); rval = qedi_ops->common->update_drv_state(qedi->cdev, false); if (rval) @@ -2367,15 +2388,12 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) qedi_destroy_fp(qedi); - if (mode == QEDI_MODE_NORMAL) { + if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { qedi_release_cid_que(qedi); qedi_cm_free_mem(qedi); qedi_free_uio(qedi->udev); qedi_free_itt(qedi); - iscsi_host_remove(qedi->shost); - iscsi_host_free(qedi->shost); - if (qedi->ll2_recv_thread) { kthread_stop(qedi->ll2_recv_thread); qedi->ll2_recv_thread = NULL; @@ -2384,9 +2402,22 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) if (qedi->boot_kset) iscsi_boot_destroy_kset(qedi->boot_kset); + + iscsi_host_remove(qedi->shost); + iscsi_host_free(qedi->shost); } } +static void qedi_shutdown(struct pci_dev *pdev) +{ + struct qedi_ctx *qedi = pci_get_drvdata(pdev); + + QEDI_ERR(&qedi->dbg_ctx, "%s: Shutdown qedi\n", __func__); + if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) + return; + __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); +} + static int __qedi_probe(struct pci_dev *pdev, int mode) { struct qedi_ctx *qedi; @@ -2435,14 +2466,12 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) qedi->dev_info.common.num_hwfns, qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); - if (mode != QEDI_MODE_RECOVERY) { - rc = qedi_set_iscsi_pf_param(qedi); - if (rc) { - rc = -ENOMEM; - QEDI_ERR(&qedi->dbg_ctx, - "Set iSCSI pf param fail\n"); - goto free_host; - } + rc = qedi_set_iscsi_pf_param(qedi); + if (rc) { + rc = -ENOMEM; + QEDI_ERR(&qedi->dbg_ctx, + "Set iSCSI pf param fail\n"); + goto free_host; } qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); @@ -2633,6 +2662,8 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) goto free_cid_que; } + INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler); + /* F/w needs 1st task context memory entry for performance */ set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); atomic_set(&qedi->num_offloads, 0); @@ -2673,6 +2704,32 @@ exit_probe: return rc; } +static void qedi_mark_conn_recovery(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *session = cls_session->dd_data; + struct iscsi_conn *conn = session->leadconn; + struct qedi_conn *qedi_conn = conn->dd_data; + + iscsi_conn_failure(qedi_conn->cls_conn->dd_data, ISCSI_ERR_CONN_FAILED); +} + +static void qedi_recovery_handler(struct work_struct *work) +{ + struct qedi_ctx *qedi = + container_of(work, struct qedi_ctx, recovery_work.work); + + iscsi_host_for_each_session(qedi->shost, qedi_mark_conn_recovery); + + /* Call common_ops->recovery_prolog to allow the MFW to quiesce + * any PCI transactions. + */ + qedi_ops->common->recovery_prolog(qedi->cdev); + + __qedi_remove(qedi->pdev, QEDI_MODE_RECOVERY); + __qedi_probe(qedi->pdev, QEDI_MODE_RECOVERY); + clear_bit(QEDI_IN_RECOVERY, &qedi->flags); +} + static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { return __qedi_probe(pdev, QEDI_MODE_NORMAL); @@ -2697,6 +2754,7 @@ static struct pci_driver qedi_pci_driver = { .id_table = qedi_pci_tbl, .probe = qedi_probe, .remove = qedi_remove, + .shutdown = qedi_shutdown, }; static int __init qedi_init(void) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d7e7043f9eab..97cabd7e0014 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1324,6 +1324,79 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, } static ssize_t +qla2x00_beacon_config_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + uint16_t led[3] = { 0 }; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return -EPERM; + + if (ql26xx_led_config(vha, 0, led)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%#04hx %#04hx %#04hx\n", + led[0], led[1], led[2]); +} + +static ssize_t +qla2x00_beacon_config_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + uint16_t options = BIT_0; + uint16_t led[3] = { 0 }; + uint16_t word[4]; + int n; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return -EPERM; + + n = sscanf(buf, "%hx %hx %hx %hx", word+0, word+1, word+2, word+3); + if (n == 4) { + if (word[0] == 3) { + options |= BIT_3|BIT_2|BIT_1; + led[0] = word[1]; + led[1] = word[2]; + led[2] = word[3]; + goto write; + } + return -EINVAL; + } + + if (n == 2) { + /* check led index */ + if (word[0] == 0) { + options |= BIT_2; + led[0] = word[1]; + goto write; + } + if (word[0] == 1) { + options |= BIT_3; + led[1] = word[1]; + goto write; + } + if (word[0] == 2) { + options |= BIT_1; + led[2] = word[1]; + goto write; + } + return -EINVAL; + } + + return -EINVAL; + +write: + if (ql26xx_led_config(vha, options, led)) + return -EFAULT; + + return count; +} + +static ssize_t qla2x00_optrom_bios_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2250,6 +2323,26 @@ qla2x00_port_no_show(struct device *dev, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%u\n", vha->hw->port_no); } +static ssize_t +qla2x00_dport_diagnostics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && + !IS_QLA28XX(vha->hw)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + if (!*vha->dport_data) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", + vha->dport_data[0], vha->dport_data[1], + vha->dport_data[2], vha->dport_data[3]); +} +static DEVICE_ATTR(dport_diagnostics, 0444, + qla2x00_dport_diagnostics_show, NULL); + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -2264,6 +2357,8 @@ static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show, qla2x00_zio_timer_store); static DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, qla2x00_beacon_store); +static DEVICE_ATTR(beacon_config, 0644, qla2x00_beacon_config_show, + qla2x00_beacon_config_store); static DEVICE_ATTR(optrom_bios_version, S_IRUGO, qla2x00_optrom_bios_version_show, NULL); static DEVICE_ATTR(optrom_efi_version, S_IRUGO, @@ -2327,6 +2422,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_zio, &dev_attr_zio_timer, &dev_attr_beacon, + &dev_attr_beacon_config, &dev_attr_optrom_bios_version, &dev_attr_optrom_efi_version, &dev_attr_optrom_fcode_version, @@ -2355,6 +2451,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_port_speed, &dev_attr_port_no, &dev_attr_fw_attr, + &dev_attr_dport_diagnostics, NULL, /* reserve for qlini_mode */ NULL, /* reserve for ql2xiniexchg */ NULL, /* reserve for ql2xexchoffld */ @@ -2648,22 +2745,28 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (rval != QLA_SUCCESS) goto done_free; - p->link_failure_count = stats->link_fail_cnt; - p->loss_of_sync_count = stats->loss_sync_cnt; - p->loss_of_signal_count = stats->loss_sig_cnt; - p->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; - p->invalid_tx_word_count = stats->inval_xmit_word_cnt; - p->invalid_crc_count = stats->inval_crc_cnt; + p->link_failure_count = le32_to_cpu(stats->link_fail_cnt); + p->loss_of_sync_count = le32_to_cpu(stats->loss_sync_cnt); + p->loss_of_signal_count = le32_to_cpu(stats->loss_sig_cnt); + p->prim_seq_protocol_err_count = le32_to_cpu(stats->prim_seq_err_cnt); + p->invalid_tx_word_count = le32_to_cpu(stats->inval_xmit_word_cnt); + p->invalid_crc_count = le32_to_cpu(stats->inval_crc_cnt); if (IS_FWI2_CAPABLE(ha)) { - p->lip_count = stats->lip_cnt; - p->tx_frames = stats->tx_frames; - p->rx_frames = stats->rx_frames; - p->dumped_frames = stats->discarded_frames; - p->nos_count = stats->nos_rcvd; + p->lip_count = le32_to_cpu(stats->lip_cnt); + p->tx_frames = le32_to_cpu(stats->tx_frames); + p->rx_frames = le32_to_cpu(stats->rx_frames); + p->dumped_frames = le32_to_cpu(stats->discarded_frames); + p->nos_count = le32_to_cpu(stats->nos_rcvd); p->error_frames = - stats->dropped_frames + stats->discarded_frames; - p->rx_words = vha->qla_stats.input_bytes; - p->tx_words = vha->qla_stats.output_bytes; + le32_to_cpu(stats->dropped_frames) + + le32_to_cpu(stats->discarded_frames); + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + p->rx_words = le64_to_cpu(stats->fpm_recv_word_cnt); + p->tx_words = le64_to_cpu(stats->fpm_xmit_word_cnt); + } else { + p->rx_words = vha->qla_stats.input_bytes; + p->tx_words = vha->qla_stats.output_bytes; + } } p->fcp_control_requests = vha->qla_stats.control_requests; p->fcp_input_requests = vha->qla_stats.input_requests; @@ -2671,7 +2774,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) p->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20; p->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20; p->seconds_since_last_reset = - get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset; + get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset; do_div(p->seconds_since_last_reset, HZ); done_free: diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index d7169e43f5e1..97b51c477972 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -11,6 +11,14 @@ #include <linux/delay.h> #include <linux/bsg-lib.h> +static void qla2xxx_free_fcport_work(struct work_struct *work) +{ + struct fc_port *fcport = container_of(work, typeof(*fcport), + free_work); + + qla2x00_free_fcport(fcport); +} + /* BSG support for ELS/CT pass through */ void qla2x00_bsg_job_done(srb_t *sp, int res) { @@ -53,8 +61,10 @@ void qla2x00_bsg_sp_free(srb_t *sp) if (sp->type == SRB_CT_CMD || sp->type == SRB_FXIOCB_BCMD || - sp->type == SRB_ELS_CMD_HST) - qla2x00_free_fcport(sp->fcport); + sp->type == SRB_ELS_CMD_HST) { + INIT_WORK(&sp->fcport->free_work, qla2xxx_free_fcport_work); + queue_work(ha->wq, &sp->fcport->free_work); + } qla2x00_rel_sp(sp); } @@ -718,7 +728,7 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) uint16_t response[MAILBOX_REGISTER_COUNT]; uint16_t config[4], new_config[4]; uint8_t *fw_sts_ptr; - uint8_t *req_data = NULL; + void *req_data = NULL; dma_addr_t req_data_dma; uint32_t req_data_len; uint8_t *rsp_data = NULL; @@ -796,10 +806,11 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) bsg_request->rqst_data.h_vendor.vendor_cmd[2]; if (atomic_read(&vha->loop_state) == LOOP_READY && - (ha->current_topology == ISP_CFG_F || - (get_unaligned_le32(req_data) == ELS_OPCODE_BYTE && - req_data_len == MAX_ELS_FRAME_PAYLOAD)) && - elreq.options == EXTERNAL_LOOPBACK) { + ((ha->current_topology == ISP_CFG_F && (elreq.options & 7) >= 2) || + ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) && + get_unaligned_le32(req_data) == ELS_OPCODE_BYTE && + req_data_len == MAX_ELS_FRAME_PAYLOAD && + elreq.options == EXTERNAL_LOOPBACK))) { type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; ql_dbg(ql_dbg_user, vha, 0x701e, "BSG request type: %s.\n", type); @@ -1506,10 +1517,15 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) bsg_job->request_payload.sg_cnt, ha->optrom_buffer, ha->optrom_region_size); - ha->isp_ops->write_optrom(vha, ha->optrom_buffer, + rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer, ha->optrom_region_start, ha->optrom_region_size); - bsg_reply->result = DID_OK; + if (rval) { + bsg_reply->result = -EINVAL; + rval = -EINVAL; + } else { + bsg_reply->result = DID_OK; + } vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; @@ -2404,7 +2420,7 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job) regions.global_image = active_regions.global; if (IS_QLA28XX(ha)) { - qla27xx_get_active_image(vha, &active_regions); + qla28xx_get_aux_images(vha, &active_regions); regions.board_config = active_regions.aux.board_config; regions.vpd_nvram = active_regions.aux.vpd_nvram; regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 88a56e8480f7..f301a8048b2f 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -73,6 +73,8 @@ #include "qla_def.h" #include <linux/delay.h> +#define CREATE_TRACE_POINTS +#include <trace/events/qla.h> static uint32_t ql_dbg_offset = 0x800; @@ -2537,15 +2539,30 @@ ql_dbg(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...) { va_list va; struct va_format vaf; - - if (!ql_mask_match(level)) - return; + char pbuf[64]; va_start(va, fmt); vaf.fmt = fmt; vaf.va = &va; + if (!ql_mask_match(level)) { + if (vha != NULL) { + const struct pci_dev *pdev = vha->hw->pdev; + /* <module-name> <msg-id>:<host> Message */ + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x:%ld: ", + QL_MSGHDR, dev_name(&(pdev->dev)), id, + vha->host_no); + } else { + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", + QL_MSGHDR, "0000:00:00.0", id); + } + pbuf[sizeof(pbuf) - 1] = 0; + trace_ql_dbg_log(pbuf, &vaf); + va_end(va); + return; + } + if (vha != NULL) { const struct pci_dev *pdev = vha->hw->pdev; /* <module-name> <pci-name> <msg-id>:<host> Message */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ed32e9715794..47c7a56438b5 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -119,7 +119,10 @@ typedef struct { #define LSD(x) ((uint32_t)((uint64_t)(x))) #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) -#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y))) +static inline uint32_t make_handle(uint16_t x, uint16_t y) +{ + return ((uint32_t)x << 16) | y; +} /* * I/O register @@ -414,7 +417,7 @@ struct els_logo_payload { struct els_plogi_payload { uint8_t opcode; uint8_t rsvd[3]; - uint8_t data[112]; + __be32 data[112 / 4]; }; struct ct_arg { @@ -597,9 +600,6 @@ typedef struct srb { struct fc_port *fcport; struct scsi_qla_host *vha; unsigned int start_timer:1; - unsigned int abort:1; - unsigned int aborted:1; - unsigned int completed:1; uint32_t handle; uint16_t flags; @@ -1049,6 +1049,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBA_TEMPERATURE_ALERT 0x8070 /* Temperature Alert */ #define MBA_DPORT_DIAGNOSTICS 0x8080 /* D-port Diagnostics */ #define MBA_TRANS_INSERT 0x8130 /* Transceiver Insertion */ +#define MBA_TRANS_REMOVE 0x8131 /* Transceiver Removal */ #define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */ #define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change Notification */ @@ -1134,6 +1135,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */ #define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/ #define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */ +#define MBC_SET_GET_FC_LED_CONFIG 0x3b /* Set/Get FC LED config */ #define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */ #define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */ #define MBC_GET_RESOURCE_COUNTS 0x42 /* Get Resource Counts. */ @@ -1260,10 +1262,15 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define MBX_1 BIT_1 #define MBX_0 BIT_0 +#define RNID_TYPE_ELS_CMD 0x5 #define RNID_TYPE_PORT_LOGIN 0x7 +#define RNID_BUFFER_CREDITS 0x8 #define RNID_TYPE_SET_VERSION 0x9 #define RNID_TYPE_ASIC_TEMP 0xC +#define ELS_CMD_MAP_SIZE 32 +#define ELS_COMMAND_RDP 0x18 + /* * Firmware state codes from get firmware state mailbox command */ @@ -1474,47 +1481,44 @@ typedef struct { #define GLSO_USE_DID BIT_3 struct link_statistics { - uint32_t link_fail_cnt; - uint32_t loss_sync_cnt; - uint32_t loss_sig_cnt; - uint32_t prim_seq_err_cnt; - uint32_t inval_xmit_word_cnt; - uint32_t inval_crc_cnt; - uint32_t lip_cnt; - uint32_t link_up_cnt; - uint32_t link_down_loop_init_tmo; - uint32_t link_down_los; - uint32_t link_down_loss_rcv_clk; + __le32 link_fail_cnt; + __le32 loss_sync_cnt; + __le32 loss_sig_cnt; + __le32 prim_seq_err_cnt; + __le32 inval_xmit_word_cnt; + __le32 inval_crc_cnt; + __le32 lip_cnt; + __le32 link_up_cnt; + __le32 link_down_loop_init_tmo; + __le32 link_down_los; + __le32 link_down_loss_rcv_clk; uint32_t reserved0[5]; - uint32_t port_cfg_chg; + __le32 port_cfg_chg; uint32_t reserved1[11]; - uint32_t rsp_q_full; - uint32_t atio_q_full; - uint32_t drop_ae; - uint32_t els_proto_err; - uint32_t reserved2; - uint32_t tx_frames; - uint32_t rx_frames; - uint32_t discarded_frames; - uint32_t dropped_frames; + __le32 rsp_q_full; + __le32 atio_q_full; + __le32 drop_ae; + __le32 els_proto_err; + __le32 reserved2; + __le32 tx_frames; + __le32 rx_frames; + __le32 discarded_frames; + __le32 dropped_frames; uint32_t reserved3; - uint32_t nos_rcvd; + __le32 nos_rcvd; uint32_t reserved4[4]; - uint32_t tx_prjt; - uint32_t rcv_exfail; - uint32_t rcv_abts; - uint32_t seq_frm_miss; - uint32_t corr_err; - uint32_t mb_rqst; - uint32_t nport_full; - uint32_t eofa; + __le32 tx_prjt; + __le32 rcv_exfail; + __le32 rcv_abts; + __le32 seq_frm_miss; + __le32 corr_err; + __le32 mb_rqst; + __le32 nport_full; + __le32 eofa; uint32_t reserved5; - uint32_t fpm_recv_word_cnt_lo; - uint32_t fpm_recv_word_cnt_hi; - uint32_t fpm_disc_word_cnt_lo; - uint32_t fpm_disc_word_cnt_hi; - uint32_t fpm_xmit_word_cnt_lo; - uint32_t fpm_xmit_word_cnt_hi; + __le64 fpm_recv_word_cnt; + __le64 fpm_disc_word_cnt; + __le64 fpm_xmit_word_cnt; uint32_t reserved6[70]; }; @@ -2624,10 +2628,11 @@ static const char * const port_dstate_str[] = { #define GFF_ID_RSP_SIZE (16 + 128) /* - * HBA attribute types. + * FDMI HBA attribute types. */ -#define FDMI_HBA_ATTR_COUNT 9 -#define FDMIV2_HBA_ATTR_COUNT 17 +#define FDMI1_HBA_ATTR_COUNT 9 +#define FDMI2_HBA_ATTR_COUNT 17 + #define FDMI_HBA_NODE_NAME 0x1 #define FDMI_HBA_MANUFACTURER 0x2 #define FDMI_HBA_SERIAL_NUMBER 0x3 @@ -2639,12 +2644,13 @@ static const char * const port_dstate_str[] = { #define FDMI_HBA_FIRMWARE_VERSION 0x9 #define FDMI_HBA_OS_NAME_AND_VERSION 0xa #define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb + #define FDMI_HBA_NODE_SYMBOLIC_NAME 0xc -#define FDMI_HBA_VENDOR_ID 0xd +#define FDMI_HBA_VENDOR_SPECIFIC_INFO 0xd #define FDMI_HBA_NUM_PORTS 0xe #define FDMI_HBA_FABRIC_NAME 0xf #define FDMI_HBA_BOOT_BIOS_NAME 0x10 -#define FDMI_HBA_TYPE_VENDOR_IDENTIFIER 0xe0 +#define FDMI_HBA_VENDOR_IDENTIFIER 0xe0 struct ct_fdmi_hba_attr { uint16_t type; @@ -2661,31 +2667,9 @@ struct ct_fdmi_hba_attr { uint8_t fw_version[32]; uint8_t os_version[128]; uint32_t max_ct_len; - } a; -}; - -struct ct_fdmi_hba_attributes { - uint32_t count; - struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; -}; -struct ct_fdmiv2_hba_attr { - uint16_t type; - uint16_t len; - union { - uint8_t node_name[WWN_SIZE]; - uint8_t manufacturer[64]; - uint8_t serial_num[32]; - uint8_t model[16+1]; - uint8_t model_desc[80]; - uint8_t hw_version[16]; - uint8_t driver_version[32]; - uint8_t orom_version[16]; - uint8_t fw_version[32]; - uint8_t os_version[128]; - uint32_t max_ct_len; uint8_t sym_name[256]; - uint32_t vendor_id; + uint32_t vendor_specific_info; uint32_t num_ports; uint8_t fabric_name[WWN_SIZE]; uint8_t bios_name[32]; @@ -2693,22 +2677,30 @@ struct ct_fdmiv2_hba_attr { } a; }; -struct ct_fdmiv2_hba_attributes { +struct ct_fdmi1_hba_attributes { uint32_t count; - struct ct_fdmiv2_hba_attr entry[FDMIV2_HBA_ATTR_COUNT]; + struct ct_fdmi_hba_attr entry[FDMI1_HBA_ATTR_COUNT]; +}; + +struct ct_fdmi2_hba_attributes { + uint32_t count; + struct ct_fdmi_hba_attr entry[FDMI2_HBA_ATTR_COUNT]; }; /* - * Port attribute types. + * FDMI Port attribute types. */ -#define FDMI_PORT_ATTR_COUNT 6 -#define FDMIV2_PORT_ATTR_COUNT 16 +#define FDMI1_PORT_ATTR_COUNT 6 +#define FDMI2_PORT_ATTR_COUNT 16 +#define FDMI2_SMARTSAN_PORT_ATTR_COUNT 23 + #define FDMI_PORT_FC4_TYPES 0x1 #define FDMI_PORT_SUPPORT_SPEED 0x2 #define FDMI_PORT_CURRENT_SPEED 0x3 #define FDMI_PORT_MAX_FRAME_SIZE 0x4 #define FDMI_PORT_OS_DEVICE_NAME 0x5 #define FDMI_PORT_HOST_NAME 0x6 + #define FDMI_PORT_NODE_NAME 0x7 #define FDMI_PORT_NAME 0x8 #define FDMI_PORT_SYM_NAME 0x9 @@ -2718,7 +2710,15 @@ struct ct_fdmiv2_hba_attributes { #define FDMI_PORT_FC4_TYPE 0xd #define FDMI_PORT_STATE 0x101 #define FDMI_PORT_COUNT 0x102 -#define FDMI_PORT_ID 0x103 +#define FDMI_PORT_IDENTIFIER 0x103 + +#define FDMI_SMARTSAN_SERVICE 0xF100 +#define FDMI_SMARTSAN_GUID 0xF101 +#define FDMI_SMARTSAN_VERSION 0xF102 +#define FDMI_SMARTSAN_PROD_NAME 0xF103 +#define FDMI_SMARTSAN_PORT_INFO 0xF104 +#define FDMI_SMARTSAN_QOS_SUPPORT 0xF105 +#define FDMI_SMARTSAN_SECURITY_SUPPORT 0xF106 #define FDMI_PORT_SPEED_1GB 0x1 #define FDMI_PORT_SPEED_2GB 0x2 @@ -2734,7 +2734,7 @@ struct ct_fdmiv2_hba_attributes { #define FC_CLASS_3 0x08 #define FC_CLASS_2_3 0x0C -struct ct_fdmiv2_port_attr { +struct ct_fdmi_port_attr { uint16_t type; uint16_t len; union { @@ -2744,6 +2744,7 @@ struct ct_fdmiv2_port_attr { uint32_t max_frame_size; uint8_t os_dev_name[32]; uint8_t host_name[256]; + uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t port_sym_name[128]; @@ -2754,35 +2755,38 @@ struct ct_fdmiv2_port_attr { uint32_t port_state; uint32_t num_ports; uint32_t port_id; + + uint8_t smartsan_service[24]; + uint8_t smartsan_guid[16]; + uint8_t smartsan_version[24]; + uint8_t smartsan_prod_name[16]; + uint32_t smartsan_port_info; + uint32_t smartsan_qos_support; + uint32_t smartsan_security_support; } a; }; -/* - * Port Attribute Block. - */ -struct ct_fdmiv2_port_attributes { +struct ct_fdmi1_port_attributes { uint32_t count; - struct ct_fdmiv2_port_attr entry[FDMIV2_PORT_ATTR_COUNT]; -}; - -struct ct_fdmi_port_attr { - uint16_t type; - uint16_t len; - union { - uint8_t fc4_types[32]; - uint32_t sup_speed; - uint32_t cur_speed; - uint32_t max_frame_size; - uint8_t os_dev_name[32]; - uint8_t host_name[256]; - } a; + struct ct_fdmi_port_attr entry[FDMI1_PORT_ATTR_COUNT]; }; -struct ct_fdmi_port_attributes { +struct ct_fdmi2_port_attributes { uint32_t count; - struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; + struct ct_fdmi_port_attr entry[FDMI2_PORT_ATTR_COUNT]; }; +#define FDMI_ATTR_TYPELEN(obj) \ + (sizeof((obj)->type) + sizeof((obj)->len)) + +#define FDMI_ATTR_ALIGNMENT(len) \ + (4 - ((len) & 3)) + +/* FDMI register call options */ +#define CALLOPT_FDMI1 0 +#define CALLOPT_FDMI2 1 +#define CALLOPT_FDMI2_SMARTSAN 2 + /* FDMI definitions. */ #define GRHL_CMD 0x100 #define GHAT_CMD 0x101 @@ -2793,10 +2797,13 @@ struct ct_fdmi_port_attributes { #define RHBA_RSP_SIZE 16 #define RHAT_CMD 0x201 + #define RPRT_CMD 0x210 +#define RPRT_RSP_SIZE 24 #define RPA_CMD 0x211 #define RPA_RSP_SIZE 16 +#define SMARTSAN_RPA_RSP_SIZE 24 #define DHBA_CMD 0x300 #define DHBA_REQ_SIZE (16 + 8) @@ -2879,30 +2886,24 @@ struct ct_sns_req { uint8_t hba_identifier[8]; uint32_t entry_count; uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi2_hba_attributes attrs; } rhba; struct { uint8_t hba_identifier[8]; - uint32_t entry_count; - uint8_t port_name[8]; - struct ct_fdmiv2_hba_attributes attrs; - } rhba2; - - struct { - uint8_t hba_identifier[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi1_hba_attributes attrs; } rhat; struct { uint8_t port_name[8]; - struct ct_fdmi_port_attributes attrs; + struct ct_fdmi2_port_attributes attrs; } rpa; struct { + uint8_t hba_identifier[8]; uint8_t port_name[8]; - struct ct_fdmiv2_port_attributes attrs; - } rpa2; + struct ct_fdmi2_port_attributes attrs; + } rprt; struct { uint8_t port_name[8]; @@ -3016,7 +3017,7 @@ struct ct_sns_rsp { struct { uint32_t entry_count; uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; + struct ct_fdmi1_hba_attributes attrs; } ghat; struct { @@ -3250,6 +3251,7 @@ struct isp_operations { #define QLA_MSIX_RSP_Q 0x01 #define QLA_ATIO_VECTOR 0x02 #define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03 +#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS 0x04 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 @@ -3562,6 +3564,134 @@ struct qlfc_fw { uint32_t len; }; +struct rdp_req_payload { + uint32_t els_request; + uint32_t desc_list_len; + + /* NPIV descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t reserved; + uint8_t nport_id[3]; + } npiv_desc; +}; + +struct rdp_rsp_payload { + struct { + uint32_t cmd; + uint32_t len; + } hdr; + + /* LS Request Info descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t req_payload_word_0; + } ls_req_info_desc; + + /* LS Request Info descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t req_payload_word_0; + } ls_req_info_desc2; + + /* SFP diagnostic param descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t temperature; + uint16_t vcc; + uint16_t tx_bias; + uint16_t tx_power; + uint16_t rx_power; + uint16_t sfp_flags; + } sfp_diag_desc; + + /* Port Speed Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t speed_capab; + uint16_t operating_speed; + } port_speed_desc; + + /* Link Error Status Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t link_fail_cnt; + uint32_t loss_sync_cnt; + uint32_t loss_sig_cnt; + uint32_t prim_seq_err_cnt; + uint32_t inval_xmit_word_cnt; + uint32_t inval_crc_cnt; + uint8_t pn_port_phy_type; + uint8_t reserved[3]; + } ls_err_desc; + + /* Port name description with diag param */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t WWNN[WWN_SIZE]; + uint8_t WWPN[WWN_SIZE]; + } port_name_diag_desc; + + /* Port Name desc for Direct attached Fx_Port or Nx_Port */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t WWNN[WWN_SIZE]; + uint8_t WWPN[WWN_SIZE]; + } port_name_direct_desc; + + /* Buffer Credit descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint32_t fcport_b2b; + uint32_t attached_fcport_b2b; + uint32_t fcport_rtt; + } buffer_credit_desc; + + /* Optical Element Data Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint16_t high_alarm; + uint16_t low_alarm; + uint16_t high_warn; + uint16_t low_warn; + uint32_t element_flags; + } optical_elmt_desc[5]; + + /* Optical Product Data Descriptor */ + struct { + uint32_t desc_tag; + uint32_t desc_len; + uint8_t vendor_name[16]; + uint8_t part_number[16]; + uint8_t serial_number[16]; + uint8_t revision[4]; + uint8_t date[8]; + } optical_prod_desc; +}; + +#define RDP_DESC_LEN(obj) \ + (sizeof(obj) - sizeof((obj).desc_tag) - sizeof((obj).desc_len)) + +#define RDP_PORT_SPEED_1GB BIT_15 +#define RDP_PORT_SPEED_2GB BIT_14 +#define RDP_PORT_SPEED_4GB BIT_13 +#define RDP_PORT_SPEED_10GB BIT_12 +#define RDP_PORT_SPEED_8GB BIT_11 +#define RDP_PORT_SPEED_16GB BIT_10 +#define RDP_PORT_SPEED_32GB BIT_9 +#define RDP_PORT_SPEED_64GB BIT_8 +#define RDP_PORT_SPEED_UNKNOWN BIT_0 + struct scsi_qlt_host { void *target_lport_ptr; struct mutex tgt_mutex; @@ -3673,8 +3803,8 @@ struct qla_hw_data { uint32_t fw_started:1; uint32_t fw_init_done:1; - uint32_t detected_lr_sfp:1; - uint32_t using_lr_setting:1; + uint32_t lr_detected:1; + uint32_t rida_fmt2:1; uint32_t purge_mbox:1; uint32_t n2n_bigger:1; @@ -3683,7 +3813,7 @@ struct qla_hw_data { } flags; uint16_t max_exchg; - uint16_t long_range_distance; /* 32G & above */ + uint16_t lr_distance; /* 32G & above */ #define LR_DISTANCE_5K 1 #define LR_DISTANCE_10K 0 @@ -3965,6 +4095,8 @@ struct qla_hw_data { #define SFP_DEV_SIZE 512 #define SFP_BLOCK_SIZE 64 +#define SFP_RTDI_LEN SFP_BLOCK_SIZE + void *sfp_data; dma_addr_t sfp_data_dma; @@ -4344,6 +4476,15 @@ struct active_regions { #define QLA_SET_DATA_RATE_NOLR 1 #define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */ +struct purex_item { + struct list_head list; + struct scsi_qla_host *vha; + void (*process_item)(struct scsi_qla_host *vha, void *pkt); + struct { + uint8_t iocb[64]; + } iocb; +}; + /* * Qlogic scsi host structure */ @@ -4424,6 +4565,8 @@ typedef struct scsi_qla_host { #define ISP_ABORT_TO_ROM 33 #define VPORT_DELETE 34 +#define PROCESS_PUREX_IOCB 63 + unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ #define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */ @@ -4461,6 +4604,7 @@ typedef struct scsi_qla_host { uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t fabric_node_name[WWN_SIZE]; + uint8_t fabric_port_name[WWN_SIZE]; struct nvme_fc_local_port *nvme_local_port; struct completion nvme_del_done; @@ -4531,6 +4675,11 @@ typedef struct scsi_qla_host { uint16_t ql2xexchoffld; uint16_t ql2xiniexchg; + struct purex_list { + struct list_head head; + spinlock_t lock; + } purex_list; + struct name_list_extended gnl; /* Count of active session/fcport */ int fcport_count; @@ -4540,6 +4689,7 @@ typedef struct scsi_qla_host { uint8_t n2n_node_name[WWN_SIZE]; uint8_t n2n_port_name[WWN_SIZE]; uint16_t n2n_id; + __le16 dport_data[4]; struct list_head gpnid_list; struct fab_scan scan; @@ -4822,11 +4972,14 @@ struct sff_8247_a0 { u8 resv2[128]; }; -#define AUTO_DETECT_SFP_SUPPORT(_vha)\ - (ql2xautodetectsfp && !_vha->vp_idx && \ - (IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\ - IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \ - IS_QLA28XX(_vha->hw))) +/* BPM -- Buffer Plus Management support. */ +#define IS_BPM_CAPABLE(ha) \ + (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ + IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_BPM_RANGE_CAPABLE(ha) \ + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_BPM_ENABLED(vha) \ + (ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw)) #define FLASH_SEMAPHORE_REGISTER_ADDR 0x00101016 diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 0a6fb359f4d5..e62b2115235e 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -134,11 +134,11 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) } else { seq_puts(s, "FW Resource count\n\n"); seq_printf(s, "Original TGT exchg count[%d]\n", mb[1]); - seq_printf(s, "current TGT exchg count[%d]\n", mb[2]); - seq_printf(s, "original Initiator Exchange count[%d]\n", mb[3]); - seq_printf(s, "Current Initiator Exchange count[%d]\n", mb[6]); - seq_printf(s, "Original IOCB count[%d]\n", mb[7]); - seq_printf(s, "Current IOCB count[%d]\n", mb[10]); + seq_printf(s, "Current TGT exchg count[%d]\n", mb[2]); + seq_printf(s, "Current Initiator Exchange count[%d]\n", mb[3]); + seq_printf(s, "Original Initiator Exchange count[%d]\n", mb[6]); + seq_printf(s, "Current IOCB count[%d]\n", mb[7]); + seq_printf(s, "Original IOCB count[%d]\n", mb[10]); seq_printf(s, "MAX VP count[%d]\n", mb[11]); seq_printf(s, "MAX FCF count[%d]\n", mb[12]); seq_printf(s, "Current free pageable XCB buffer cnt[%d]\n", @@ -149,7 +149,6 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) mb[22]); seq_printf(s, "Original Target fast XCB buffer cnt[%d]\n", mb[23]); - } return 0; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index d641918cdd46..f9bad5bd7198 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -31,6 +31,9 @@ #define PDO_FORCE_ADISC BIT_1 #define PDO_FORCE_PLOGI BIT_0 +struct buffer_credit_24xx { + u32 parameter[28]; +}; #define PORT_DATABASE_24XX_SIZE 64 struct port_database_24xx { @@ -721,6 +724,48 @@ struct ct_entry_24xx { }; /* + * ISP queue - PUREX IOCB entry structure definition + */ +#define PUREX_IOCB_TYPE 0x51 /* CT Pass Through IOCB entry */ +struct purex_entry_24xx { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint16_t reserved1; + uint8_t vp_idx; + uint8_t reserved2; + + uint16_t status_flags; + uint16_t nport_handle; + + uint16_t frame_size; + uint16_t trunc_frame_size; + + uint32_t rx_xchg_addr; + + uint8_t d_id[3]; + uint8_t r_ctl; + + uint8_t s_id[3]; + uint8_t cs_ctl; + + uint8_t f_ctl[3]; + uint8_t type; + + uint16_t seq_cnt; + uint8_t df_ctl; + uint8_t seq_id; + + uint16_t rx_id; + uint16_t ox_id; + uint32_t param; + + uint8_t els_frame_payload[20]; +}; + +/* * ISP queue - ELS Pass-Through entry structure definition. */ #define ELS_IOCB_TYPE 0x53 /* ELS Pass-Through IOCB entry */ @@ -732,9 +777,8 @@ struct els_entry_24xx { uint32_t handle; /* System handle. */ - uint16_t reserved_1; - - uint16_t nport_handle; /* N_PORT handle. */ + uint16_t comp_status; /* response only */ + uint16_t nport_handle; uint16_t tx_dsd_count; @@ -749,7 +793,7 @@ struct els_entry_24xx { uint8_t opcode; uint8_t reserved_2; - uint8_t port_id[3]; + uint8_t d_id[3]; uint8_t s_id[3]; uint16_t control_flags; /* Control flags. */ @@ -761,13 +805,24 @@ struct els_entry_24xx { #define ECF_CLR_PASSTHRU_PEND BIT_12 #define ECF_INCL_FRAME_HDR BIT_11 - __le32 rx_byte_count; - __le32 tx_byte_count; + union { + struct { + __le32 rx_byte_count; + __le32 tx_byte_count; - __le64 tx_address __packed; /* Data segment 0 address. */ - __le32 tx_len; /* Data segment 0 length. */ - __le64 rx_address __packed; /* Data segment 1 address. */ - __le32 rx_len; /* Data segment 1 length. */ + __le64 tx_address __packed; /* DSD 0 address. */ + __le32 tx_len; /* DSD 0 length. */ + + __le64 rx_address __packed; /* DSD 1 address. */ + __le32 rx_len; /* DSD 1 length. */ + }; + struct { + uint32_t total_byte_count; + uint32_t error_subcode_1; + uint32_t error_subcode_2; + uint32_t error_subcode_3; + }; + }; }; struct els_sts_entry_24xx { @@ -793,15 +848,16 @@ struct els_sts_entry_24xx { uint8_t opcode; uint8_t reserved_3; - uint8_t port_id[3]; - uint8_t reserved_4; - - uint16_t reserved_5; + uint8_t d_id[3]; + uint8_t s_id[3]; uint16_t control_flags; /* Control flags. */ uint32_t total_byte_count; uint32_t error_subcode_1; uint32_t error_subcode_2; + uint32_t error_subcode_3; + + uint32_t reserved_4[4]; }; /* * ISP queue - Mailbox Command entry structure definition. @@ -942,6 +998,91 @@ struct abort_entry_24xx { uint8_t reserved_2[12]; }; +#define ABTS_RCV_TYPE 0x54 +#define ABTS_RSP_TYPE 0x55 +struct abts_entry_24xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t handle_count; + uint8_t entry_status; + + uint32_t handle; /* type 0x55 only */ + + uint16_t comp_status; /* type 0x55 only */ + uint16_t nport_handle; /* type 0x54 only */ + + uint16_t control_flags; /* type 0x55 only */ + uint8_t vp_idx; + uint8_t sof_type; /* sof_type is upper nibble */ + + uint32_t rx_xch_addr; + + uint8_t d_id[3]; + uint8_t r_ctl; + + uint8_t s_id[3]; + uint8_t cs_ctl; + + uint8_t f_ctl[3]; + uint8_t type; + + uint16_t seq_cnt; + uint8_t df_ctl; + uint8_t seq_id; + + uint16_t rx_id; + uint16_t ox_id; + + uint32_t param; + + union { + struct { + uint32_t subcode3; + uint32_t rsvd; + uint32_t subcode1; + uint32_t subcode2; + } error; + struct { + uint16_t rsrvd1; + uint8_t last_seq_id; + uint8_t seq_id_valid; + uint16_t aborted_rx_id; + uint16_t aborted_ox_id; + uint16_t high_seq_cnt; + uint16_t low_seq_cnt; + } ba_acc; + struct { + uint8_t vendor_unique; + uint8_t explanation; + uint8_t reason; + } ba_rjt; + } payload; + + uint32_t rx_xch_addr_to_abort; +} __packed; + +/* ABTS payload explanation values */ +#define BA_RJT_EXP_NO_ADDITIONAL 0 +#define BA_RJT_EXP_INV_OX_RX_ID 3 +#define BA_RJT_EXP_SEQ_ABORTED 5 + +/* ABTS payload reason values */ +#define BA_RJT_RSN_INV_CMD_CODE 1 +#define BA_RJT_RSN_LOGICAL_ERROR 3 +#define BA_RJT_RSN_LOGICAL_BUSY 5 +#define BA_RJT_RSN_PROTOCOL_ERROR 7 +#define BA_RJT_RSN_UNABLE_TO_PERFORM 9 +#define BA_RJT_RSN_VENDOR_SPECIFIC 0xff + +/* FC_F values */ +#define FC_TYPE_BLD 0x000 /* Basic link data */ +#define FC_F_CTL_RSP_CNTXT 0x800000 /* Responder of exchange */ +#define FC_F_CTL_LAST_SEQ 0x100000 /* Last sequence */ +#define FC_F_CTL_END_SEQ 0x80000 /* Last sequence */ +#define FC_F_CTL_SEQ_INIT 0x010000 /* Sequence initiative */ +#define FC_ROUTING_BLD 0x80 /* Basic link data frame */ +#define FC_R_CTL_BLD_BA_ACC 0x04 /* BA_ACC (basic accept) */ + /* * ISP I/O Register Set structure definitions. */ @@ -1726,9 +1867,8 @@ struct access_chip_rsp_84xx { /* LR Distance bit positions */ #define LR_DIST_NV_POS 2 +#define LR_DIST_NV_MASK 0xf #define LR_DIST_FW_POS 12 -#define LR_DIST_FW_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS) -#define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000) /* FAC semaphore defines */ #define FAC_SEMAPHORE_UNLOCK 0 @@ -1883,6 +2023,7 @@ struct nvram_81xx { * BIT 6-15 = Unused */ uint16_t enhanced_features; + uint16_t reserved_24[4]; /* Offset 416. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 2a64729a2bc5..1b93f5b4d77d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -31,7 +31,7 @@ extern int qla24xx_nvram_config(struct scsi_qla_host *); extern int qla81xx_nvram_config(struct scsi_qla_host *); extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); -extern void qla81xx_update_fw_options(scsi_qla_host_t *); + extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); @@ -109,7 +109,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*, void *, u8); int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); -int qla24xx_detect_sfp(scsi_qla_host_t *vha); +int qla24xx_detect_sfp(scsi_qla_host_t *); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); extern void qla28xx_get_aux_images(struct scsi_qla_host *, @@ -142,6 +142,8 @@ extern int qlport_down_retry; extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; +extern int ql2xrdpenable; +extern int ql2xsmartsan; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xiidmaenable; @@ -226,6 +228,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_post_relogin_work(struct scsi_qla_host *vha); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); +void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt); /* * Global Functions in qla_mid.c source file. @@ -354,6 +357,9 @@ extern int qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); extern int +qla24xx_get_port_database(scsi_qla_host_t *, u16, struct port_database_24xx *); + +extern int qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *); extern int @@ -452,6 +458,13 @@ extern int qla25xx_set_driver_version(scsi_qla_host_t *, char *); extern int +qla25xx_set_els_cmds_supported(scsi_qla_host_t *); + +extern int +qla24xx_get_buffer_credits(scsi_qla_host_t *, struct buffer_credit_24xx *, + dma_addr_t); + +extern int qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, uint16_t, uint16_t, uint16_t, uint16_t); @@ -552,6 +565,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *, uint32_t); extern irqreturn_t qla2xxx_msix_rsp_q(int irq, void *dev_id); +extern irqreturn_t +qla2xxx_msix_rsp_q_hs(int irq, void *dev_id); fc_port_t *qla2x00_find_fcport_by_loopid(scsi_qla_host_t *, uint16_t); fc_port_t *qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *, u8 *, u8); fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8); @@ -656,7 +671,7 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); -extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); +extern size_t qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, struct ct_sns_rsp *, const char *); extern void qla2x00_async_iocb_timeout(void *data); @@ -844,6 +859,7 @@ extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); extern int qla82xx_read_temperature(scsi_qla_host_t *); extern int qla8044_read_temperature(scsi_qla_host_t *); extern int qla2x00_read_sfp_dev(struct scsi_qla_host *, char *, int); +extern int ql26xx_led_config(scsi_qla_host_t *, uint16_t, uint16_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct bsg_job *); @@ -913,6 +929,7 @@ void qlt_remove_target_resources(struct qla_hw_data *); void qlt_clr_qp_table(struct scsi_qla_host *vha); void qlt_set_mode(struct scsi_qla_host *); int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); +extern void qla24xx_process_purex_list(struct purex_list *); /* nvme.c */ void qla_nvme_unregister_remote_port(struct fc_port *fcport); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index aaa4a5bbf2ff..42c3ad27f1cb 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -19,6 +19,8 @@ static int qla_async_rffid(scsi_qla_host_t *, port_id_t *, u8, u8); static int qla_async_rnnid(scsi_qla_host_t *, port_id_t *, u8*); static int qla_async_rsnn_nn(scsi_qla_host_t *); + + /** * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query. * @vha: HA context @@ -844,19 +846,18 @@ done: return rval; } -void +size_t qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn, size_t size) { struct qla_hw_data *ha = vha->hw; if (IS_QLAFX00(ha)) - snprintf(snn, size, "%s FW:v%s DVR:v%s", ha->model_number, - ha->mr.fw_version, qla2x00_version_str); - else - snprintf(snn, size, - "%s FW:v%d.%02d.%02d DVR:v%s", ha->model_number, - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, qla2x00_version_str); + return scnprintf(snn, size, "%s FW:v%s DVR:v%s", + ha->model_number, ha->mr.fw_version, qla2x00_version_str); + + return scnprintf(snn, size, "%s FW:v%d.%02d.%02d DVR:v%s", + ha->model_number, ha->fw_major_version, ha->fw_minor_version, + ha->fw_subminor_version, qla2x00_version_str); } /** @@ -1501,747 +1502,732 @@ qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd, return &p->p.req; } +static uint +qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha) +{ + if (IS_CNA_CAPABLE(ha)) + return FDMI_PORT_SPEED_10GB; + if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) { + uint speeds = 0; + + if (ha->max_supported_speed == 2) { + if (ha->min_supported_speed <= 6) + speeds |= FDMI_PORT_SPEED_64GB; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1) { + if (ha->min_supported_speed <= 5) + speeds |= FDMI_PORT_SPEED_32GB; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 4) + speeds |= FDMI_PORT_SPEED_16GB; + } + if (ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 3) + speeds |= FDMI_PORT_SPEED_8GB; + } + if (ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 2) + speeds |= FDMI_PORT_SPEED_4GB; + } + return speeds; + } + if (IS_QLA2031(ha)) + return FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB| + FDMI_PORT_SPEED_4GB; + if (IS_QLA25XX(ha)) + return FDMI_PORT_SPEED_8GB|FDMI_PORT_SPEED_4GB| + FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; + if (IS_QLA24XX_TYPE(ha)) + return FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_2GB| + FDMI_PORT_SPEED_1GB; + if (IS_QLA23XX(ha)) + return FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; + return FDMI_PORT_SPEED_1GB; +} +static uint +qla25xx_fdmi_port_speed_currently(struct qla_hw_data *ha) +{ + switch (ha->link_data_rate) { + case PORT_SPEED_1GB: + return FDMI_PORT_SPEED_1GB; + case PORT_SPEED_2GB: + return FDMI_PORT_SPEED_2GB; + case PORT_SPEED_4GB: + return FDMI_PORT_SPEED_4GB; + case PORT_SPEED_8GB: + return FDMI_PORT_SPEED_8GB; + case PORT_SPEED_10GB: + return FDMI_PORT_SPEED_10GB; + case PORT_SPEED_16GB: + return FDMI_PORT_SPEED_16GB; + case PORT_SPEED_32GB: + return FDMI_PORT_SPEED_32GB; + case PORT_SPEED_64GB: + return FDMI_PORT_SPEED_64GB; + default: + return FDMI_PORT_SPEED_UNKNOWN; + } +} + /** - * qla2x00_fdmi_rhba() - perform RHBA FDMI registration + * qla2x00_hba_attributes() perform HBA attributes registration * @vha: HA context + * @entries: number of entries to use + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ -static int -qla2x00_fdmi_rhba(scsi_qla_host_t *vha) +static unsigned long +qla2x00_hba_attributes(scsi_qla_host_t *vha, void *entries, + unsigned int callopt) { - int rval, alen; - uint32_t size, sn; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; - struct ct_fdmi_hba_attr *eiter; struct qla_hw_data *ha = vha->hw; - - /* Issue RHBA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, RHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba.entry_count = cpu_to_be32(1); - memcpy(ct_req->req.rhba.port_name, vha->port_name, WWN_SIZE); - size = 2 * WWN_SIZE + 4 + 4; - - /* Attributes */ - ct_req->req.rhba.attrs.count = - cpu_to_be32(FDMI_HBA_ATTR_COUNT); - entries = &ct_req->req; + struct init_cb_24xx *icb24 = (void *)ha->init_cb; + struct new_utsname *p_sysid = utsname(); + struct ct_fdmi_hba_attr *eiter; + uint16_t alen; + unsigned long size = 0; /* Nodename. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x2025, - "NodeName = %8phN.\n", eiter->a.node_name); - + memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); + alen = sizeof(eiter->a.node_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a0, + "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); /* Manufacturer. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); - alen = strlen(QLA2XXX_MANUFACTURER); - snprintf(eiter->a.manufacturer, sizeof(eiter->a.manufacturer), - "%s", "QLogic Corporation"); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2026, - "Manufacturer = %s.\n", eiter->a.manufacturer); - + alen = scnprintf( + eiter->a.manufacturer, sizeof(eiter->a.manufacturer), + "%s", "QLogic Corporation"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a1, + "MANUFACTURER = %s.\n", eiter->a.manufacturer); /* Serial number. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); - if (IS_FWI2_CAPABLE(ha)) - qla2xxx_get_vpd_field(vha, "SN", eiter->a.serial_num, - sizeof(eiter->a.serial_num)); - else { - sn = ((ha->serial0 & 0x1f) << 16) | + alen = 0; + if (IS_FWI2_CAPABLE(ha)) { + alen = qla2xxx_get_vpd_field(vha, "SN", + eiter->a.serial_num, sizeof(eiter->a.serial_num)); + } + if (!alen) { + uint32_t sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; - snprintf(eiter->a.serial_num, sizeof(eiter->a.serial_num), - "%c%05d", 'A' + sn / 100000, sn % 100000); + alen = scnprintf( + eiter->a.serial_num, sizeof(eiter->a.serial_num), + "%c%05d", 'A' + sn / 100000, sn % 100000); } - alen = strlen(eiter->a.serial_num); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2027, - "Serial no. = %s.\n", eiter->a.serial_num); - + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a2, + "SERIAL NUMBER = %s.\n", eiter->a.serial_num); /* Model name. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MODEL); - snprintf(eiter->a.model, sizeof(eiter->a.model), - "%s", ha->model_number); - alen = strlen(eiter->a.model); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2028, - "Model Name = %s.\n", eiter->a.model); - + alen = scnprintf( + eiter->a.model, sizeof(eiter->a.model), + "%s", ha->model_number); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a3, + "MODEL NAME = %s.\n", eiter->a.model); /* Model description. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - snprintf(eiter->a.model_desc, sizeof(eiter->a.model_desc), - "%s", ha->model_desc); - alen = strlen(eiter->a.model_desc); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2029, - "Model Desc = %s.\n", eiter->a.model_desc); - + alen = scnprintf( + eiter->a.model_desc, sizeof(eiter->a.model_desc), + "%s", ha->model_desc); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a4, + "MODEL DESCRIPTION = %s.\n", eiter->a.model_desc); /* Hardware version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - if (!IS_FWI2_CAPABLE(ha)) { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } else if (qla2xxx_get_vpd_field(vha, "MN", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else if (qla2xxx_get_vpd_field(vha, "EC", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); + alen = 0; + if (IS_FWI2_CAPABLE(ha)) { + if (!alen) { + alen = qla2xxx_get_vpd_field(vha, "MN", + eiter->a.hw_version, sizeof(eiter->a.hw_version)); + } + if (!alen) { + alen = qla2xxx_get_vpd_field(vha, "EC", + eiter->a.hw_version, sizeof(eiter->a.hw_version)); + } } - alen = strlen(eiter->a.hw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202a, - "Hardware ver = %s.\n", eiter->a.hw_version); - + if (!alen) { + alen = scnprintf( + eiter->a.hw_version, sizeof(eiter->a.hw_version), + "HW:%s", ha->adapter_id); + } + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a5, + "HARDWARE VERSION = %s.\n", eiter->a.hw_version); /* Driver version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); - snprintf(eiter->a.driver_version, sizeof(eiter->a.driver_version), - "%s", qla2x00_version_str); - alen = strlen(eiter->a.driver_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202b, - "Driver ver = %s.\n", eiter->a.driver_version); - + alen = scnprintf( + eiter->a.driver_version, sizeof(eiter->a.driver_version), + "%s", qla2x00_version_str); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a6, + "DRIVER VERSION = %s.\n", eiter->a.driver_version); /* Option ROM version. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); - snprintf(eiter->a.orom_version, sizeof(eiter->a.orom_version), - "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.orom_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha , 0x202c, - "Optrom vers = %s.\n", eiter->a.orom_version); + alen = scnprintf( + eiter->a.orom_version, sizeof(eiter->a.orom_version), + "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a7, + "OPTROM VERSION = %d.%02d.\n", + eiter->a.orom_version[1], eiter->a.orom_version[0]); /* Firmware version */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, sizeof(eiter->a.fw_version)); - alen = strlen(eiter->a.fw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202d, - "Firmware vers = %s.\n", eiter->a.fw_version); - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x202e, - "RHBA identifier = %8phN size=%d.\n", - ct_req->req.rhba.hba_identifier, size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2030, - "RHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && - ct_rsp->header.explanation_code == - CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x2034, - "HBA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x20ad, - "RHBA FDMI registration failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); - } - } else { - ql_dbg(ql_dbg_disc, vha, 0x2035, - "RHBA exiting normally.\n"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a8, + "FIRMWARE VERSION = %s.\n", eiter->a.fw_version); + if (callopt == CALLOPT_FDMI1) + goto done; + /* OS Name and Version */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_OS_NAME_AND_VERSION); + alen = 0; + if (p_sysid) { + alen = scnprintf( + eiter->a.os_version, sizeof(eiter->a.os_version), + "%s %s %s", + p_sysid->sysname, p_sysid->release, p_sysid->machine); } - - return rval; + if (!alen) { + alen = scnprintf( + eiter->a.os_version, sizeof(eiter->a.os_version), + "%s %s", + "Linux", fc_host_system_hostname(vha->host)); + } + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20a9, + "OS VERSION = %s.\n", eiter->a.os_version); + /* MAX CT Payload Length */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); + eiter->a.max_ct_len = cpu_to_be32(le16_to_cpu(IS_FWI2_CAPABLE(ha) ? + icb24->frame_payload_size : ha->init_cb->frame_payload_size)); + alen = sizeof(eiter->a.max_ct_len); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20aa, + "CT PAYLOAD LENGTH = 0x%x.\n", be32_to_cpu(eiter->a.max_ct_len)); + /* Node Sybolic Name */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_NODE_SYMBOLIC_NAME); + alen = qla2x00_get_sym_node_name(vha, eiter->a.sym_name, + sizeof(eiter->a.sym_name)); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ab, + "SYMBOLIC NAME = %s.\n", eiter->a.sym_name); + /* Vendor Specific information */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_SPECIFIC_INFO); + eiter->a.vendor_specific_info = cpu_to_be32(PCI_VENDOR_ID_QLOGIC); + alen = sizeof(eiter->a.vendor_specific_info); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ac, + "VENDOR SPECIFIC INFO = 0x%x.\n", + be32_to_cpu(eiter->a.vendor_specific_info)); + /* Num Ports */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_NUM_PORTS); + eiter->a.num_ports = cpu_to_be32(1); + alen = sizeof(eiter->a.num_ports); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ad, + "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); + /* Fabric Name */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_FABRIC_NAME); + memcpy(eiter->a.fabric_name, vha->fabric_node_name, + sizeof(eiter->a.fabric_name)); + alen = sizeof(eiter->a.fabric_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ae, + "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + /* BIOS Version */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_BOOT_BIOS_NAME); + alen = scnprintf( + eiter->a.bios_name, sizeof(eiter->a.bios_name), + "BIOS %d.%02d", ha->bios_revision[1], ha->bios_revision[0]); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20af, + "BIOS NAME = %s\n", eiter->a.bios_name); + /* Vendor Identifier */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_IDENTIFIER); + alen = scnprintf( + eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), + "%s", "QLGC"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20b0, + "VENDOR IDENTIFIER = %s.\n", eiter->a.vendor_identifier); +done: + return size; } /** - * qla2x00_fdmi_rpa() - perform RPA registration + * qla2x00_port_attributes() perform Port attributes registration * @vha: HA context + * @entries: number of entries to use + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ -static int -qla2x00_fdmi_rpa(scsi_qla_host_t *vha) +static unsigned long +qla2x00_port_attributes(scsi_qla_host_t *vha, void *entries, + unsigned int callopt) { - int rval, alen; - uint32_t size; struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; + struct init_cb_24xx *icb24 = (void *)ha->init_cb; + struct new_utsname *p_sysid = utsname(); + char *hostname = p_sysid ? + p_sysid->nodename : fc_host_system_hostname(vha->host); struct ct_fdmi_port_attr *eiter; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; - struct new_utsname *p_sysid = NULL; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, - RPA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rpa.port_name, vha->port_name, WWN_SIZE); - size = WWN_SIZE + 4; - - /* Attributes */ - ct_req->req.rpa.attrs.count = cpu_to_be32(FDMI_PORT_ATTR_COUNT); - entries = &ct_req->req; + uint16_t alen; + unsigned long size = 0; /* FC4 types. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPES); - eiter->len = cpu_to_be16(4 + 32); + eiter->a.fc4_types[0] = 0x00; + eiter->a.fc4_types[1] = 0x00; eiter->a.fc4_types[2] = 0x01; - size += 4 + 32; - - ql_dbg(ql_dbg_disc, vha, 0x2039, - "FC4_TYPES=%02x %02x.\n", - eiter->a.fc4_types[2], - eiter->a.fc4_types[1]); - + eiter->a.fc4_types[3] = 0x00; + alen = sizeof(eiter->a.fc4_types); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c0, + "FC4 TYPES = %016llx.\n", *(uint64_t *)eiter->a.fc4_types); + if (vha->flags.nvme_enabled) { + eiter->a.fc4_types[6] = 1; /* NVMe type 28h */ + ql_dbg(ql_dbg_disc, vha, 0x211f, + "NVME FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", + eiter->a.fc4_types[6]); + } /* Supported speed. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - if (IS_CNA_CAPABLE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_32GB| - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB); - else if (IS_QLA2031(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB); - else if (IS_QLA25XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA24XX_TYPE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA23XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_1GB); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203a, - "Supported_Speed=%x.\n", eiter->a.sup_speed); - + eiter->a.sup_speed = cpu_to_be32( + qla25xx_fdmi_port_speed_capability(ha)); + alen = sizeof(eiter->a.sup_speed); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c1, + "SUPPORTED SPEED = %x.\n", be32_to_cpu(eiter->a.sup_speed)); /* Current speed. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_CURRENT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_1GB); - break; - case PORT_SPEED_2GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_2GB); - break; - case PORT_SPEED_4GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_4GB); - break; - case PORT_SPEED_8GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_8GB); - break; - case PORT_SPEED_10GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_10GB); - break; - case PORT_SPEED_16GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_16GB); - break; - case PORT_SPEED_32GB: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_32GB); - break; - default: - eiter->a.cur_speed = - cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); - break; - } - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203b, - "Current_Speed=%x.\n", eiter->a.cur_speed); - + eiter->a.cur_speed = cpu_to_be32( + qla25xx_fdmi_port_speed_currently(ha)); + alen = sizeof(eiter->a.cur_speed); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c2, + "CURRENT SPEED = %x.\n", be32_to_cpu(eiter->a.cur_speed)); /* Max frame size. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); - eiter->len = cpu_to_be16(4 + 4); - eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size) : - le16_to_cpu(ha->init_cb->frame_payload_size); - eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203c, - "Max_Frame_Size=%x.\n", eiter->a.max_frame_size); - + eiter->a.max_frame_size = cpu_to_be32(le16_to_cpu(IS_FWI2_CAPABLE(ha) ? + icb24->frame_payload_size : ha->init_cb->frame_payload_size)); + alen = sizeof(eiter->a.max_frame_size); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c3, + "MAX FRAME SIZE = %x.\n", be32_to_cpu(eiter->a.max_frame_size)); /* OS device name. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - snprintf(eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), - "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); - alen = strlen(eiter->a.os_dev_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x204b, - "OS_Device_Name=%s.\n", eiter->a.os_dev_name); - + alen = scnprintf( + eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), + "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c4, + "OS DEVICE NAME = %s.\n", eiter->a.os_dev_name); /* Hostname. */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", p_sysid->nodename); - } else { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", fc_host_system_hostname(vha->host)); - } - alen = strlen(eiter->a.host_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x203d, "HostName=%s.\n", eiter->a.host_name); - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x203e, - "RPA portname %016llx, size = %d.\n", - wwn_to_u64(ct_req->req.rpa.port_name), size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2040, - "RPA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && - ct_rsp->header.explanation_code == - CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20cd, - "RPA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } - - } else { - ql_dbg(ql_dbg_disc, vha, 0x2041, - "RPA exiting normally.\n"); - } - - return rval; -} - -/** - * qla2x00_fdmiv2_rhba() - perform RHBA FDMI v2 registration - * @vha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) -{ - int rval, alen; - uint32_t size, sn; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - void *entries; - struct ct_fdmiv2_hba_attr *eiter; - struct qla_hw_data *ha = vha->hw; - struct new_utsname *p_sysid = NULL; - - /* Issue RHBA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, - RHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rhba2.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba2.entry_count = cpu_to_be32(1); - memcpy(ct_req->req.rhba2.port_name, vha->port_name, WWN_SIZE); - size = 2 * WWN_SIZE + 4 + 4; + if (!*hostname || !strncmp(hostname, "(none)", 6)) + hostname = "Linux-default"; + alen = scnprintf( + eiter->a.host_name, sizeof(eiter->a.host_name), + "%s", hostname); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c5, + "HOSTNAME = %s.\n", eiter->a.host_name); - /* Attributes */ - ct_req->req.rhba2.attrs.count = cpu_to_be32(FDMIV2_HBA_ATTR_COUNT); - entries = &ct_req->req; + if (callopt == CALLOPT_FDMI1) + goto done; - /* Nodename. */ + /* Node Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x207d, - "NodeName = %016llx.\n", wwn_to_u64(eiter->a.node_name)); + eiter->type = cpu_to_be16(FDMI_PORT_NODE_NAME); + memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); + alen = sizeof(eiter->a.node_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c6, + "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); - /* Manufacturer. */ + /* Port Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); - snprintf(eiter->a.manufacturer, sizeof(eiter->a.manufacturer), - "%s", "QLogic Corporation"); - eiter->a.manufacturer[strlen("QLogic Corporation")] = '\0'; - alen = strlen(eiter->a.manufacturer); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a5, - "Manufacturer = %s.\n", eiter->a.manufacturer); + eiter->type = cpu_to_be16(FDMI_PORT_NAME); + memcpy(eiter->a.port_name, vha->port_name, sizeof(eiter->a.port_name)); + alen = sizeof(eiter->a.port_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c7, + "PORTNAME = %016llx.\n", wwn_to_u64(eiter->a.port_name)); - /* Serial number. */ + /* Port Symbolic Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); - if (IS_FWI2_CAPABLE(ha)) - qla2xxx_get_vpd_field(vha, "SN", eiter->a.serial_num, - sizeof(eiter->a.serial_num)); - else { - sn = ((ha->serial0 & 0x1f) << 16) | - (ha->serial2 << 8) | ha->serial1; - snprintf(eiter->a.serial_num, sizeof(eiter->a.serial_num), - "%c%05d", 'A' + sn / 100000, sn % 100000); - } - alen = strlen(eiter->a.serial_num); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a6, - "Serial no. = %s.\n", eiter->a.serial_num); + eiter->type = cpu_to_be16(FDMI_PORT_SYM_NAME); + alen = qla2x00_get_sym_node_name(vha, eiter->a.port_sym_name, + sizeof(eiter->a.port_sym_name)); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c8, + "PORT SYMBOLIC NAME = %s\n", eiter->a.port_sym_name); - /* Model name. */ + /* Port Type */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MODEL); - snprintf(eiter->a.model, sizeof(eiter->a.model), - "%s", ha->model_number); - alen = strlen(eiter->a.model); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a7, - "Model Name = %s.\n", eiter->a.model); - - /* Model description. */ + eiter->type = cpu_to_be16(FDMI_PORT_TYPE); + eiter->a.port_type = cpu_to_be32(NS_NX_PORT_TYPE); + alen = sizeof(eiter->a.port_type); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20c9, + "PORT TYPE = %x.\n", be32_to_cpu(eiter->a.port_type)); + + /* Supported Class of Service */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - snprintf(eiter->a.model_desc, sizeof(eiter->a.model_desc), - "%s", ha->model_desc); - alen = strlen(eiter->a.model_desc); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a8, - "Model Desc = %s.\n", eiter->a.model_desc); + eiter->type = cpu_to_be16(FDMI_PORT_SUPP_COS); + eiter->a.port_supported_cos = cpu_to_be32(FC_CLASS_3); + alen = sizeof(eiter->a.port_supported_cos); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ca, + "SUPPORTED COS = %08x\n", be32_to_cpu(eiter->a.port_supported_cos)); - /* Hardware version. */ + /* Port Fabric Name */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - if (!IS_FWI2_CAPABLE(ha)) { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } else if (qla2xxx_get_vpd_field(vha, "MN", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else if (qla2xxx_get_vpd_field(vha, "EC", eiter->a.hw_version, - sizeof(eiter->a.hw_version))) { - ; - } else { - snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), - "HW:%s", ha->adapter_id); - } - alen = strlen(eiter->a.hw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20a9, - "Hardware ver = %s.\n", eiter->a.hw_version); + eiter->type = cpu_to_be16(FDMI_PORT_FABRIC_NAME); + memcpy(eiter->a.fabric_name, vha->fabric_node_name, + sizeof(eiter->a.fabric_name)); + alen = sizeof(eiter->a.fabric_name); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cb, + "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); - /* Driver version. */ + /* FC4_type */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); - snprintf(eiter->a.driver_version, sizeof(eiter->a.driver_version), - "%s", qla2x00_version_str); - alen = strlen(eiter->a.driver_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20aa, - "Driver ver = %s.\n", eiter->a.driver_version); + eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPE); + eiter->a.port_fc4_type[0] = 0x00; + eiter->a.port_fc4_type[1] = 0x00; + eiter->a.port_fc4_type[2] = 0x01; + eiter->a.port_fc4_type[3] = 0x00; + alen = sizeof(eiter->a.port_fc4_type); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cc, + "PORT ACTIVE FC4 TYPE = %016llx.\n", + *(uint64_t *)eiter->a.port_fc4_type); - /* Option ROM version. */ + /* Port State */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); - snprintf(eiter->a.orom_version, sizeof(eiter->a.orom_version), - "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.orom_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha , 0x20ab, - "Optrom version = %d.%02d.\n", eiter->a.orom_version[1], - eiter->a.orom_version[0]); + eiter->type = cpu_to_be16(FDMI_PORT_STATE); + eiter->a.port_state = cpu_to_be32(2); + alen = sizeof(eiter->a.port_state); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cd, + "PORT_STATE = %x.\n", be32_to_cpu(eiter->a.port_state)); - /* Firmware version */ + /* Number of Ports */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); - ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, - sizeof(eiter->a.fw_version)); - alen = strlen(eiter->a.fw_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20ac, - "Firmware vers = %s.\n", eiter->a.fw_version); - - /* OS Name and Version */ + eiter->type = cpu_to_be16(FDMI_PORT_COUNT); + eiter->a.num_ports = cpu_to_be32(1); + alen = sizeof(eiter->a.num_ports); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20ce, + "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); + + /* Port Identifier */ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_OS_NAME_AND_VERSION); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.os_version, sizeof(eiter->a.os_version), - "%s %s %s", - p_sysid->sysname, p_sysid->release, p_sysid->version); - } else { - snprintf(eiter->a.os_version, sizeof(eiter->a.os_version), - "%s %s", "Linux", fc_host_system_hostname(vha->host)); - } - alen = strlen(eiter->a.os_version); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20ae, - "OS Name and Version = %s.\n", eiter->a.os_version); + eiter->type = cpu_to_be16(FDMI_PORT_IDENTIFIER); + eiter->a.port_id = cpu_to_be32(vha->d_id.b24); + alen = sizeof(eiter->a.port_id); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20cf, + "PORT ID = %x.\n", be32_to_cpu(eiter->a.port_id)); + + if (callopt == CALLOPT_FDMI2 || !ql2xsmartsan) + goto done; - /* MAX CT Payload Length */ + /* Smart SAN Service Category (Populate Smart SAN Initiator)*/ eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); - eiter->a.max_ct_len = cpu_to_be32(ha->frame_payload_size); - eiter->a.max_ct_len = cpu_to_be32(eiter->a.max_ct_len); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_SERVICE); + alen = scnprintf( + eiter->a.smartsan_service, sizeof(eiter->a.smartsan_service), + "%s", "Smart SAN Initiator"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d0, + "SMARTSAN SERVICE CATEGORY = %s.\n", eiter->a.smartsan_service); + + /* Smart SAN GUID (NWWN+PWWN) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_GUID); + memcpy(eiter->a.smartsan_guid, vha->node_name, WWN_SIZE); + memcpy(eiter->a.smartsan_guid + WWN_SIZE, vha->port_name, WWN_SIZE); + alen = sizeof(eiter->a.smartsan_guid); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d1, + "Smart SAN GUID = %016llx-%016llx\n", + wwn_to_u64(eiter->a.smartsan_guid), + wwn_to_u64(eiter->a.smartsan_guid + WWN_SIZE)); + + /* Smart SAN Version (populate "Smart SAN Version 1.0") */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_VERSION); + alen = scnprintf( + eiter->a.smartsan_version, sizeof(eiter->a.smartsan_version), + "%s", "Smart SAN Version 2.0"); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d2, + "SMARTSAN VERSION = %s\n", eiter->a.smartsan_version); + + /* Smart SAN Product Name (Specify Adapter Model No) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_PROD_NAME); + alen = scnprintf(eiter->a.smartsan_prod_name, + sizeof(eiter->a.smartsan_prod_name), + "ISP%04x", ha->pdev->device); + alen += FDMI_ATTR_ALIGNMENT(alen); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "SMARTSAN PRODUCT NAME = %s\n", eiter->a.smartsan_prod_name); + + /* Smart SAN Port Info (specify: 1=Physical, 2=NPIV, 3=SRIOV) */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_PORT_INFO); + eiter->a.smartsan_port_info = cpu_to_be32(vha->vp_idx ? 2 : 1); + alen = sizeof(eiter->a.smartsan_port_info); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d4, + "SMARTSAN PORT INFO = %x\n", eiter->a.smartsan_port_info); + + /* Smart SAN Security Support */ + eiter = entries + size; + eiter->type = cpu_to_be16(FDMI_SMARTSAN_SECURITY_SUPPORT); + eiter->a.smartsan_security_support = cpu_to_be32(1); + alen = sizeof(eiter->a.smartsan_security_support); + alen += FDMI_ATTR_TYPELEN(eiter); + eiter->len = cpu_to_be16(alen); + size += alen; + ql_dbg(ql_dbg_disc, vha, 0x20d6, + "SMARTSAN SECURITY SUPPORT = %d\n", + be32_to_cpu(eiter->a.smartsan_security_support)); - ql_dbg(ql_dbg_disc, vha, 0x20af, - "CT Payload Length = 0x%x.\n", eiter->a.max_ct_len); +done: + return size; +} - /* Node Sybolic Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NODE_SYMBOLIC_NAME); - qla2x00_get_sym_node_name(vha, eiter->a.sym_name, - sizeof(eiter->a.sym_name)); - alen = strlen(eiter->a.sym_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; +/** + * qla2x00_fdmi_rhba() - perform RHBA FDMI registration + * @vha: HA context + * @callopt: Option to issue FDMI registration + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rhba(scsi_qla_host_t *vha, unsigned int callopt) +{ + struct qla_hw_data *ha = vha->hw; + unsigned long size = 0; + unsigned int rval, count; + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + void *entries; - ql_dbg(ql_dbg_disc, vha, 0x20b0, - "Symbolic Name = %s.\n", eiter->a.sym_name); + count = callopt != CALLOPT_FDMI1 ? + FDMI2_HBA_ATTR_COUNT : FDMI1_HBA_ATTR_COUNT; - /* Vendor Id */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_ID); - eiter->a.vendor_id = cpu_to_be32(0x1077); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + size = RHBA_RSP_SIZE; - ql_dbg(ql_dbg_disc, vha, 0x20b1, - "Vendor Id = %x.\n", eiter->a.vendor_id); + ql_dbg(ql_dbg_disc, vha, 0x20e0, + "RHBA (callopt=%x count=%u size=%lu).\n", callopt, count, size); - /* Num Ports */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_NUM_PORTS); - eiter->a.num_ports = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); - ql_dbg(ql_dbg_disc, vha, 0x20b2, - "Port Num = %x.\n", eiter->a.num_ports); + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, size); + ct_rsp = &ha->ct_sns->p.rsp; - /* Fabric Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_FABRIC_NAME); - memcpy(eiter->a.fabric_name, vha->fabric_node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; + /* Prepare FDMI command entries */ + memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, + sizeof(ct_req->req.rhba.hba_identifier)); + size += sizeof(ct_req->req.rhba.hba_identifier); - ql_dbg(ql_dbg_disc, vha, 0x20b3, - "Fabric Name = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + ct_req->req.rhba.entry_count = cpu_to_be32(1); + size += sizeof(ct_req->req.rhba.entry_count); - /* BIOS Version */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_BOOT_BIOS_NAME); - snprintf(eiter->a.bios_name, sizeof(eiter->a.bios_name), - "BIOS %d.%02d", ha->bios_revision[1], ha->bios_revision[0]); - alen = strlen(eiter->a.bios_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; + memcpy(ct_req->req.rhba.port_name, vha->port_name, + sizeof(ct_req->req.rhba.port_name)); + size += sizeof(ct_req->req.rhba.port_name); - ql_dbg(ql_dbg_disc, vha, 0x20b4, - "BIOS Name = %s\n", eiter->a.bios_name); + /* Attribute count */ + ct_req->req.rhba.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rhba.attrs.count); - /* Vendor Identifier */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_HBA_TYPE_VENDOR_IDENTIFIER); - snprintf(eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), - "%s", "QLGC"); - alen = strlen(eiter->a.vendor_identifier); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; + /* Attribute block */ + entries = &ct_req->req.rhba.attrs.entry; - ql_dbg(ql_dbg_disc, vha, 0x201b, - "Vendor Identifier = %s.\n", eiter->a.vendor_identifier); + size += qla2x00_hba_attributes(vha, entries, callopt); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); - ql_dbg(ql_dbg_disc, vha, 0x20b5, - "RHBA identifier = %016llx.\n", - wwn_to_u64(ct_req->req.rhba2.hba_identifier)); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20b6, + ql_dbg(ql_dbg_disc, vha, 0x20e1, + "RHBA %016llx %016llx.\n", + wwn_to_u64(ct_req->req.rhba.hba_identifier), + wwn_to_u64(ct_req->req.rhba.port_name)); + + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20e2, entries, size); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x20b7, - "RHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20e3, + "RHBA iocb failed (%d).\n", rval); + return rval; + } + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA"); + if (rval) { if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && ct_rsp->header.explanation_code == CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20b8, - "HBA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2016, - "RHBA FDMI v2 failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); + ql_dbg(ql_dbg_disc, vha, 0x20e4, + "RHBA already registered.\n"); + return QLA_ALREADY_REGISTERED; } - } else { - ql_dbg(ql_dbg_disc, vha, 0x20b9, - "RHBA FDMI V2 exiting normally.\n"); + + ql_dbg(ql_dbg_disc, vha, 0x20e5, + "RHBA failed, CT Reason %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } + ql_dbg(ql_dbg_disc, vha, 0x20e6, "RHBA exiting normally.\n"); return rval; } -/** - * qla2x00_fdmi_dhba() - - * @vha: HA context - * - * Returns 0 on success. - */ + static int qla2x00_fdmi_dhba(scsi_qla_host_t *vha) { @@ -2250,22 +2236,17 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha) ms_iocb_entry_t *ms_pkt; struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; - /* Issue RPA */ /* Prepare common MS IOCB */ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, DHBA_REQ_SIZE, DHBA_RSP_SIZE); - /* Prepare CT request */ ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, DHBA_CMD, DHBA_RSP_SIZE); ct_rsp = &ha->ct_sns->p.rsp; - /* Prepare FDMI command arguments -- portname. */ memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE); - ql_dbg(ql_dbg_disc, vha, 0x2036, "DHBA portname = %8phN.\n", ct_req->req.dhba.port_name); - /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, sizeof(ms_iocb_entry_t)); @@ -2280,337 +2261,178 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha) ql_dbg(ql_dbg_disc, vha, 0x2038, "DHBA exiting normally.\n"); } - return rval; } /** - * qla2x00_fdmiv2_rpa() - + * qla2x00_fdmi_rprt() perform RPRT registration * @vha: HA context + * @callopt: Option to issue extended or standard FDMI + * command parameter * * Returns 0 on success. */ static int -qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) +qla2x00_fdmi_rprt(scsi_qla_host_t *vha, int callopt) { - int rval, alen; - uint32_t size; + struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); struct qla_hw_data *ha = vha->hw; + ulong size = 0; + uint rval, count; ms_iocb_entry_t *ms_pkt; struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; void *entries; - struct ct_fdmiv2_port_attr *eiter; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; - struct new_utsname *p_sysid = NULL; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE); - + count = callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? + FDMI2_SMARTSAN_PORT_ATTR_COUNT : + callopt != CALLOPT_FDMI1 ? + FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; + + size = RPRT_RSP_SIZE; + ql_dbg(ql_dbg_disc, vha, 0x20e8, + "RPRT (callopt=%x count=%u size=%lu).\n", callopt, count, size); + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, RPA_RSP_SIZE); + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPRT_CMD, size); ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rpa2.port_name, vha->port_name, WWN_SIZE); - size = WWN_SIZE + 4; - - /* Attributes */ - ct_req->req.rpa2.attrs.count = cpu_to_be32(FDMIV2_PORT_ATTR_COUNT); - entries = &ct_req->req; - - /* FC4 types. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPES); - eiter->len = cpu_to_be16(4 + 32); - eiter->a.fc4_types[2] = 0x01; - size += 4 + 32; - - ql_dbg(ql_dbg_disc, vha, 0x20ba, - "FC4_TYPES=%02x %02x.\n", - eiter->a.fc4_types[2], - eiter->a.fc4_types[1]); - - if (vha->flags.nvme_enabled) { - eiter->a.fc4_types[6] = 1; /* NVMe type 28h */ - ql_dbg(ql_dbg_disc, vha, 0x211f, - "NVME FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", - eiter->a.fc4_types[6]); - } - - /* Supported speed. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - if (IS_CNA_CAPABLE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_32GB| - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB); - else if (IS_QLA2031(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_16GB| - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB); - else if (IS_QLA25XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_8GB| - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA24XX_TYPE(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_4GB| - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else if (IS_QLA23XX(ha)) - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_1GB); - else - eiter->a.sup_speed = cpu_to_be32( - FDMI_PORT_SPEED_1GB); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20bb, - "Supported Port Speed = %x.\n", eiter->a.sup_speed); - - /* Current speed. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_CURRENT_SPEED); - eiter->len = cpu_to_be16(4 + 4); - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_1GB); - break; - case PORT_SPEED_2GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_2GB); - break; - case PORT_SPEED_4GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_4GB); - break; - case PORT_SPEED_8GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_8GB); - break; - case PORT_SPEED_10GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_10GB); - break; - case PORT_SPEED_16GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_16GB); - break; - case PORT_SPEED_32GB: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_32GB); - break; - default: - eiter->a.cur_speed = cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); - break; + /* Prepare FDMI command entries */ + memcpy(ct_req->req.rprt.hba_identifier, base_vha->port_name, + sizeof(ct_req->req.rprt.hba_identifier)); + size += sizeof(ct_req->req.rprt.hba_identifier); + memcpy(ct_req->req.rprt.port_name, vha->port_name, + sizeof(ct_req->req.rprt.port_name)); + size += sizeof(ct_req->req.rprt.port_name); + /* Attribute count */ + ct_req->req.rprt.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rprt.attrs.count); + /* Attribute block */ + entries = ct_req->req.rprt.attrs.entry; + size += qla2x00_port_attributes(vha, entries, callopt); + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(vha, size + 16); + ql_dbg(ql_dbg_disc, vha, 0x20e9, + "RPRT %016llx %016llx.\n", + wwn_to_u64(ct_req->req.rprt.port_name), + wwn_to_u64(ct_req->req.rprt.port_name)); + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20ea, + entries, size); + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20eb, + "RPRT iocb failed (%d).\n", rval); + return rval; } - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x2017, - "Current_Speed = %x.\n", eiter->a.cur_speed); - - /* Max frame size. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); - eiter->len = cpu_to_be16(4 + 4); - eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size) : - le16_to_cpu(ha->init_cb->frame_payload_size); - eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20bc, - "Max_Frame_Size = %x.\n", eiter->a.max_frame_size); - - /* OS device name. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - alen = strlen(QLA2XXX_DRIVER_NAME); - snprintf(eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), - "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20be, - "OS_Device_Name = %s.\n", eiter->a.os_dev_name); + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPRT"); + if (rval) { + if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && + ct_rsp->header.explanation_code == + CT_EXPL_ALREADY_REGISTERED) { + ql_dbg(ql_dbg_disc, vha, 0x20ec, + "RPRT already registered.\n"); + return QLA_ALREADY_REGISTERED; + } - /* Hostname. */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); - p_sysid = utsname(); - if (p_sysid) { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", p_sysid->nodename); - } else { - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", fc_host_system_hostname(vha->host)); + ql_dbg(ql_dbg_disc, vha, 0x20ed, + "RPRT failed, CT Reason code: %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } - alen = strlen(eiter->a.host_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x201a, - "HostName=%s.\n", eiter->a.host_name); - - /* Node Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_NODE_NAME); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x20c0, - "Node Name = %016llx.\n", wwn_to_u64(eiter->a.node_name)); - - /* Port Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_NAME); - memcpy(eiter->a.port_name, vha->port_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x20c1, - "Port Name = %016llx.\n", wwn_to_u64(eiter->a.port_name)); - - /* Port Symbolic Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_SYM_NAME); - qla2x00_get_sym_node_name(vha, eiter->a.port_sym_name, - sizeof(eiter->a.port_sym_name)); - alen = strlen(eiter->a.port_sym_name); - alen += 4 - (alen & 3); - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x20c2, - "port symbolic name = %s\n", eiter->a.port_sym_name); - - /* Port Type */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_TYPE); - eiter->a.port_type = cpu_to_be32(NS_NX_PORT_TYPE); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c3, - "Port Type = %x.\n", eiter->a.port_type); - - /* Class of Service */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_SUPP_COS); - eiter->a.port_supported_cos = cpu_to_be32(FC_CLASS_3); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c4, - "Supported COS = %08x\n", eiter->a.port_supported_cos); + ql_dbg(ql_dbg_disc, vha, 0x20ee, "RPRT exiting normally.\n"); + return rval; +} - /* Port Fabric Name */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FABRIC_NAME); - memcpy(eiter->a.fabric_name, vha->fabric_node_name, WWN_SIZE); - eiter->len = cpu_to_be16(4 + WWN_SIZE); - size += 4 + WWN_SIZE; +/** + * qla2x00_fdmi_rpa() - perform RPA registration + * @vha: HA context + * @callopt: Option to issue FDMI registration + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rpa(scsi_qla_host_t *vha, uint callopt) +{ + struct qla_hw_data *ha = vha->hw; + ulong size = 0; + uint rval, count; + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + void *entries; - ql_dbg(ql_dbg_disc, vha, 0x20c5, - "Fabric Name = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); + count = + callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? + FDMI2_SMARTSAN_PORT_ATTR_COUNT : + callopt != CALLOPT_FDMI1 ? + FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; - /* FC4_type */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPE); - eiter->a.port_fc4_type[0] = 0; - eiter->a.port_fc4_type[1] = 0; - eiter->a.port_fc4_type[2] = 1; - eiter->a.port_fc4_type[3] = 0; - eiter->len = cpu_to_be16(4 + 32); - size += 4 + 32; + size = + callopt != CALLOPT_FDMI1 ? + SMARTSAN_RPA_RSP_SIZE : RPA_RSP_SIZE; - ql_dbg(ql_dbg_disc, vha, 0x20c6, - "Port Active FC4 Type = %02x %02x.\n", - eiter->a.port_fc4_type[2], eiter->a.port_fc4_type[1]); + ql_dbg(ql_dbg_disc, vha, 0x20f0, + "RPA (callopt=%x count=%u size=%lu).\n", callopt, count, size); - if (vha->flags.nvme_enabled) { - eiter->a.port_fc4_type[4] = 0; - eiter->a.port_fc4_type[5] = 0; - eiter->a.port_fc4_type[6] = 1; /* NVMe type 28h */ - ql_dbg(ql_dbg_disc, vha, 0x2120, - "NVME Port Active FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", - eiter->a.port_fc4_type[6]); - } + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); - /* Port State */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_STATE); - eiter->a.port_state = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, size); + ct_rsp = &ha->ct_sns->p.rsp; - ql_dbg(ql_dbg_disc, vha, 0x20c7, - "Port State = %x.\n", eiter->a.port_state); + /* Prepare FDMI command entries. */ + memcpy(ct_req->req.rpa.port_name, vha->port_name, + sizeof(ct_req->req.rpa.port_name)); + size += sizeof(ct_req->req.rpa.port_name); - /* Number of Ports */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_COUNT); - eiter->a.num_ports = cpu_to_be32(1); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x20c8, - "Number of ports = %x.\n", eiter->a.num_ports); + /* Attribute count */ + ct_req->req.rpa.attrs.count = cpu_to_be32(count); + size += sizeof(ct_req->req.rpa.attrs.count); - /* Port Id */ - eiter = entries + size; - eiter->type = cpu_to_be16(FDMI_PORT_ID); - eiter->a.port_id = cpu_to_be32(vha->d_id.b24); - eiter->len = cpu_to_be16(4 + 4); - size += 4 + 4; + /* Attribute block */ + entries = ct_req->req.rpa.attrs.entry; - ql_dbg(ql_dbg_disc, vha, 0x201c, - "Port Id = %x.\n", eiter->a.port_id); + size += qla2x00_port_attributes(vha, entries, callopt); /* Update MS request size. */ qla2x00_update_ms_fdmi_iocb(vha, size + 16); - ql_dbg(ql_dbg_disc, vha, 0x2018, - "RPA portname= %8phN size=%d.\n", ct_req->req.rpa.port_name, size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20ca, + ql_dbg(ql_dbg_disc, vha, 0x20f1, + "RPA %016llx.\n", wwn_to_u64(ct_req->req.rpa.port_name)); + + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20f2, entries, size); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x20cb, - "RPA FDMI v2 issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; + sizeof(*ha->ms_iocb)); + if (rval) { + ql_dbg(ql_dbg_disc, vha, 0x20f3, + "RPA iocb failed (%d).\n", rval); + return rval; + } + + rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA"); + if (rval) { if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && ct_rsp->header.explanation_code == CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x20ce, - "RPA FDMI v2 already registered\n"); - rval = QLA_ALREADY_REGISTERED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2020, - "RPA FDMI v2 failed, CT Reason code: 0x%x, CT Explanation 0x%x\n", - ct_rsp->header.reason_code, - ct_rsp->header.explanation_code); + ql_dbg(ql_dbg_disc, vha, 0x20f4, + "RPA already registered.\n"); + return QLA_ALREADY_REGISTERED; } - } else { - ql_dbg(ql_dbg_disc, vha, 0x20cc, - "RPA FDMI V2 exiting normally.\n"); + + ql_dbg(ql_dbg_disc, vha, 0x20f5, + "RPA failed, CT Reason code: %#x, CT Explanation %#x\n", + ct_rsp->header.reason_code, + ct_rsp->header.explanation_code); + return rval; } + ql_dbg(ql_dbg_disc, vha, 0x20f6, "RPA exiting normally.\n"); return rval; } @@ -2623,18 +2445,31 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) int qla2x00_fdmi_register(scsi_qla_host_t *vha) { - int rval = QLA_FUNCTION_FAILED; + int rval = QLA_SUCCESS; struct qla_hw_data *ha = vha->hw; if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLAFX00(ha)) - return QLA_FUNCTION_FAILED; + return rval; rval = qla2x00_mgmt_svr_login(vha); if (rval) return rval; - rval = qla2x00_fdmiv2_rhba(vha); + /* For npiv/vport send rprt only */ + if (vha->vp_idx) { + if (ql2xsmartsan) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2_SMARTSAN); + if (rval || !ql2xsmartsan) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2); + if (rval) + rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI1); + + return rval; + } + + /* Try fdmi2 first, if fails then try fdmi1 */ + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); if (rval) { if (rval != QLA_ALREADY_REGISTERED) goto try_fdmi; @@ -2643,18 +2478,22 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha) if (rval) goto try_fdmi; - rval = qla2x00_fdmiv2_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); if (rval) goto try_fdmi; } - rval = qla2x00_fdmiv2_rpa(vha); + + if (ql2xsmartsan) + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2_SMARTSAN); + if (rval || !ql2xsmartsan) + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2); if (rval) goto try_fdmi; - goto out; + return rval; try_fdmi: - rval = qla2x00_fdmi_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); if (rval) { if (rval != QLA_ALREADY_REGISTERED) return rval; @@ -2663,12 +2502,13 @@ try_fdmi: if (rval) return rval; - rval = qla2x00_fdmi_rhba(vha); + rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); if (rval) return rval; } - rval = qla2x00_fdmi_rpa(vha); -out: + + rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI1); + return rval; } @@ -2893,7 +2733,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) for (i = 0; i < ha->max_fibre_devices; i++) { /* Set default FC4 Type as UNKNOWN so the default is to * Process this port */ - list[i].fc4_type = FC4_TYPE_UNKNOWN; + list[i].fc4_type = 0; /* Do not attempt GFF_ID if we are not FWI_2 capable */ if (!IS_FWI2_CAPABLE(ha)) @@ -3243,7 +3083,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) "%s %d %8phC post new sess\n", __func__, __LINE__, ea->port_name); qla24xx_post_newsess_work(vha, &ea->id, - ea->port_name, NULL, NULL, FC4_TYPE_UNKNOWN); + ea->port_name, NULL, NULL, 0); } } } @@ -3647,6 +3487,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) continue; fcport->scan_state = QLA_FCPORT_FOUND; + fcport->last_rscn_gen = fcport->rscn_gen; found = true; /* * If device was not a fabric device before. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9e6b56527b25..5b2deaa730bf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1043,7 +1043,7 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res) __func__, __LINE__, (u8 *)&wwn, id.b24); wwnn = wwn_to_u64(e->node_name); qla24xx_post_newsess_work(vha, &id, (u8 *)&wwn, - (u8 *)&wwnn, NULL, FC4_TYPE_UNKNOWN); + (u8 *)&wwnn, NULL, 0); } } @@ -2219,10 +2219,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) /* Check for secure flash support */ if (IS_QLA28XX(ha)) { - if (RD_REG_DWORD(®->mailbox12) & BIT_0) { - ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n"); + if (RD_REG_DWORD(®->mailbox12) & BIT_0) ha->flags.secure_adapter = 1; - } + ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n", + (ha->flags.secure_adapter) ? "Yes" : "No"); } @@ -2270,6 +2270,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init, vha, 0x0078, "Verifying loaded RISC code...\n"); + /* If smartsan enabled then require fdmi and rdp enabled */ + if (ql2xsmartsan) { + ql2xfdmienable = 1; + ql2xrdpenable = 1; + } + if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) { rval = ha->isp_ops->chip_diag(vha); if (rval) @@ -3544,53 +3550,77 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha) } -/* - * Return Code: - * QLA_SUCCESS: no action - * QLA_INTERFACE_ERROR: SFP is not there. - * QLA_FUNCTION_FAILED: detected New SFP +/** + * qla24xx_detect_sfp() + * + * @vha: adapter state pointer. + * + * @return + * 0 -- Configure firmware to use short-range settings -- normal + * buffer-to-buffer credits. + * + * 1 -- Configure firmware to use long-range settings -- extra + * buffer-to-buffer credits should be allocated with + * ha->lr_distance containing distance settings from NVRAM or SFP + * (if supported). */ int qla24xx_detect_sfp(scsi_qla_host_t *vha) { - int rc = QLA_SUCCESS; + int rc, used_nvram; struct sff_8247_a0 *a; struct qla_hw_data *ha = vha->hw; - - if (!AUTO_DETECT_SFP_SUPPORT(vha)) + struct nvram_81xx *nv = ha->nvram; +#define LR_DISTANCE_UNKNOWN 2 + static const char * const types[] = { "Short", "Long" }; + static const char * const lengths[] = { "(10km)", "(5km)", "" }; + u8 ll = 0; + + /* Seed with NVRAM settings. */ + used_nvram = 0; + ha->flags.lr_detected = 0; + if (IS_BPM_RANGE_CAPABLE(ha) && + (nv->enhanced_features & NEF_LR_DIST_ENABLE)) { + used_nvram = 1; + ha->flags.lr_detected = 1; + ha->lr_distance = + (nv->enhanced_features >> LR_DIST_NV_POS) + & LR_DIST_NV_MASK; + } + + if (!IS_BPM_ENABLED(vha)) goto out; - + /* Determine SR/LR capabilities of SFP/Transceiver. */ rc = qla2x00_read_sfp_dev(vha, NULL, 0); if (rc) goto out; + used_nvram = 0; a = (struct sff_8247_a0 *)vha->hw->sfp_data; qla2xxx_print_sfp_info(vha); - if (a->fc_ll_cc7 & FC_LL_VL || a->fc_ll_cc7 & FC_LL_L) { - /* long range */ - ha->flags.detected_lr_sfp = 1; + ha->flags.lr_detected = 0; + ll = a->fc_ll_cc7; + if (ll & FC_LL_VL || ll & FC_LL_L) { + /* Long range, track length. */ + ha->flags.lr_detected = 1; if (a->length_km > 5 || a->length_100m > 50) - ha->long_range_distance = LR_DISTANCE_10K; + ha->lr_distance = LR_DISTANCE_10K; else - ha->long_range_distance = LR_DISTANCE_5K; - - if (ha->flags.detected_lr_sfp != ha->flags.using_lr_setting) - ql_dbg(ql_dbg_async, vha, 0x507b, - "Detected Long Range SFP.\n"); - } else { - /* short range */ - ha->flags.detected_lr_sfp = 0; - if (ha->flags.using_lr_setting) - ql_dbg(ql_dbg_async, vha, 0x5084, - "Detected Short Range SFP.\n"); + ha->lr_distance = LR_DISTANCE_5K; } if (!vha->flags.init_done) rc = QLA_SUCCESS; out: - return rc; + ql_dbg(ql_dbg_async, vha, 0x507b, + "SFP detect: %s-Range SFP %s (nvr=%x ll=%x lr=%x lrd=%x).\n", + types[ha->flags.lr_detected], + ha->flags.lr_detected ? lengths[ha->lr_distance] : + lengths[LR_DISTANCE_UNKNOWN], + used_nvram, ll, ha->flags.lr_detected, ha->lr_distance); + return ha->flags.lr_detected; } /** @@ -3608,6 +3638,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; unsigned long flags; uint16_t fw_major_version; + int done_once = 0; if (IS_P3P_TYPE(ha)) { rval = ha->isp_ops->load_risc(vha, &srisc_address); @@ -3628,6 +3659,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) qla81xx_mpi_sync(vha); +execute_fw_with_lr: /* Load firmware sequences */ rval = ha->isp_ops->load_risc(vha, &srisc_address); if (rval == QLA_SUCCESS) { @@ -3649,7 +3681,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_execute_fw(vha, srisc_address); /* Retrieve firmware information. */ if (rval == QLA_SUCCESS) { - qla24xx_detect_sfp(vha); + /* Enable BPM support? */ + if (!done_once++ && qla24xx_detect_sfp(vha)) { + ql_dbg(ql_dbg_init, vha, 0x00ca, + "Re-starting firmware -- BPM.\n"); + /* Best-effort - re-init. */ + ha->isp_ops->reset_chip(vha); + ha->isp_ops->chip_diag(vha); + goto execute_fw_with_lr; + } if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && @@ -3708,6 +3748,10 @@ enable_82xx_npiv: "ISP Firmware failed checksum.\n"); goto failed; } + + /* Enable PUREX PASSTHRU */ + if (ql2xrdpenable) + qla25xx_set_els_cmds_supported(vha); } else goto failed; @@ -3919,6 +3963,13 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) ha->fw_options[2] &= ~BIT_8; } + if (ql2xrdpenable) + ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB; + + /* Enable Async 8130/8131 events -- transceiver insertion/removal */ + if (IS_BPM_RANGE_CAPABLE(ha)) + ha->fw_options[3] |= BIT_10; + ql_dbg(ql_dbg_init, vha, 0x00e8, "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", __func__, ha->fw_options[1], ha->fw_options[2], @@ -5060,7 +5111,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (N2N_TOPO(ha)) { if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { /* borrowing */ - u32 *bp, i, sz; + u32 *bp, sz; memset(ha->init_cb, 0, ha->init_cb_size); sz = min_t(int, sizeof(struct els_plogi_payload), @@ -5068,13 +5119,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, (void *)ha->init_cb, sz); if (rval == QLA_SUCCESS) { + __be32 *q = &ha->plogi_els_payld.data[0]; + bp = (uint32_t *)ha->init_cb; - for (i = 0; i < sz/4 ; i++, bp++) - *bp = cpu_to_be32(*bp); + cpu_to_be32_array(q, bp, sz / 4); - memcpy(&ha->plogi_els_payld.data, - (void *)ha->init_cb, - sizeof(ha->plogi_els_payld.data)); + memcpy(bp, q, sizeof(ha->plogi_els_payld.data)); } else { ql_dbg(ql_dbg_init, vha, 0x00d1, "PLOGI ELS param read fail.\n"); @@ -5097,6 +5147,7 @@ skip_login: set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } + return QLA_FUNCTION_FAILED; } found_devs = 0; @@ -5541,24 +5592,22 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) } vha->device_flags |= SWITCH_FOUND; + rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_port_name, 0); + if (rval != QLA_SUCCESS) + ql_dbg(ql_dbg_disc, vha, 0x20ff, + "Failed to get Fabric Port Name\n"); if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { rval = qla2x00_send_change_request(vha, 0x3, 0); if (rval != QLA_SUCCESS) ql_log(ql_log_warn, vha, 0x121, - "Failed to enable receiving of RSCN requests: 0x%x.\n", - rval); + "Failed to enable receiving of RSCN requests: 0x%x.\n", + rval); } - do { qla2x00_mgmt_svr_login(vha); - /* FDMI support. */ - if (ql2xfdmienable && - test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags)) - qla2x00_fdmi_register(vha); - /* Ensure we are logged into the SNS. */ loop_id = NPH_SNS_LID(ha); rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff, @@ -5570,6 +5619,12 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return rval; } + + /* FDMI support. */ + if (ql2xfdmienable && + test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags)) + qla2x00_fdmi_register(vha); + if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) { if (qla2x00_rft_id(vha)) { /* EMPTY */ @@ -5812,7 +5867,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) /* Bypass ports whose FCP-4 type is not FCP_SCSI */ if (ql2xgffidenable && (!(new_fcport->fc4_type & FS_FC4TYPE_FCP) && - new_fcport->fc4_type != FC4_TYPE_UNKNOWN)) + new_fcport->fc4_type != 0)) continue; spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); @@ -6656,7 +6711,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->flags.n2n_ae = 0; ha->flags.lip_ae = 0; ha->current_topology = 0; - ha->flags.fw_started = 0; + QLA_FW_STOPPED(ha); ha->flags.fw_init_done = 0; ha->chip_reset++; ha->base_qpair->chip_reset = ha->chip_reset; @@ -8663,61 +8718,6 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) return status; } -void -qla81xx_update_fw_options(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - /* Hold status IOCBs until ABTS response received. */ - if (ql2xfwholdabts) - ha->fw_options[3] |= BIT_12; - - /* Set Retry FLOGI in case of P2P connection */ - if (ha->operating_mode == P2P) { - ha->fw_options[2] |= BIT_3; - ql_dbg(ql_dbg_disc, vha, 0x2103, - "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n", - __func__, ha->fw_options[2]); - } - - /* Move PUREX, ABTS RX & RIDA to ATIOQ */ - if (ql2xmvasynctoatio) { - if (qla_tgt_mode_enabled(vha) || - qla_dual_mode_enabled(vha)) - ha->fw_options[2] |= BIT_11; - else - ha->fw_options[2] &= ~BIT_11; - } - - if (qla_tgt_mode_enabled(vha) || - qla_dual_mode_enabled(vha)) { - /* FW auto send SCSI status during */ - ha->fw_options[1] |= BIT_8; - ha->fw_options[10] |= (u16)SAM_STAT_BUSY << 8; - - /* FW perform Exchange validation */ - ha->fw_options[2] |= BIT_4; - } else { - ha->fw_options[1] &= ~BIT_8; - ha->fw_options[10] &= 0x00ff; - - ha->fw_options[2] &= ~BIT_4; - } - - if (ql2xetsenable) { - /* Enable ETS Burst. */ - memset(ha->fw_options, 0, sizeof(ha->fw_options)); - ha->fw_options[2] |= BIT_9; - } - - ql_dbg(ql_dbg_init, vha, 0x00e9, - "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n", - __func__, ha->fw_options[1], ha->fw_options[2], - ha->fw_options[3], vha->host->active_mode); - - qla2x00_set_fw_options(vha, ha->fw_options); -} - /* * qla24xx_get_fcp_prio * Gets the fcp cmd priority value for the logged in port. diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 47bf60a9490a..182bd68c79ac 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -530,7 +530,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun); host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); mrk24->vp_index = vha->vp_idx; - mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle); + mrk24->handle = make_handle(req->id, mrk24->handle); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16((uint16_t)lun); @@ -1655,7 +1655,7 @@ qla24xx_start_scsi(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -1843,7 +1843,7 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Fill-in common area */ cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); clr_ptr = (uint32_t *)cmd_pkt + 2; memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); @@ -1975,7 +1975,7 @@ qla2xxx_start_scsi_mq(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -2178,7 +2178,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) /* Fill-in common area */ cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); clr_ptr = (uint32_t *)cmd_pkt + 2; memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); @@ -2362,6 +2362,8 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) struct srb_iocb *lio = &sp->u.iocb_cmd; logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); + if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) { logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); } else { @@ -2489,7 +2491,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) tsk->entry_type = TSK_MGMT_IOCB_TYPE; tsk->entry_count = 1; - tsk->handle = MAKE_HANDLE(req->id, tsk->handle); + tsk->handle = make_handle(req->id, tsk->handle); tsk->nport_handle = cpu_to_le16(fcport->loop_id); tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->control_flags = cpu_to_le32(flags); @@ -2684,9 +2686,9 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->rx_dsd_count = 0; els_iocb->opcode = elsio->u.els_logo.els_cmd; - els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - els_iocb->port_id[1] = sp->fcport->d_id.b.area; - els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->d_id[1] = sp->fcport->d_id.b.area; + els_iocb->d_id[2] = sp->fcport->d_id.b.domain; /* For SID the byte order is different than DID */ els_iocb->s_id[1] = vha->d_id.b.al_pa; els_iocb->s_id[2] = vha->d_id.b.area; @@ -2939,7 +2941,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, sp->fcport = fcport; elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; - init_completion(&elsio->u.els_plogi.comp); if (wait) sp->flags = SRB_WAKEUP_ON_COMP; @@ -2949,7 +2950,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; ptr = elsio->u.els_plogi.els_plogi_pyld = - dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.tx_size, &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); if (!elsio->u.els_plogi.els_plogi_pyld) { @@ -2958,7 +2959,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, } resp_ptr = elsio->u.els_plogi.els_resp_pyld = - dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.rx_size, &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL); if (!elsio->u.els_plogi.els_resp_pyld) { @@ -2982,6 +2983,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, sizeof(*elsio->u.els_plogi.els_plogi_pyld)); + init_completion(&elsio->u.els_plogi.comp); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { rval = QLA_FUNCTION_FAILED; @@ -3030,9 +3032,9 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) sp->type == SRB_ELS_CMD_RPT ? bsg_request->rqst_data.r_els.els_code : bsg_request->rqst_data.h_els.command_code; - els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - els_iocb->port_id[1] = sp->fcport->d_id.b.area; - els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->d_id[1] = sp->fcport->d_id.b.area; + els_iocb->d_id[2] = sp->fcport->d_id.b.domain; els_iocb->control_flags = 0; els_iocb->rx_byte_count = cpu_to_le32(bsg_job->reply_payload.payload_len); @@ -3358,7 +3360,7 @@ sufficient_dsds: } cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -3429,7 +3431,7 @@ sufficient_dsds: goto queuing_error; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ @@ -3534,7 +3536,7 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); abt_iocb->entry_type = ABORT_IOCB_TYPE; abt_iocb->entry_count = 1; - abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + abt_iocb->handle = cpu_to_le32(make_handle(req->id, sp->handle)); if (sp->fcport) { abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -3542,7 +3544,7 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; } abt_iocb->handle_to_abort = - cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, + cpu_to_le32(make_handle(aio->u.abt.req_que_no, aio->u.abt.cmd_hndl)); abt_iocb->vp_index = vha->vp_idx; abt_iocb->req_que_no = cpu_to_le16(aio->u.abt.req_que_no); @@ -3905,7 +3907,7 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) } cmd_pkt = (struct cmd_bidir *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e40705d38cea..8d7a905f6247 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -31,6 +31,144 @@ const char *const port_state_str[] = { "ONLINE" }; +static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt, + void (*process_item)(struct scsi_qla_host *vha, void *pkt)) +{ + struct purex_list *list = &vha->purex_list; + struct purex_item *item; + ulong flags; + + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + ql_log(ql_log_warn, vha, 0x5092, + ">> Failed allocate purex list item.\n"); + return; + } + + item->vha = vha; + item->process_item = process_item; + memcpy(&item->iocb, pkt, sizeof(item->iocb)); + + spin_lock_irqsave(&list->lock, flags); + list_add_tail(&item->list, &list->head); + spin_unlock_irqrestore(&list->lock, flags); + + set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags); +} + +static void +qla24xx_process_abts(struct scsi_qla_host *vha, void *pkt) +{ + struct abts_entry_24xx *abts = pkt; + struct qla_hw_data *ha = vha->hw; + struct els_entry_24xx *rsp_els; + struct abts_entry_24xx *abts_rsp; + dma_addr_t dma; + uint32_t fctl; + int rval; + + ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__); + + ql_log(ql_log_warn, vha, 0x0287, + "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n", + abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id, + abts->seq_id, abts->seq_cnt); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, + "-------- ABTS RCV -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, + (uint8_t *)abts, sizeof(*abts)); + + rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma, + GFP_KERNEL); + if (!rsp_els) { + ql_log(ql_log_warn, vha, 0x0287, + "Failed allocate dma buffer ABTS/ELS RSP.\n"); + return; + } + + /* terminate exchange */ + memset(rsp_els, 0, sizeof(*rsp_els)); + rsp_els->entry_type = ELS_IOCB_TYPE; + rsp_els->entry_count = 1; + rsp_els->nport_handle = ~0; + rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort; + rsp_els->control_flags = EPD_RX_XCHG; + ql_dbg(ql_dbg_init, vha, 0x0283, + "Sending ELS Response to terminate exchange %#x...\n", + abts->rx_xch_addr_to_abort); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, + (uint8_t *)rsp_els, sizeof(*rsp_els)); + rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0); + if (rval) { + ql_log(ql_log_warn, vha, 0x0288, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (rsp_els->comp_status) { + ql_log(ql_log_warn, vha, 0x0289, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, rsp_els->comp_status, + rsp_els->error_subcode_1, rsp_els->error_subcode_2); + } else { + ql_dbg(ql_dbg_init, vha, 0x028a, + "%s: abort exchange done.\n", __func__); + } + + /* send ABTS response */ + abts_rsp = (void *)rsp_els; + memset(abts_rsp, 0, sizeof(*abts_rsp)); + abts_rsp->entry_type = ABTS_RSP_TYPE; + abts_rsp->entry_count = 1; + abts_rsp->nport_handle = abts->nport_handle; + abts_rsp->vp_idx = abts->vp_idx; + abts_rsp->sof_type = abts->sof_type & 0xf0; + abts_rsp->rx_xch_addr = abts->rx_xch_addr; + abts_rsp->d_id[0] = abts->s_id[0]; + abts_rsp->d_id[1] = abts->s_id[1]; + abts_rsp->d_id[2] = abts->s_id[2]; + abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC; + abts_rsp->s_id[0] = abts->d_id[0]; + abts_rsp->s_id[1] = abts->d_id[1]; + abts_rsp->s_id[2] = abts->d_id[2]; + abts_rsp->cs_ctl = abts->cs_ctl; + /* include flipping bit23 in fctl */ + fctl = ~(abts->f_ctl[2] | 0x7F) << 16 | + FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT; + abts_rsp->f_ctl[0] = fctl >> 0 & 0xff; + abts_rsp->f_ctl[1] = fctl >> 8 & 0xff; + abts_rsp->f_ctl[2] = fctl >> 16 & 0xff; + abts_rsp->type = FC_TYPE_BLD; + abts_rsp->rx_id = abts->rx_id; + abts_rsp->ox_id = abts->ox_id; + abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id; + abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id; + abts_rsp->payload.ba_acc.high_seq_cnt = ~0; + abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort; + ql_dbg(ql_dbg_init, vha, 0x028b, + "Sending BA ACC response to ABTS %#x...\n", + abts->rx_xch_addr_to_abort); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, + (uint8_t *)abts_rsp, sizeof(*abts_rsp)); + rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0); + if (rval) { + ql_log(ql_log_warn, vha, 0x028c, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (abts_rsp->comp_status) { + ql_log(ql_log_warn, vha, 0x028d, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, abts_rsp->comp_status, + abts_rsp->payload.error.subcode1, + abts_rsp->payload.error.subcode2); + } else { + ql_dbg(ql_dbg_init, vha, 0x028ea, + "%s: done.\n", __func__); + } + + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma); +} + /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. * @irq: interrupt number @@ -716,12 +854,24 @@ skip_rio: break; case MBA_SYSTEM_ERR: /* System Error */ - mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || - IS_QLA28XX(ha)) ? - RD_REG_WORD(®24->mailbox7) : 0; - ql_log(ql_log_warn, vha, 0x5003, - "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh " - "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx); + mbx = 0; + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || + IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + u16 m[4]; + + m[0] = RD_REG_WORD(®24->mailbox4); + m[1] = RD_REG_WORD(®24->mailbox5); + m[2] = RD_REG_WORD(®24->mailbox6); + mbx = m[3] = RD_REG_WORD(®24->mailbox7); + + ql_log(ql_log_warn, vha, 0x5003, + "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n", + mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]); + } else + ql_log(ql_log_warn, vha, 0x5003, + "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ", + mb[1], mb[2], mb[3]); + ha->fw_dump_mpi = (IS_QLA27XX(ha) || IS_QLA28XX(ha)) && RD_REG_WORD(®24->mailbox7) & BIT_8; @@ -813,13 +963,15 @@ skip_rio: "LOOP UP detected (%s Gbps).\n", qla2x00_get_link_speed_str(ha, ha->link_data_rate)); + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if (mb[2] & BIT_0) + ql_log(ql_log_info, vha, 0x11a0, + "FEC=enabled (link up).\n"); + } + vha->flags.management_server_logged_in = 0; qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate); - if (AUTO_DETECT_SFP_SUPPORT(vha)) { - set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } break; case MBA_LOOP_DOWN: /* Loop Down Event */ @@ -1254,6 +1406,7 @@ global_port_update: ql_dbg(ql_dbg_async, vha, 0x5052, "D-Port Diagnostics: %04x %04x %04x %04x\n", mb[0], mb[1], mb[2], mb[3]); + memcpy(vha->dport_data, mb, sizeof(vha->dport_data)); if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { static char *results[] = { "start", "done(pass)", "done(error)", "undefined" }; @@ -1291,6 +1444,11 @@ global_port_update: case MBA_TRANS_INSERT: ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Insertion: %04x\n", mb[1]); + set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags); + break; + + case MBA_TRANS_REMOVE: + ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n"); break; default: @@ -1754,11 +1912,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, } if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { - ql_dbg(ql_dbg_async, fcport->vha, 0x5036, - "Async-%s complete - %8phC hdl=%x portid=%02x%02x%02x " - "iop0=%x.\n", type, fcport->port_name, sp->handle, - fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, + ql_dbg(ql_dbg_async, sp->vha, 0x5036, + "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n", + type, sp->handle, fcport->d_id.b24, fcport->port_name, le32_to_cpu(logio->io_parameter[0])); vha->hw->exch_starvation = 0; @@ -1837,11 +1993,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, break; } - ql_dbg(ql_dbg_async, fcport->vha, 0x5037, - "Async-%s failed - %8phC hdl=%x portid=%02x%02x%02x comp=%x " - "iop0=%x iop1=%x.\n", type, fcport->port_name, - sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, + ql_dbg(ql_dbg_async, sp->vha, 0x5037, + "Async-%s failed: handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n", + type, sp->handle, fcport->d_id.b24, fcport->port_name, le16_to_cpu(logio->comp_status), le32_to_cpu(logio->io_parameter[0]), le32_to_cpu(logio->io_parameter[1])); @@ -1910,6 +2064,7 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, struct nvmefc_fcp_req *fd; uint16_t ret = QLA_SUCCESS; uint16_t comp_status = le16_to_cpu(sts->comp_status); + int logit = 0; iocb = &sp->u.iocb_cmd; fcport = sp->fcport; @@ -1920,6 +2075,12 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, if (unlikely(iocb->u.nvme.aen_op)) atomic_dec(&sp->vha->hw->nvme_active_aen_cnt); + if (unlikely(comp_status != CS_COMPLETE)) + logit = 1; + + fd->transferred_length = fd->payload_length - + le32_to_cpu(sts->residual_len); + /* * State flags: Bit 6 and 0. * If 0 is set, we don't care about 6. @@ -1930,8 +2091,20 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, */ if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) { iocb->u.nvme.rsp_pyld_len = 0; - } else if ((state_flags & SF_FCP_RSP_DMA)) { + } else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) == + (SF_FCP_RSP_DMA | SF_NVME_ERSP)) { + /* Response already DMA'd to fd->rspaddr. */ iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len); + } else if ((state_flags & SF_FCP_RSP_DMA)) { + /* + * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this + * as an error. + */ + iocb->u.nvme.rsp_pyld_len = 0; + fd->transferred_length = 0; + ql_dbg(ql_dbg_io, fcport->vha, 0x307a, + "Unexpected values in NVMe_RSP IU.\n"); + logit = 1; } else if (state_flags & SF_NVME_ERSP) { uint32_t *inbuf, *outbuf; uint16_t iter; @@ -1954,16 +2127,28 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, iter = iocb->u.nvme.rsp_pyld_len >> 2; for (; iter; iter--) *outbuf++ = swab32(*inbuf++); - } else { /* unhandled case */ - ql_log(ql_log_warn, fcport->vha, 0x503a, - "NVME-%s error. Unhandled state_flags of %x\n", - sp->name, state_flags); } - fd->transferred_length = fd->payload_length - - le32_to_cpu(sts->residual_len); + if (state_flags & SF_NVME_ERSP) { + struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr; + u32 tgt_xfer_len; - if (unlikely(comp_status != CS_COMPLETE)) + tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len); + if (fd->transferred_length != tgt_xfer_len) { + ql_dbg(ql_dbg_io, fcport->vha, 0x3079, + "Dropped frame(s) detected (sent/rcvd=%u/%u).\n", + tgt_xfer_len, fd->transferred_length); + logit = 1; + } else if (comp_status == CS_DATA_UNDERRUN) { + /* + * Do not log if this is just an underflow and there + * is no data loss. + */ + logit = 0; + } + } + + if (unlikely(logit)) ql_log(ql_log_warn, fcport->vha, 0x5060, "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n", sp->name, sp->handle, comp_status, @@ -2516,11 +2701,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } - if (sp->abort) - sp->aborted = 1; - else - sp->completed = 1; - if (sp->cmd_type != TYPE_SRB) { req->outstanding_cmds[handle] = NULL; ql_dbg(ql_dbg_io, vha, 0x3015, @@ -3083,6 +3263,11 @@ process_err: qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); break; case ABTS_RECV_24XX: + if (qla_ini_mode_enabled(vha)) { + qla24xx_purex_iocb(vha, pkt, + qla24xx_process_abts); + break; + } if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { /* ensure that the ATIO queue is empty */ @@ -3127,6 +3312,19 @@ process_err: qla_ctrlvp_completed(vha, rsp->req, (struct vp_ctrl_entry_24xx *)pkt); break; + case PUREX_IOCB_TYPE: + { + struct purex_entry_24xx *purex = (void *)pkt; + + if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) { + ql_dbg(ql_dbg_init, vha, 0x5091, + "Discarding ELS Request opcode %#x...\n", + purex->els_frame_payload[3]); + break; + } + qla24xx_purex_iocb(vha, pkt, qla24xx_process_purex_rdp); + break; + } default: /* Type Not Supported. */ ql_dbg(ql_dbg_async, vha, 0x5042, @@ -3442,6 +3640,25 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) { struct qla_hw_data *ha; struct qla_qpair *qpair; + + qpair = dev_id; + if (!qpair) { + ql_log(ql_log_info, NULL, 0x505b, + "%s: NULL response queue pointer.\n", __func__); + return IRQ_NONE; + } + ha = qpair->hw; + + queue_work(ha->wq, &qpair->q_work); + + return IRQ_HANDLED; +} + +irqreturn_t +qla2xxx_msix_rsp_q_hs(int irq, void *dev_id) +{ + struct qla_hw_data *ha; + struct qla_qpair *qpair; struct device_reg_24xx __iomem *reg; unsigned long flags; @@ -3453,13 +3670,10 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) } ha = qpair->hw; - /* Clear the interrupt, if enabled, for this response queue */ - if (unlikely(!ha->flags.disable_msix_handshake)) { - reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } + reg = &ha->iobase->isp24; + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + spin_unlock_irqrestore(&ha->hardware_lock, flags); queue_work(ha->wq, &qpair->q_work); @@ -3478,6 +3692,7 @@ static const struct qla_init_msix_entry msix_entries[] = { { "rsp_q", qla24xx_msix_rsp_q }, { "atio_q", qla83xx_msix_atio_q }, { "qpair_multiq", qla2xxx_msix_rsp_q }, + { "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs }, }; static const struct qla_init_msix_entry qla82xx_msix_entries[] = { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 9e09964f5c0e..9fd83d1bffe0 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -117,10 +117,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ql_dbg(ql_dbg_mbx, vha, 0x1000, "Entered %s.\n", __func__); - if (ha->pdev->error_state > pci_channel_io_frozen) { + if (ha->pdev->error_state == pci_channel_io_perm_failure) { ql_log(ql_log_warn, vha, 0x1001, - "error_state is greater than pci_channel_io_frozen, " - "exiting.\n"); + "PCI channel failed permanently, exiting.\n"); return QLA_FUNCTION_TIMEOUT; } @@ -643,30 +642,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, return rval; } -#define EXTENDED_BB_CREDITS BIT_0 #define NVME_ENABLE_FLAG BIT_3 -static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha) -{ - uint16_t mb4 = BIT_0; - - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) - mb4 |= ha->long_range_distance << LR_DIST_FW_POS; - - return mb4; -} - -static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha) -{ - uint16_t mb4 = BIT_0; - - if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { - struct nvram_81xx *nv = ha->nvram; - - mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features); - } - - return mb4; -} /* * qla2x00_execute_fw @@ -690,10 +666,14 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) struct qla_hw_data *ha = vha->hw; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + u8 semaphore = 0; +#define EXE_FW_FORCE_SEMAPHORE BIT_7 + u8 retry = 3; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1025, "Entered %s.\n", __func__); +again: mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; mcp->in_mb = MBX_0; @@ -703,25 +683,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[3] = 0; mcp->mb[4] = 0; mcp->mb[11] = 0; - ha->flags.using_lr_setting = 0; - if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || - IS_QLA27XX(ha) || IS_QLA28XX(ha)) { - if (ql2xautodetectsfp) { - if (ha->flags.detected_lr_sfp) { - mcp->mb[4] |= - qla25xx_set_sfp_lr_dist(ha); - ha->flags.using_lr_setting = 1; - } - } else { - struct nvram_81xx *nv = ha->nvram; - /* set LR distance if specified in nvram */ - if (nv->enhanced_features & - NEF_LR_DIST_ENABLE) { - mcp->mb[4] |= - qla25xx_set_nvr_lr_dist(ha); - ha->flags.using_lr_setting = 1; - } - } + + /* Enable BPM? */ + if (ha->flags.lr_detected) { + mcp->mb[4] = BIT_0; + if (IS_BPM_RANGE_CAPABLE(ha)) + mcp->mb[4] |= + ha->lr_distance << LR_DIST_FW_POS; } if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha))) @@ -747,6 +715,9 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) if (ha->flags.exchoffld_enabled) mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD; + if (semaphore) + mcp->mb[11] |= EXE_FW_FORCE_SEMAPHORE; + mcp->out_mb |= MBX_4 | MBX_3 | MBX_2 | MBX_1 | MBX_11; mcp->in_mb |= MBX_3 | MBX_2 | MBX_1; } else { @@ -763,6 +734,15 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { + if (IS_QLA28XX(ha) && rval == QLA_COMMAND_ERROR && + mcp->mb[1] == 0x27 && retry) { + semaphore = 1; + retry--; + ql_dbg(ql_dbg_async, vha, 0x1026, + "Exe FW: force semaphore.\n"); + goto again; + } + ql_dbg(ql_dbg_mbx, vha, 0x1026, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); return rval; @@ -1137,11 +1117,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22]; ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24]; if (IS_QLA28XX(ha)) { - if (mcp->mb[16] & BIT_10) { - ql_log(ql_log_info, vha, 0xffff, - "FW support secure flash updates\n"); + if (mcp->mb[16] & BIT_10) ha->flags.secure_fw = 1; - } + + ql_log(ql_log_info, vha, 0xffff, + "Secure Flash Update in FW: %s\n", + (ha->flags.secure_fw) ? "Supported" : + "Not Supported"); } } @@ -1405,17 +1387,20 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + if (!vha->hw->flags.fw_started) + return QLA_INVALID_COMMAND; + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1038, "Entered %s.\n", __func__); mcp->mb[0] = MBC_IOCB_COMMAND_A64; mcp->mb[1] = 0; - mcp->mb[2] = MSW(phys_addr); - mcp->mb[3] = LSW(phys_addr); + mcp->mb[2] = MSW(LSD(phys_addr)); + mcp->mb[3] = LSW(LSD(phys_addr)); mcp->mb[6] = MSW(MSD(phys_addr)); mcp->mb[7] = LSW(MSD(phys_addr)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = tov; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -1424,13 +1409,14 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x1039, "Failed=%x.\n", rval); } else { - sts_entry_t *sts_entry = (sts_entry_t *) buffer; + sts_entry_t *sts_entry = buffer; /* Mask reserved bits. */ sts_entry->entry_status &= IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103a, - "Done %s.\n", __func__); + "Done %s (status=%x).\n", __func__, + sts_entry->entry_status); } return rval; @@ -1475,7 +1461,7 @@ qla2x00_abort_command(srb_t *sp) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103b, "Entered %s.\n", __func__); - if (vha->flags.qpairs_available && sp->qpair) + if (sp->qpair) req = sp->qpair->req; else req = vha->req; @@ -2045,6 +2031,57 @@ gpd_error_out: return rval; } +int +qla24xx_get_port_database(scsi_qla_host_t *vha, u16 nport_handle, + struct port_database_24xx *pdb) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + dma_addr_t pdb_dma; + int rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1115, + "Entered %s.\n", __func__); + + memset(pdb, 0, sizeof(*pdb)); + + pdb_dma = dma_map_single(&vha->hw->pdev->dev, pdb, + sizeof(*pdb), DMA_FROM_DEVICE); + if (!pdb_dma) { + ql_log(ql_log_warn, vha, 0x1116, "Failed to map dma buffer.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + mcp->mb[0] = MBC_GET_PORT_DATABASE; + mcp->mb[1] = nport_handle; + mcp->mb[2] = MSW(LSD(pdb_dma)); + mcp->mb[3] = LSW(LSD(pdb_dma)); + mcp->mb[6] = MSW(MSD(pdb_dma)); + mcp->mb[7] = LSW(MSD(pdb_dma)); + mcp->mb[9] = 0; + mcp->mb[10] = 0; + mcp->out_mb = MBX_10|MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = sizeof(*pdb); + mcp->flags = MBX_DMA_IN; + mcp->tov = vha->hw->login_timeout * 2; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x111a, + "Failed=%x mb[0]=%x mb[1]=%x.\n", + rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111b, + "Done %s.\n", __func__); + } + + dma_unmap_single(&vha->hw->pdev->dev, pdb_dma, + sizeof(*pdb), DMA_FROM_DEVICE); + + return rval; +} + /* * qla2x00_get_firmware_state * Get adapter firmware state. @@ -2384,7 +2421,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); + lg->handle = make_handle(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) @@ -2654,7 +2691,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, req = vha->req; lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); + lg->handle = make_handle(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| @@ -3060,18 +3097,19 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - uint32_t *iter, dwords; + uint32_t *iter = (void *)stats; + ushort dwords = sizeof(*stats)/sizeof(*iter); ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1088, "Entered %s.\n", __func__); memset(&mc, 0, sizeof(mc)); mc.mb[0] = MBC_GET_LINK_PRIV_STATS; - mc.mb[2] = MSW(stats_dma); - mc.mb[3] = LSW(stats_dma); + mc.mb[2] = MSW(LSD(stats_dma)); + mc.mb[3] = LSW(LSD(stats_dma)); mc.mb[6] = MSW(MSD(stats_dma)); mc.mb[7] = LSW(MSD(stats_dma)); - mc.mb[8] = sizeof(struct link_statistics) / 4; + mc.mb[8] = dwords; mc.mb[9] = cpu_to_le16(vha->vp_idx); mc.mb[10] = cpu_to_le16(options); @@ -3086,8 +3124,6 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108a, "Done %s.\n", __func__); /* Re-endianize - firmware data is le32. */ - dwords = sizeof(struct link_statistics) / 4; - iter = &stats->link_fail_cnt; for ( ; dwords--; iter++) le32_to_cpus(iter); } @@ -3145,9 +3181,9 @@ qla24xx_abort_command(srb_t *sp) abt->entry_type = ABORT_IOCB_TYPE; abt->entry_count = 1; - abt->handle = MAKE_HANDLE(req->id, abt->handle); + abt->handle = make_handle(req->id, abt->handle); abt->nport_handle = cpu_to_le16(fcport->loop_id); - abt->handle_to_abort = MAKE_HANDLE(req->id, handle); + abt->handle_to_abort = make_handle(req->id, handle); abt->port_id[0] = fcport->d_id.b.al_pa; abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; @@ -3224,7 +3260,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; tsk->p.tsk.entry_count = 1; - tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle); + tsk->p.tsk.handle = make_handle(req->id, tsk->p.tsk.handle); tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->p.tsk.control_flags = cpu_to_le32(type); @@ -3888,11 +3924,29 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, fcport->scan_state = QLA_FCPORT_SCAN; fcport->n2n_flag = 0; } + id.b24 = 0; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(rptid_entry->u.f1.port_name)) { + vha->d_id.b24 = 0; + vha->d_id.b.al_pa = 1; + ha->flags.n2n_bigger = 1; + + id.b.al_pa = 2; + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: assign local id %x remote id %x\n", + vha->d_id.b24, id.b24); + } else { + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote login - Waiting for WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + ha->flags.n2n_bigger = 0; + } fcport = qla2x00_find_fcport_by_wwpn(vha, rptid_entry->u.f1.port_name, 1); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + if (fcport) { fcport->plogi_nack_done_deadline = jiffies + HZ; fcport->dm_login_expire = jiffies + 2*HZ; @@ -3903,6 +3957,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (vha->flags.nvme_enabled) fcport->fc4_type |= FS_FC4TYPE_NVME; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(fcport->port_name)) { + fcport->d_id = id; + } + switch (fcport->disc_state) { case DSC_DELETED: set_bit(RELOGIN_NEEDED, @@ -3915,25 +3974,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, break; } } else { - id.b24 = 0; - if (wwn_to_u64(vha->port_name) > - wwn_to_u64(rptid_entry->u.f1.port_name)) { - vha->d_id.b24 = 0; - vha->d_id.b.al_pa = 1; - ha->flags.n2n_bigger = 1; - ha->flags.n2n_ae = 0; - - id.b.al_pa = 2; - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: assign local id %x remote id %x\n", - vha->d_id.b24, id.b24); - } else { - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Remote login - Waiting for WWPN %8phC.\n", - rptid_entry->u.f1.port_name); - ha->flags.n2n_bigger = 0; - ha->flags.n2n_ae = 1; - } qla24xx_post_newsess_work(vha, &id, rptid_entry->u.f1.port_name, rptid_entry->u.f1.node_name, @@ -4827,6 +4867,103 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, return rval; } +int +qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint8_t *els_cmd_map; + dma_addr_t els_cmd_map_dma; + uint cmd_opcode = ELS_COMMAND_RDP; + uint index = cmd_opcode / 8; + uint bit = cmd_opcode % 8; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha)) + return QLA_SUCCESS; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197, + "Entered %s.\n", __func__); + + els_cmd_map = dma_alloc_coherent(&ha->pdev->dev, ELS_CMD_MAP_SIZE, + &els_cmd_map_dma, GFP_KERNEL); + if (!els_cmd_map) { + ql_log(ql_log_warn, vha, 0x7101, + "Failed to allocate RDP els command param.\n"); + return QLA_MEMORY_ALLOC_FAILED; + } + + memset(els_cmd_map, 0, ELS_CMD_MAP_SIZE); + + els_cmd_map[index] |= 1 << bit; + + mcp->mb[0] = MBC_SET_RNID_PARAMS; + mcp->mb[1] = RNID_TYPE_ELS_CMD << 8; + mcp->mb[2] = MSW(LSD(els_cmd_map_dma)); + mcp->mb[3] = LSW(LSD(els_cmd_map_dma)); + mcp->mb[6] = MSW(MSD(els_cmd_map_dma)); + mcp->mb[7] = LSW(MSD(els_cmd_map_dma)); + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT; + mcp->buf_size = ELS_CMD_MAP_SIZE; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x118d, + "Failed=%x (%x,%x).\n", rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c, + "Done %s.\n", __func__); + } + + dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + els_cmd_map, els_cmd_map_dma); + + return rval; +} + +int +qla24xx_get_buffer_credits(scsi_qla_host_t *vha, struct buffer_credit_24xx *bbc, + dma_addr_t bbc_dma) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118e, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_GET_RNID_PARAMS; + mcp->mb[1] = RNID_BUFFER_CREDITS << 8; + mcp->mb[2] = MSW(LSD(bbc_dma)); + mcp->mb[3] = LSW(LSD(bbc_dma)); + mcp->mb[6] = MSW(MSD(bbc_dma)); + mcp->mb[7] = LSW(MSD(bbc_dma)); + mcp->mb[8] = sizeof(*bbc) / sizeof(*bbc->parameter); + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->buf_size = sizeof(*bbc); + mcp->flags = MBX_DMA_IN; + mcp->tov = MBX_TOV_SECONDS; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x118f, + "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1190, + "Done %s.\n", __func__); + } + + return rval; +} + static int qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp) { @@ -4880,8 +5017,8 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mcp->mb[0] = MBC_READ_SFP; mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); + mcp->mb[2] = MSW(LSD(sfp_dma)); + mcp->mb[3] = LSW(LSD(sfp_dma)); mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; @@ -4934,8 +5071,8 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mcp->mb[0] = MBC_WRITE_SFP; mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); + mcp->mb[2] = MSW(LSD(sfp_dma)); + mcp->mb[3] = LSW(LSD(sfp_dma)); mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; @@ -5170,10 +5307,11 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, mcp->out_mb |= MBX_2; mcp->in_mb = MBX_0; - if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) + if (IS_CNA_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || + IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_1; - if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) + if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) mcp->in_mb |= MBX_3; mcp->tov = MBX_TOV_SECONDS; @@ -5407,6 +5545,15 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1107, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { + if (mcp->mb[1] != 0x7) + ha->link_data_rate = mcp->mb[1]; + + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if (mcp->mb[4] & BIT_0) + ql_log(ql_log_info, vha, 0x11a2, + "FEC=enabled (data rate).\n"); + } + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108, "Done %s.\n", __func__); if (mcp->mb[1] != 0x7) @@ -6688,3 +6835,60 @@ int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr, return rval; } + +int +ql26xx_led_config(scsi_qla_host_t *vha, uint16_t options, uint16_t *led) +{ + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx, vha, 0x7070, "Entered %s (options=%x).\n", + __func__, options); + + mcp->mb[0] = MBC_SET_GET_FC_LED_CONFIG; + mcp->mb[1] = options; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + if (options & BIT_0) { + if (options & BIT_1) { + mcp->mb[2] = led[2]; + mcp->out_mb |= MBX_2; + } + if (options & BIT_2) { + mcp->mb[3] = led[0]; + mcp->out_mb |= MBX_3; + } + if (options & BIT_3) { + mcp->mb[4] = led[1]; + mcp->out_mb |= MBX_4; + } + } else { + mcp->in_mb |= MBX_4|MBX_3|MBX_2; + } + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + if (rval) { + ql_dbg(ql_dbg_mbx, vha, 0x7071, "Failed %s %x (mb=%x,%x)\n", + __func__, rval, mcp->mb[0], mcp->mb[1]); + return rval; + } + + if (options & BIT_0) { + ha->beacon_blink_led = 0; + ql_dbg(ql_dbg_mbx, vha, 0x7072, "Done %s\n", __func__); + } else { + led[2] = mcp->mb[2]; + led[0] = mcp->mb[3]; + led[1] = mcp->mb[4]; + ql_dbg(ql_dbg_mbx, vha, 0x7073, "Done %s (led=%x,%x,%x)\n", + __func__, led[0], led[1], led[2]); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8ae639d089d1..d82e92da529a 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -361,6 +361,13 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) } } + if (test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)) { + if (atomic_read(&vha->loop_state) == LOOP_READY) { + qla24xx_process_purex_list(&vha->purex_list); + clear_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags); + } + } + if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, vha, 0x4016, "FCPort update scheduled.\n"); @@ -509,6 +516,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) vha->mgmt_svr_loop_id = qla2x00_reserve_mgmt_server_loop_id(vha); vha->dpc_flags = 0L; + ha->dpc_active = 0; + set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); + set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); /* * To fix the issue of processing a parent's RSCN for the vport before @@ -886,7 +896,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->rsp_q_out); ret = qla25xx_request_irq(ha, qpair, qpair->msix, - QLA_MSIX_QPAIR_MULTIQ_RSP_Q); + ha->flags.disable_msix_handshake ? + QLA_MSIX_QPAIR_MULTIQ_RSP_Q : QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS); if (ret) goto que_failed; diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index cad1fc2a1b28..df99911b8bb9 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -53,10 +53,9 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp) struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - if (ha->pdev->error_state > pci_channel_io_frozen) { + if (ha->pdev->error_state == pci_channel_io_perm_failure) { ql_log(ql_log_warn, vha, 0x115c, - "error_state is greater than pci_channel_io_frozen, " - "exiting.\n"); + "PCI channel failed permanently, exiting.\n"); return QLA_FUNCTION_TIMEOUT; } @@ -3136,7 +3135,7 @@ qlafx00_start_scsi(srb_t *sp) memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE); - lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle); + lcmd_pkt.handle = make_handle(req->id, sp->handle); lcmd_pkt.reserved_0 = 0; lcmd_pkt.port_path_ctrl = 0; lcmd_pkt.reserved_1 = 0; @@ -3206,7 +3205,7 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb) memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00)); tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00; tm_iocb.entry_count = 1; - tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + tm_iocb.handle = cpu_to_le32(make_handle(req->id, sp->handle)); tm_iocb.reserved_0 = 0; tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id); tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags); @@ -3232,9 +3231,9 @@ qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb) memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00)); abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00; abt_iocb.entry_count = 1; - abt_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + abt_iocb.handle = cpu_to_le32(make_handle(req->id, sp->handle)); abt_iocb.abort_handle = - cpu_to_le32(MAKE_HANDLE(req->id, fxio->u.abt.cmd_hndl)); + cpu_to_le32(make_handle(req->id, fxio->u.abt.cmd_hndl)); abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id); abt_iocb.req_que_no = cpu_to_le16(req->id); diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index bfcd02fdf2b8..84e2a980dea0 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -413,7 +413,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_nvme *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + cmd_pkt->handle = make_handle(req->id, handle); /* Zero out remaining portion of packet. */ clr_ptr = (uint32_t *)cmd_pkt + 2; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7a94e1171c72..d190db5ea7d9 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -113,7 +113,8 @@ module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR); module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xfdmienable, "Enables FDMI registrations. " - "0 - no FDMI. Default is 1 - perform FDMI."); + "0 - no FDMI registrations. " + "1 - provide FDMI registrations (default)."); #define MAX_Q_DEPTH 64 static int ql2xmaxqdepth = MAX_Q_DEPTH; @@ -122,11 +123,7 @@ MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to set for each LUN. " "Default is 64."); -#if (IS_ENABLED(CONFIG_NVME_FC)) -int ql2xenabledif; -#else int ql2xenabledif = 2; -#endif module_param(ql2xenabledif, int, S_IRUGO); MODULE_PARM_DESC(ql2xenabledif, " Enable T10-CRC-DIF:\n" @@ -306,6 +303,22 @@ MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, "0 (Default). Based on check.\n" "1 Force using internal buffers\n"); +int ql2xsmartsan; +module_param(ql2xsmartsan, int, 0444); +module_param_named(smartsan, ql2xsmartsan, int, 0444); +MODULE_PARM_DESC(ql2xsmartsan, + "Send SmartSAN Management Attributes for FDMI Registration." + " Default is 0 - No SmartSAN registration," + " 1 - Register SmartSAN Management Attributes."); + +int ql2xrdpenable; +module_param(ql2xrdpenable, int, 0444); +module_param_named(rdpenable, ql2xrdpenable, int, 0444); +MODULE_PARM_DESC(ql2xrdpenable, + "Enables RDP responses. " + "0 - no RDP responses (default). " + "1 - provide RDP responses."); + static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static int qla2xxx_map_queues(struct Scsi_Host *shost); @@ -583,6 +596,9 @@ qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) case 3: speed_str = "8.0GT/s"; break; + case 4: + speed_str = "16.0GT/s"; + break; default: speed_str = "<unknown>"; break; @@ -1253,17 +1269,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return SUCCESS; spin_lock_irqsave(qpair->qp_lock_ptr, flags); - if (sp->completed) { - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return SUCCESS; - } - - if (sp->abort || sp->aborted) { - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return FAILED; - } - - sp->abort = 1; sp->comp = ∁ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -1688,6 +1693,10 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) return QLA_SUCCESS; } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, unsigned long *flags) __releases(qp->qp_lock_ptr) @@ -1696,10 +1705,13 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, DECLARE_COMPLETION_ONSTACK(comp); scsi_qla_host_t *vha = qp->vha; struct qla_hw_data *ha = vha->hw; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); int rval; bool ret_cmd; uint32_t ratov_j; + lockdep_assert_held(qp->qp_lock_ptr); + if (qla2x00_chip_is_down(vha)) { sp->done(sp, res); return; @@ -1715,7 +1727,6 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, } sp->comp = ∁ - sp->abort = 1; spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); rval = ha->isp_ops->abort_command(sp); @@ -1739,13 +1750,17 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, } spin_lock_irqsave(qp->qp_lock_ptr, *flags); - if (ret_cmd && (!sp->completed || !sp->aborted)) + if (ret_cmd && blk_mq_request_started(cmd->request)) sp->done(sp, res); } else { sp->done(sp, res); } } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ static void __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) { @@ -1792,6 +1807,10 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) spin_unlock_irqrestore(qp->qp_lock_ptr, flags); } +/* + * The caller must ensure that no completion interrupts will happen + * while this function is in progress. + */ void qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) { @@ -2285,7 +2304,7 @@ static struct isp_operations qla81xx_isp_ops = { .config_rings = qla24xx_config_rings, .reset_adapter = qla24xx_reset_adapter, .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, + .update_fw_options = qla24xx_update_fw_options, .load_risc = qla81xx_load_risc, .pci_info_str = qla24xx_pci_info_str, .fw_version_str = qla24xx_fw_version_str, @@ -2402,7 +2421,7 @@ static struct isp_operations qla83xx_isp_ops = { .config_rings = qla24xx_config_rings, .reset_adapter = qla24xx_reset_adapter, .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, + .update_fw_options = qla24xx_update_fw_options, .load_risc = qla81xx_load_risc, .pci_info_str = qla24xx_pci_info_str, .fw_version_str = qla24xx_fw_version_str, @@ -3439,13 +3458,6 @@ skip_dpc: if (test_bit(UNLOADING, &base_vha->dpc_flags)) return -ENODEV; - if (ha->flags.detected_lr_sfp) { - ql_log(ql_log_info, base_vha, 0xffff, - "Reset chip to pick up LR SFP setting\n"); - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); - qla2xxx_wake_dpc(base_vha); - } - return 0; probe_failed: @@ -3806,6 +3818,20 @@ qla2x00_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } +static inline void +qla24xx_free_purex_list(struct purex_list *list) +{ + struct list_head *item, *next; + ulong flags; + + spin_lock_irqsave(&list->lock, flags); + list_for_each_safe(item, next, &list->head) { + list_del(item); + kfree(list_entry(item, struct purex_item, list)); + } + spin_unlock_irqrestore(&list->lock, flags); +} + static void qla2x00_free_device(scsi_qla_host_t *vha) { @@ -3838,6 +3864,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) } + qla24xx_free_purex_list(&vha->purex_list); + qla2x00_mem_free(ha); qla82xx_md_free(vha); @@ -3907,19 +3935,6 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, set_bit(RELOGIN_NEEDED, &vha->dpc_flags); } -/* - * qla2x00_mark_all_devices_lost - * Updates fcport state when device goes offline. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * None. - * - * Context: - */ void qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha) { @@ -3931,16 +3946,6 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha) list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = 0; qlt_schedule_sess_for_deletion(fcport); - - if (vha->vp_idx != 0 && vha->vp_idx != fcport->vha->vp_idx) - continue; - - /* - * No point in marking the device as lost, if the device is - * already DEAD. - */ - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) - continue; } } @@ -4811,6 +4816,9 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->gpnid_list); INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn); + INIT_LIST_HEAD(&vha->purex_list.head); + spin_lock_init(&vha->purex_list.lock); + spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); init_waitqueue_head(&vha->fcport_waitQ); @@ -5168,9 +5176,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->n2n_flag = 1; } fcport->fw_login_state = 0; - /* - * wait link init done before sending login - */ + + schedule_delayed_work(&vha->scan.scan_work, 5); } else { qla24xx_fcport_handle_login(vha, fcport); } @@ -5731,6 +5738,583 @@ retry_lock: return; } +static bool +qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, + struct purex_entry_24xx *purex) +{ + char fwstr[16]; + u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0]; + struct port_database_24xx *pdb; + + /* Domain Controller is always logged-out. */ + /* if RDP request is not from Domain Controller: */ + if (sid != 0xfffc01) + return false; + + ql_dbg(ql_dbg_init, vha, 0x0181, "%s: s_id=%#x\n", __func__, sid); + + pdb = kzalloc(sizeof(*pdb), GFP_KERNEL); + if (!pdb) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Failed allocate pdb\n", __func__); + } else if (qla24xx_get_port_database(vha, purex->nport_handle, pdb)) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Failed get pdb sid=%x\n", __func__, sid); + } else if (pdb->current_login_state != PDS_PLOGI_COMPLETE && + pdb->current_login_state != PDS_PRLI_COMPLETE) { + ql_dbg(ql_dbg_init, vha, 0x0181, + "%s: Port not logged in sid=%#x\n", __func__, sid); + } else { + /* RDP request is from logged in port */ + kfree(pdb); + return false; + } + kfree(pdb); + + vha->hw->isp_ops->fw_version_str(vha, fwstr, sizeof(fwstr)); + fwstr[strcspn(fwstr, " ")] = 0; + /* if FW version allows RDP response length upto 2048 bytes: */ + if (strcmp(fwstr, "8.09.00") > 0 || strcmp(fwstr, "8.05.65") == 0) + return false; + + ql_dbg(ql_dbg_init, vha, 0x0181, "%s: fw=%s\n", __func__, fwstr); + + /* RDP response length is to be reduced to maximum 256 bytes */ + return true; +} + +static uint +qla25xx_rdp_port_speed_capability(struct qla_hw_data *ha) +{ + if (IS_CNA_CAPABLE(ha)) + return RDP_PORT_SPEED_10GB; + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + unsigned int speeds = 0; + + if (ha->max_supported_speed == 2) { + if (ha->min_supported_speed <= 6) + speeds |= RDP_PORT_SPEED_64GB; + } + + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1) { + if (ha->min_supported_speed <= 5) + speeds |= RDP_PORT_SPEED_32GB; + } + + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 4) + speeds |= RDP_PORT_SPEED_16GB; + } + + if (ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 3) + speeds |= RDP_PORT_SPEED_8GB; + } + + if (ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 2) + speeds |= RDP_PORT_SPEED_4GB; + } + + return speeds; + } + + if (IS_QLA2031(ha)) + return RDP_PORT_SPEED_16GB|RDP_PORT_SPEED_8GB| + RDP_PORT_SPEED_4GB; + + if (IS_QLA25XX(ha)) + return RDP_PORT_SPEED_8GB|RDP_PORT_SPEED_4GB| + RDP_PORT_SPEED_2GB|RDP_PORT_SPEED_1GB; + + if (IS_QLA24XX_TYPE(ha)) + return RDP_PORT_SPEED_4GB|RDP_PORT_SPEED_2GB| + RDP_PORT_SPEED_1GB; + + if (IS_QLA23XX(ha)) + return RDP_PORT_SPEED_2GB|RDP_PORT_SPEED_1GB; + + return RDP_PORT_SPEED_1GB; +} + +static uint +qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha) +{ + switch (ha->link_data_rate) { + case PORT_SPEED_1GB: + return RDP_PORT_SPEED_1GB; + + case PORT_SPEED_2GB: + return RDP_PORT_SPEED_2GB; + + case PORT_SPEED_4GB: + return RDP_PORT_SPEED_4GB; + + case PORT_SPEED_8GB: + return RDP_PORT_SPEED_8GB; + + case PORT_SPEED_10GB: + return RDP_PORT_SPEED_10GB; + + case PORT_SPEED_16GB: + return RDP_PORT_SPEED_16GB; + + case PORT_SPEED_32GB: + return RDP_PORT_SPEED_32GB; + + case PORT_SPEED_64GB: + return RDP_PORT_SPEED_64GB; + + default: + return RDP_PORT_SPEED_UNKNOWN; + } +} + +/* + * Function Name: qla24xx_process_purex_iocb + * + * Description: + * Prepare a RDP response and send to Fabric switch + * + * PARAMETERS: + * vha: SCSI qla host + * purex: RDP request received by HBA + */ +void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt) +{ + struct qla_hw_data *ha = vha->hw; + struct purex_entry_24xx *purex = pkt; + dma_addr_t rsp_els_dma; + dma_addr_t rsp_payload_dma; + dma_addr_t stat_dma; + dma_addr_t bbc_dma; + dma_addr_t sfp_dma; + struct els_entry_24xx *rsp_els = NULL; + struct rdp_rsp_payload *rsp_payload = NULL; + struct link_statistics *stat = NULL; + struct buffer_credit_24xx *bbc = NULL; + uint8_t *sfp = NULL; + uint16_t sfp_flags = 0; + uint rsp_payload_length = sizeof(*rsp_payload); + int rval; + + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180, + "%s: Enter\n", __func__); + + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181, + "-------- ELS REQ -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182, + (void *)purex, sizeof(*purex)); + + if (qla25xx_rdp_rsp_reduce_size(vha, purex)) { + rsp_payload_length = + offsetof(typeof(*rsp_payload), optical_elmt_desc); + ql_dbg(ql_dbg_init, vha, 0x0181, + "Reducing RSP payload length to %u bytes...\n", + rsp_payload_length); + } + + rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), + &rsp_els_dma, GFP_KERNEL); + if (!rsp_els) { + ql_log(ql_log_warn, vha, 0x0183, + "Failed allocate dma buffer ELS RSP.\n"); + goto dealloc; + } + + rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload), + &rsp_payload_dma, GFP_KERNEL); + if (!rsp_payload) { + ql_log(ql_log_warn, vha, 0x0184, + "Failed allocate dma buffer ELS RSP payload.\n"); + goto dealloc; + } + + sfp = dma_alloc_coherent(&ha->pdev->dev, SFP_RTDI_LEN, + &sfp_dma, GFP_KERNEL); + + stat = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stat), + &stat_dma, GFP_KERNEL); + + bbc = dma_alloc_coherent(&ha->pdev->dev, sizeof(*bbc), + &bbc_dma, GFP_KERNEL); + + /* Prepare Response IOCB */ + rsp_els->entry_type = ELS_IOCB_TYPE; + rsp_els->entry_count = 1; + rsp_els->sys_define = 0; + rsp_els->entry_status = 0; + rsp_els->handle = 0; + rsp_els->nport_handle = purex->nport_handle; + rsp_els->tx_dsd_count = 1; + rsp_els->vp_index = purex->vp_idx; + rsp_els->sof_type = EST_SOFI3; + rsp_els->rx_xchg_address = purex->rx_xchg_addr; + rsp_els->rx_dsd_count = 0; + rsp_els->opcode = purex->els_frame_payload[0]; + + rsp_els->d_id[0] = purex->s_id[0]; + rsp_els->d_id[1] = purex->s_id[1]; + rsp_els->d_id[2] = purex->s_id[2]; + + rsp_els->control_flags = EPD_ELS_ACC; + rsp_els->rx_byte_count = 0; + rsp_els->tx_byte_count = cpu_to_le32(rsp_payload_length); + + put_unaligned_le64(rsp_payload_dma, &rsp_els->tx_address); + rsp_els->tx_len = rsp_els->tx_byte_count; + + rsp_els->rx_address = 0; + rsp_els->rx_len = 0; + + /* Prepare Response Payload */ + rsp_payload->hdr.cmd = cpu_to_be32(0x2 << 24); /* LS_ACC */ + rsp_payload->hdr.len = cpu_to_be32( + rsp_els->tx_byte_count - sizeof(rsp_payload->hdr)); + + /* Link service Request Info Descriptor */ + rsp_payload->ls_req_info_desc.desc_tag = cpu_to_be32(0x1); + rsp_payload->ls_req_info_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc)); + rsp_payload->ls_req_info_desc.req_payload_word_0 = + cpu_to_be32p((uint32_t *)purex->els_frame_payload); + + /* Link service Request Info Descriptor 2 */ + rsp_payload->ls_req_info_desc2.desc_tag = cpu_to_be32(0x1); + rsp_payload->ls_req_info_desc2.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc2)); + rsp_payload->ls_req_info_desc2.req_payload_word_0 = + cpu_to_be32p((uint32_t *)purex->els_frame_payload); + + + rsp_payload->sfp_diag_desc.desc_tag = cpu_to_be32(0x10000); + rsp_payload->sfp_diag_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->sfp_diag_desc)); + + if (sfp) { + /* SFP Flags */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x7, 2, 0); + if (!rval) { + /* SFP Flags bits 3-0: Port Tx Laser Type */ + if (sfp[0] & BIT_2 || sfp[1] & (BIT_6|BIT_5)) + sfp_flags |= BIT_0; /* short wave */ + else if (sfp[0] & BIT_1) + sfp_flags |= BIT_1; /* long wave 1310nm */ + else if (sfp[1] & BIT_4) + sfp_flags |= BIT_1|BIT_0; /* long wave 1550nm */ + } + + /* SFP Type */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x0, 1, 0); + if (!rval) { + sfp_flags |= BIT_4; /* optical */ + if (sfp[0] == 0x3) + sfp_flags |= BIT_6; /* sfp+ */ + } + + rsp_payload->sfp_diag_desc.sfp_flags = cpu_to_be16(sfp_flags); + + /* SFP Diagnostics */ + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0x60, 10, 0); + if (!rval) { + uint16_t *trx = (void *)sfp; /* already be16 */ + rsp_payload->sfp_diag_desc.temperature = trx[0]; + rsp_payload->sfp_diag_desc.vcc = trx[1]; + rsp_payload->sfp_diag_desc.tx_bias = trx[2]; + rsp_payload->sfp_diag_desc.tx_power = trx[3]; + rsp_payload->sfp_diag_desc.rx_power = trx[4]; + } + } + + /* Port Speed Descriptor */ + rsp_payload->port_speed_desc.desc_tag = cpu_to_be32(0x10001); + rsp_payload->port_speed_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_speed_desc)); + rsp_payload->port_speed_desc.speed_capab = cpu_to_be16( + qla25xx_rdp_port_speed_capability(ha)); + rsp_payload->port_speed_desc.operating_speed = cpu_to_be16( + qla25xx_rdp_port_speed_currently(ha)); + + /* Link Error Status Descriptor */ + rsp_payload->ls_err_desc.desc_tag = cpu_to_be32(0x10002); + rsp_payload->ls_err_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_err_desc)); + + if (stat) { + rval = qla24xx_get_isp_stats(vha, stat, stat_dma, 0); + if (!rval) { + rsp_payload->ls_err_desc.link_fail_cnt = + cpu_to_be32(stat->link_fail_cnt); + rsp_payload->ls_err_desc.loss_sync_cnt = + cpu_to_be32(stat->loss_sync_cnt); + rsp_payload->ls_err_desc.loss_sig_cnt = + cpu_to_be32(stat->loss_sig_cnt); + rsp_payload->ls_err_desc.prim_seq_err_cnt = + cpu_to_be32(stat->prim_seq_err_cnt); + rsp_payload->ls_err_desc.inval_xmit_word_cnt = + cpu_to_be32(stat->inval_xmit_word_cnt); + rsp_payload->ls_err_desc.inval_crc_cnt = + cpu_to_be32(stat->inval_crc_cnt); + rsp_payload->ls_err_desc.pn_port_phy_type |= BIT_6; + } + } + + /* Portname Descriptor */ + rsp_payload->port_name_diag_desc.desc_tag = cpu_to_be32(0x10003); + rsp_payload->port_name_diag_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_diag_desc)); + memcpy(rsp_payload->port_name_diag_desc.WWNN, + vha->node_name, + sizeof(rsp_payload->port_name_diag_desc.WWNN)); + memcpy(rsp_payload->port_name_diag_desc.WWPN, + vha->port_name, + sizeof(rsp_payload->port_name_diag_desc.WWPN)); + + /* F-Port Portname Descriptor */ + rsp_payload->port_name_direct_desc.desc_tag = cpu_to_be32(0x10003); + rsp_payload->port_name_direct_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_direct_desc)); + memcpy(rsp_payload->port_name_direct_desc.WWNN, + vha->fabric_node_name, + sizeof(rsp_payload->port_name_direct_desc.WWNN)); + memcpy(rsp_payload->port_name_direct_desc.WWPN, + vha->fabric_port_name, + sizeof(rsp_payload->port_name_direct_desc.WWPN)); + + /* Bufer Credit Descriptor */ + rsp_payload->buffer_credit_desc.desc_tag = cpu_to_be32(0x10006); + rsp_payload->buffer_credit_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->buffer_credit_desc)); + rsp_payload->buffer_credit_desc.fcport_b2b = 0; + rsp_payload->buffer_credit_desc.attached_fcport_b2b = cpu_to_be32(0); + rsp_payload->buffer_credit_desc.fcport_rtt = cpu_to_be32(0); + + if (bbc) { + memset(bbc, 0, sizeof(*bbc)); + rval = qla24xx_get_buffer_credits(vha, bbc, bbc_dma); + if (!rval) { + rsp_payload->buffer_credit_desc.fcport_b2b = + cpu_to_be32(LSW(bbc->parameter[0])); + } + } + + if (rsp_payload_length < sizeof(*rsp_payload)) + goto send; + + /* Optical Element Descriptor, Temperature */ + rsp_payload->optical_elmt_desc[0].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[0].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Voltage */ + rsp_payload->optical_elmt_desc[1].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[1].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Tx Bias Current */ + rsp_payload->optical_elmt_desc[2].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[2].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Tx Power */ + rsp_payload->optical_elmt_desc[3].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[3].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + /* Optical Element Descriptor, Rx Power */ + rsp_payload->optical_elmt_desc[4].desc_tag = cpu_to_be32(0x10007); + rsp_payload->optical_elmt_desc[4].desc_len = + cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); + + if (sfp) { + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0, 64, 0); + if (!rval) { + uint16_t *trx = (void *)sfp; /* already be16 */ + + /* Optical Element Descriptor, Temperature */ + rsp_payload->optical_elmt_desc[0].high_alarm = trx[0]; + rsp_payload->optical_elmt_desc[0].low_alarm = trx[1]; + rsp_payload->optical_elmt_desc[0].high_warn = trx[2]; + rsp_payload->optical_elmt_desc[0].low_warn = trx[3]; + rsp_payload->optical_elmt_desc[0].element_flags = + cpu_to_be32(1 << 28); + + /* Optical Element Descriptor, Voltage */ + rsp_payload->optical_elmt_desc[1].high_alarm = trx[4]; + rsp_payload->optical_elmt_desc[1].low_alarm = trx[5]; + rsp_payload->optical_elmt_desc[1].high_warn = trx[6]; + rsp_payload->optical_elmt_desc[1].low_warn = trx[7]; + rsp_payload->optical_elmt_desc[1].element_flags = + cpu_to_be32(2 << 28); + + /* Optical Element Descriptor, Tx Bias Current */ + rsp_payload->optical_elmt_desc[2].high_alarm = trx[8]; + rsp_payload->optical_elmt_desc[2].low_alarm = trx[9]; + rsp_payload->optical_elmt_desc[2].high_warn = trx[10]; + rsp_payload->optical_elmt_desc[2].low_warn = trx[11]; + rsp_payload->optical_elmt_desc[2].element_flags = + cpu_to_be32(3 << 28); + + /* Optical Element Descriptor, Tx Power */ + rsp_payload->optical_elmt_desc[3].high_alarm = trx[12]; + rsp_payload->optical_elmt_desc[3].low_alarm = trx[13]; + rsp_payload->optical_elmt_desc[3].high_warn = trx[14]; + rsp_payload->optical_elmt_desc[3].low_warn = trx[15]; + rsp_payload->optical_elmt_desc[3].element_flags = + cpu_to_be32(4 << 28); + + /* Optical Element Descriptor, Rx Power */ + rsp_payload->optical_elmt_desc[4].high_alarm = trx[16]; + rsp_payload->optical_elmt_desc[4].low_alarm = trx[17]; + rsp_payload->optical_elmt_desc[4].high_warn = trx[18]; + rsp_payload->optical_elmt_desc[4].low_warn = trx[19]; + rsp_payload->optical_elmt_desc[4].element_flags = + cpu_to_be32(5 << 28); + } + + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 112, 64, 0); + if (!rval) { + /* Temperature high/low alarm/warning */ + rsp_payload->optical_elmt_desc[0].element_flags |= + cpu_to_be32( + (sfp[0] >> 7 & 1) << 3 | + (sfp[0] >> 6 & 1) << 2 | + (sfp[4] >> 7 & 1) << 1 | + (sfp[4] >> 6 & 1) << 0); + + /* Voltage high/low alarm/warning */ + rsp_payload->optical_elmt_desc[1].element_flags |= + cpu_to_be32( + (sfp[0] >> 5 & 1) << 3 | + (sfp[0] >> 4 & 1) << 2 | + (sfp[4] >> 5 & 1) << 1 | + (sfp[4] >> 4 & 1) << 0); + + /* Tx Bias Current high/low alarm/warning */ + rsp_payload->optical_elmt_desc[2].element_flags |= + cpu_to_be32( + (sfp[0] >> 3 & 1) << 3 | + (sfp[0] >> 2 & 1) << 2 | + (sfp[4] >> 3 & 1) << 1 | + (sfp[4] >> 2 & 1) << 0); + + /* Tx Power high/low alarm/warning */ + rsp_payload->optical_elmt_desc[3].element_flags |= + cpu_to_be32( + (sfp[0] >> 1 & 1) << 3 | + (sfp[0] >> 0 & 1) << 2 | + (sfp[4] >> 1 & 1) << 1 | + (sfp[4] >> 0 & 1) << 0); + + /* Rx Power high/low alarm/warning */ + rsp_payload->optical_elmt_desc[4].element_flags |= + cpu_to_be32( + (sfp[1] >> 7 & 1) << 3 | + (sfp[1] >> 6 & 1) << 2 | + (sfp[5] >> 7 & 1) << 1 | + (sfp[5] >> 6 & 1) << 0); + } + } + + /* Optical Product Data Descriptor */ + rsp_payload->optical_prod_desc.desc_tag = cpu_to_be32(0x10008); + rsp_payload->optical_prod_desc.desc_len = + cpu_to_be32(RDP_DESC_LEN(rsp_payload->optical_prod_desc)); + + if (sfp) { + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 20, 64, 0); + if (!rval) { + memcpy(rsp_payload->optical_prod_desc.vendor_name, + sfp + 0, + sizeof(rsp_payload->optical_prod_desc.vendor_name)); + memcpy(rsp_payload->optical_prod_desc.part_number, + sfp + 20, + sizeof(rsp_payload->optical_prod_desc.part_number)); + memcpy(rsp_payload->optical_prod_desc.revision, + sfp + 36, + sizeof(rsp_payload->optical_prod_desc.revision)); + memcpy(rsp_payload->optical_prod_desc.serial_number, + sfp + 48, + sizeof(rsp_payload->optical_prod_desc.serial_number)); + } + + memset(sfp, 0, SFP_RTDI_LEN); + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 84, 8, 0); + if (!rval) { + memcpy(rsp_payload->optical_prod_desc.date, + sfp + 0, + sizeof(rsp_payload->optical_prod_desc.date)); + } + } + +send: + ql_dbg(ql_dbg_init, vha, 0x0183, + "Sending ELS Response to RDP Request...\n"); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184, + "-------- ELS RSP -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185, + (void *)rsp_els, sizeof(*rsp_els)); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186, + "-------- ELS RSP PAYLOAD -------\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187, + (void *)rsp_payload, rsp_payload_length); + + rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0); + + if (rval) { + ql_log(ql_log_warn, vha, 0x0188, + "%s: iocb failed to execute -> %x\n", __func__, rval); + } else if (rsp_els->comp_status) { + ql_log(ql_log_warn, vha, 0x0189, + "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", + __func__, rsp_els->comp_status, + rsp_els->error_subcode_1, rsp_els->error_subcode_2); + } else { + ql_dbg(ql_dbg_init, vha, 0x018a, "%s: done.\n", __func__); + } + +dealloc: + if (bbc) + dma_free_coherent(&ha->pdev->dev, sizeof(*bbc), + bbc, bbc_dma); + if (stat) + dma_free_coherent(&ha->pdev->dev, sizeof(*stat), + stat, stat_dma); + if (sfp) + dma_free_coherent(&ha->pdev->dev, SFP_RTDI_LEN, + sfp, sfp_dma); + if (rsp_payload) + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload), + rsp_payload, rsp_payload_dma); + if (rsp_els) + dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), + rsp_els, rsp_els_dma); +} + +void qla24xx_process_purex_list(struct purex_list *list) +{ + struct list_head head = LIST_HEAD_INIT(head); + struct purex_item *item, *next; + ulong flags; + + spin_lock_irqsave(&list->lock, flags); + list_splice_init(&list->head, &head); + spin_unlock_irqrestore(&list->lock, flags); + + list_for_each_entry_safe(item, next, &head, list) { + list_del(&item->list); + item->process_item(item->vha, &item->iocb); + kfree(item); + } +} + void qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id) { @@ -6254,13 +6838,14 @@ qla2x00_do_dpc(void *data) } if (test_and_clear_bit(DETECT_SFP_CHANGE, - &base_vha->dpc_flags) && - !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) { - qla24xx_detect_sfp(base_vha); - - if (ha->flags.detected_lr_sfp != - ha->flags.using_lr_setting) - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); + &base_vha->dpc_flags)) { + /* Semantic: + * - NO-OP -- await next ISP-ABORT. Preferred method + * to minimize disruptions that will occur + * when a forced chip-reset occurs. + * - Force -- ISP-ABORT scheduled. + */ + /* set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); */ } if (test_and_clear_bit @@ -6301,6 +6886,15 @@ qla2x00_do_dpc(void *data) } } + if (test_bit(PROCESS_PUREX_IOCB, &base_vha->dpc_flags)) { + if (atomic_read(&base_vha->loop_state) == LOOP_READY) { + qla24xx_process_purex_list + (&base_vha->purex_list); + clear_bit(PROCESS_PUREX_IOCB, + &base_vha->dpc_flags); + } + } + if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { qla2x00_update_fcports(base_vha); @@ -6692,7 +7286,8 @@ qla2x00_timer(struct timer_list *t) test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) || test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || test_bit(VP_DPC_NEEDED, &vha->dpc_flags) || - test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) { + test_bit(RELOGIN_NEEDED, &vha->dpc_flags) || + test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags))) { ql_dbg(ql_dbg_timer, vha, 0x600b, "isp_abort_needed=%d loop_resync_needed=%d " "fcport_update_needed=%d start_dpc=%d " @@ -6705,12 +7300,13 @@ qla2x00_timer(struct timer_list *t) ql_dbg(ql_dbg_timer, vha, 0x600c, "beacon_blink_needed=%d isp_unrecoverable=%d " "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d " - "relogin_needed=%d.\n", + "relogin_needed=%d, Process_purex_iocb=%d.\n", test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags), test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags), test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags), test_bit(VP_DPC_NEEDED, &vha->dpc_flags), - test_bit(RELOGIN_NEEDED, &vha->dpc_flags)); + test_bit(RELOGIN_NEEDED, &vha->dpc_flags), + test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)); qla2xxx_wake_dpc(vha); } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 76a38bf86cbc..3da79ee1d88e 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -2683,7 +2683,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t sec_mask, rest_addr, fdata; void *optrom = NULL; dma_addr_t optrom_dma; - int rval; + int rval, ret; struct secure_flash_update_block *sfub; dma_addr_t sfub_dma; uint32_t offset = faddr << 2; @@ -2939,11 +2939,12 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, write_protect: ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, "Protect flash...\n"); - rval = qla24xx_protect_flash(vha); - if (rval) { + ret = qla24xx_protect_flash(vha); + if (ret) { qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); ql_log(ql_log_warn, vha, 0x7099, "Failed protect flash\n"); + rval = QLA_COMMAND_ERROR; } if (reset_to_rom == true) { @@ -2951,10 +2952,12 @@ write_protect: set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - rval = qla2x00_wait_for_hba_online(vha); - if (rval != QLA_SUCCESS) + ret = qla2x00_wait_for_hba_online(vha); + if (ret != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0xffff, "Adapter did not come out of reset\n"); + rval = QLA_COMMAND_ERROR; + } } done: diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 70081b395fb2..622e7337affc 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -27,8 +27,6 @@ #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#include <target/target_core_base.h> -#include <target/target_core_fabric.h> #include "qla_def.h" #include "qla_target.h" @@ -1760,7 +1758,7 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; } - resp->handle = MAKE_HANDLE(qpair->req->id, h); + resp->handle = make_handle(qpair->req->id, h); resp->entry_type = ABTS_RESP_24XX; resp->entry_count = 1; resp->nport_handle = abts->nport_handle; @@ -2582,7 +2580,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, } else qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = MAKE_HANDLE(qpair->req->id, h); + pkt->handle = make_handle(qpair->req->id, h); pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); @@ -3095,7 +3093,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) } else qpair->req->outstanding_cmds[h] = (srb_t *)prm->cmd; - pkt->handle = MAKE_HANDLE(qpair->req->id, h); + pkt->handle = make_handle(qpair->req->id, h); pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); @@ -3816,7 +3814,7 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) return; } cmd->jiffies_at_free = get_jiffies_64(); - target_free_tag(sess->se_sess, &cmd->se_cmd); + cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); } EXPORT_SYMBOL(qlt_free_cmd); @@ -4150,7 +4148,7 @@ out_term: qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); qlt_decr_num_pend_cmds(vha); - target_free_tag(sess->se_sess, &cmd->se_cmd); + cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); ha->tgt.tgt_ops->put_sess(sess); @@ -4277,24 +4275,18 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, struct fc_port *sess, struct atio_from_isp *atio) { - struct se_session *se_sess = sess->se_sess; struct qla_tgt_cmd *cmd; - int tag, cpu; - tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); - if (tag < 0) + cmd = vha->hw->tgt.tgt_ops->get_cmd(sess); + if (!cmd) return NULL; - cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; - memset(cmd, 0, sizeof(struct qla_tgt_cmd)); cmd->cmd_type = TYPE_TGT_CMD; memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; qlt_incr_num_pend_cmds(vha); cmd->vha = vha; - cmd->se_cmd.map_tag = tag; - cmd->se_cmd.map_cpu = cpu; cmd->sess = sess; cmd->loop_id = sess->loop_id; cmd->conf_compl_supported = sess->conf_compl_supported; @@ -4747,11 +4739,11 @@ static int qlt_handle_login(struct scsi_qla_host *vha, qla24xx_post_newsess_work(vha, &port_id, iocb->u.isp24.port_name, iocb->u.isp24.u.plogi.node_name, - pla, FC4_TYPE_UNKNOWN); + pla, 0); else qla24xx_post_newsess_work(vha, &port_id, iocb->u.isp24.port_name, NULL, - pla, FC4_TYPE_UNKNOWN); + pla, 0); goto out; } @@ -5352,9 +5344,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; struct qla_hw_data *ha = vha->hw; struct fc_port *sess; - struct se_session *se_sess; struct qla_tgt_cmd *cmd; - int tag, cpu; unsigned long flags; if (unlikely(tgt->tgt_stop)) { @@ -5384,10 +5374,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, if (!sess) return; - se_sess = sess->se_sess; - - tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); - if (tag < 0) { + cmd = ha->tgt.tgt_ops->get_cmd(sess); + if (!cmd) { ql_dbg(ql_dbg_io, vha, 0x3009, "qla_target(%d): %s: Allocation of cmd failed\n", vha->vp_idx, __func__); @@ -5402,9 +5390,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, return; } - cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; - memset(cmd, 0, sizeof(struct qla_tgt_cmd)); - qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); memcpy(&cmd->atio, atio, sizeof(*atio)); @@ -5414,7 +5399,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; cmd->qpair = ha->base_qpair; - cmd->se_cmd.map_cpu = cpu; if (qfull) { cmd->q_full = 1; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 6539499e9e95..3cf8590feeac 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -671,6 +671,8 @@ struct qla_tgt_func_tmpl { void (*handle_data)(struct qla_tgt_cmd *); int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t, uint32_t); + struct qla_tgt_cmd *(*get_cmd)(struct fc_port *); + void (*rel_cmd)(struct qla_tgt_cmd *); void (*free_cmd)(struct qla_tgt_cmd *); void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); void (*free_session)(struct fc_port *); diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 5b0c057def2b..6aeb1c3fb7a8 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -870,7 +870,7 @@ bailout: static void qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp) { - tmp->capture_timestamp = jiffies; + tmp->capture_timestamp = cpu_to_le32(jiffies); } static void @@ -882,9 +882,10 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp) "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", v+0, v+1, v+2, v+3, v+4, v+5) != 6); - tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]; - tmp->driver_info[1] = v[5] << 8 | v[4]; - tmp->driver_info[2] = 0x12345678; + tmp->driver_info[0] = cpu_to_le32( + v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]); + tmp->driver_info[1] = cpu_to_le32(v[5] << 8 | v[4]); + tmp->driver_info[2] = __constant_cpu_to_le32(0x12345678); } static void @@ -894,10 +895,10 @@ qla27xx_firmware_info(struct scsi_qla_host *vha, tmp->firmware_version[0] = vha->hw->fw_major_version; tmp->firmware_version[1] = vha->hw->fw_minor_version; tmp->firmware_version[2] = vha->hw->fw_subminor_version; - tmp->firmware_version[3] = - vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes; - tmp->firmware_version[4] = - vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0]; + tmp->firmware_version[3] = cpu_to_le32( + vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes); + tmp->firmware_version[4] = cpu_to_le32( + vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0]); } static void diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h index d2a0014e8b21..bba8dc90acfb 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.h +++ b/drivers/scsi/qla2xxx/qla_tmpl.h @@ -18,11 +18,11 @@ struct __packed qla27xx_fwdt_template { __le32 entry_count; uint32_t template_version; - uint32_t capture_timestamp; + __le32 capture_timestamp; uint32_t template_checksum; uint32_t reserved_2; - uint32_t driver_info[3]; + __le32 driver_info[3]; uint32_t saved_state[16]; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index bb03c022e023..8ccd9ba1ddef 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.01.00.22-k" +#define QLA2XXX_VERSION "10.01.00.25-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index abe7f79bb789..1f0a185b2a95 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -268,6 +268,29 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work) transport_generic_free_cmd(&cmd->se_cmd, 0); } +static struct qla_tgt_cmd *tcm_qla2xxx_get_cmd(struct fc_port *sess) +{ + struct se_session *se_sess = sess->se_sess; + struct qla_tgt_cmd *cmd; + int tag, cpu; + + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); + if (tag < 0) + return NULL; + + cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; + memset(cmd, 0, sizeof(struct qla_tgt_cmd)); + cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; + + return cmd; +} + +static void tcm_qla2xxx_rel_cmd(struct qla_tgt_cmd *cmd) +{ + target_free_tag(cmd->sess->se_sess, &cmd->se_cmd); +} + /* * Called from qla_target_template->free_cmd(), and will call * tcm_qla2xxx_release_cmd via normal struct target_core_fabric_ops @@ -1549,6 +1572,8 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = { .handle_cmd = tcm_qla2xxx_handle_cmd, .handle_data = tcm_qla2xxx_handle_data, .handle_tmr = tcm_qla2xxx_handle_tmr, + .get_cmd = tcm_qla2xxx_get_cmd, + .rel_cmd = tcm_qla2xxx_rel_cmd, .free_cmd = tcm_qla2xxx_free_cmd, .free_mcmd = tcm_qla2xxx_free_mcmd, .free_session = tcm_qla2xxx_free_session, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 930e4803d888..56c24a73e0c7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -94,20 +94,6 @@ EXPORT_SYMBOL(scsi_logging_level); ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain); EXPORT_SYMBOL(scsi_sd_pm_domain); -/** - * scsi_put_command - Free a scsi command block - * @cmd: command block to free - * - * Returns: Nothing. - * - * Notes: The command must not belong to any lists. - */ -void scsi_put_command(struct scsi_cmnd *cmd) -{ - scsi_del_cmd_from_list(cmd); - BUG_ON(delayed_work_pending(&cmd->abort_work)); -} - #ifdef CONFIG_SCSI_LOGGING void scsi_log_send(struct scsi_cmnd *cmd) { @@ -764,10 +750,6 @@ MODULE_LICENSE("GPL"); module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels"); -/* This should go away in the future, it doesn't do anything anymore */ -bool scsi_use_blk_mq = true; -module_param_named(use_blk_mq, scsi_use_blk_mq, bool, S_IWUSR | S_IRUGO); - static int __init init_scsi(void) { int error; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ae2fa170f6ad..978be1602f71 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -2412,7 +2412,6 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) wake_up(&shost->host_wait); scsi_run_host_queues(shost); - scsi_put_command(scmd); kfree(rq); out_put_autopm_host: diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 610ee41fa54c..47835c4b4ee0 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -562,7 +562,6 @@ static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd) { scsi_mq_free_sgtables(cmd); scsi_uninit_cmd(cmd); - scsi_del_cmd_from_list(cmd); } /* Returns false when no more bytes to process, true if there are more */ @@ -1098,36 +1097,7 @@ static void scsi_cleanup_rq(struct request *rq) } } -/* Add a command to the list used by the aacraid and dpt_i2o drivers */ -void scsi_add_cmd_to_list(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct Scsi_Host *shost = sdev->host; - unsigned long flags; - - if (shost->use_cmd_list) { - spin_lock_irqsave(&sdev->list_lock, flags); - list_add_tail(&cmd->list, &sdev->cmd_list); - spin_unlock_irqrestore(&sdev->list_lock, flags); - } -} - -/* Remove a command from the list used by the aacraid and dpt_i2o drivers */ -void scsi_del_cmd_from_list(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct Scsi_Host *shost = sdev->host; - unsigned long flags; - - if (shost->use_cmd_list) { - spin_lock_irqsave(&sdev->list_lock, flags); - BUG_ON(list_empty(&cmd->list)); - list_del_init(&cmd->list); - spin_unlock_irqrestore(&sdev->list_lock, flags); - } -} - -/* Called after a request has been started. */ +/* Called before a request is prepared. See also scsi_mq_prep_fn(). */ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) { void *buf = cmd->sense_buffer; @@ -1135,7 +1105,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) struct request *rq = blk_mq_rq_from_pdu(cmd); unsigned int flags = cmd->flags & SCMD_PRESERVED_FLAGS; unsigned long jiffies_at_alloc; - int retries; + int retries, to_clear; bool in_flight; if (!blk_rq_is_scsi(rq) && !(flags & SCMD_INITIALIZED)) { @@ -1146,9 +1116,15 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) jiffies_at_alloc = cmd->jiffies_at_alloc; retries = cmd->retries; in_flight = test_bit(SCMD_STATE_INFLIGHT, &cmd->state); - /* zero out the cmd, except for the embedded scsi_request */ - memset((char *)cmd + sizeof(cmd->req), 0, - sizeof(*cmd) - sizeof(cmd->req) + dev->host->hostt->cmd_size); + /* + * Zero out the cmd, except for the embedded scsi_request. Only clear + * the driver-private command data if the LLD does not supply a + * function to initialize that data. + */ + to_clear = sizeof(*cmd) - sizeof(cmd->req); + if (!dev->host->hostt->init_cmd_priv) + to_clear += dev->host->hostt->cmd_size; + memset((char *)cmd + sizeof(cmd->req), 0, to_clear); cmd->device = dev; cmd->sense_buffer = buf; @@ -1160,7 +1136,6 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) if (in_flight) __set_bit(SCMD_STATE_INFLIGHT, &cmd->state); - scsi_add_cmd_to_list(cmd); } static blk_status_t scsi_setup_scsi_cmnd(struct scsi_device *sdev, @@ -1240,8 +1215,11 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req) * commands. The device must be brought online * before trying any recovery commands. */ - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to offline device\n"); + if (!sdev->offline_already) { + sdev->offline_already = true; + sdev_printk(KERN_ERR, sdev, + "rejecting I/O to offline device\n"); + } return BLK_STS_IOERR; case SDEV_DEL: /* @@ -1742,6 +1720,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, const bool unchecked_isa_dma = shost->unchecked_isa_dma; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); struct scatterlist *sg; + int ret = 0; if (unchecked_isa_dma) cmd->flags |= SCMD_UNCHECKED_ISA_DMA; @@ -1757,14 +1736,24 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost); } - return 0; + if (shost->hostt->init_cmd_priv) { + ret = shost->hostt->init_cmd_priv(shost, cmd); + if (ret < 0) + scsi_free_sense_buffer(unchecked_isa_dma, + cmd->sense_buffer); + } + + return ret; } static void scsi_mq_exit_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx) { + struct Scsi_Host *shost = set->driver_data; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + if (shost->hostt->exit_cmd_priv) + shost->hostt->exit_cmd_priv(shost, cmd); scsi_free_sense_buffer(cmd->flags & SCMD_UNCHECKED_ISA_DMA, cmd->sense_buffer); } @@ -2340,6 +2329,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) break; } + sdev->offline_already = false; sdev->sdev_state = state; return 0; @@ -2845,6 +2835,36 @@ scsi_target_unblock(struct device *dev, enum scsi_device_state new_state) } EXPORT_SYMBOL_GPL(scsi_target_unblock); +int +scsi_host_block(struct Scsi_Host *shost) +{ + struct scsi_device *sdev; + int ret = 0; + + shost_for_each_device(sdev, shost) { + ret = scsi_internal_device_block(sdev); + if (ret) + break; + } + return ret; +} +EXPORT_SYMBOL_GPL(scsi_host_block); + +int +scsi_host_unblock(struct Scsi_Host *shost, int new_state) +{ + struct scsi_device *sdev; + int ret = 0; + + shost_for_each_device(sdev, shost) { + ret = scsi_internal_device_unblock(sdev, new_state); + if (ret) + break; + } + return ret; +} +EXPORT_SYMBOL_GPL(scsi_host_unblock); + /** * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt * @sgl: scatter-gather list diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 3bff9f7aa684..22b6585e28b4 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -29,7 +29,6 @@ extern int scsi_init_hosts(void); extern void scsi_exit_hosts(void); /* scsi.c */ -extern bool scsi_use_blk_mq; int scsi_init_sense_cache(struct Scsi_Host *shost); void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING @@ -84,8 +83,6 @@ int scsi_eh_get_sense(struct list_head *work_q, int scsi_noretry_cmd(struct scsi_cmnd *scmd); /* scsi_lib.c */ -extern void scsi_add_cmd_to_list(struct scsi_cmnd *cmd); -extern void scsi_del_cmd_from_list(struct scsi_cmnd *cmd); extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd); extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 058079f915f1..f2437a7570ce 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -236,7 +236,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->sdev_state = SDEV_CREATED; INIT_LIST_HEAD(&sdev->siblings); INIT_LIST_HEAD(&sdev->same_target_siblings); - INIT_LIST_HEAD(&sdev->cmd_list); INIT_LIST_HEAD(&sdev->starved_entry); INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 677b5c5403d2..163dbcb741c1 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -856,7 +856,7 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \ struct bin_attribute *bin_attr, \ char *buf, loff_t off, size_t count) \ { \ - struct device *dev = container_of(kobj, struct device, kobj); \ + struct device *dev = kobj_to_dev(kobj); \ struct scsi_device *sdev = to_scsi_device(dev); \ struct scsi_vpd *vpd_page; \ int ret = -EINVAL; \ @@ -884,7 +884,7 @@ static ssize_t show_inquiry(struct file *filep, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct scsi_device *sdev = to_scsi_device(dev); if (!sdev->inquiry) @@ -1045,14 +1045,14 @@ sdev_show_blacklist(struct device *dev, struct device_attribute *attr, name = sdev_bflags_name[i]; if (name) - len += snprintf(buf + len, PAGE_SIZE - len, - "%s%s", len ? " " : "", name); + len += scnprintf(buf + len, PAGE_SIZE - len, + "%s%s", len ? " " : "", name); else - len += snprintf(buf + len, PAGE_SIZE - len, - "%sINVALID_BIT(%d)", len ? " " : "", i); + len += scnprintf(buf + len, PAGE_SIZE - len, + "%sINVALID_BIT(%d)", len ? " " : "", i); } if (len) - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } static DEVICE_ATTR(blacklist, S_IRUGO, sdev_show_blacklist, NULL); @@ -1181,7 +1181,7 @@ static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct scsi_device *sdev = to_scsi_device(dev); @@ -1207,7 +1207,7 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int i) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct scsi_device *sdev = to_scsi_device(dev); diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index ac35c301c792..41a950075913 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -18,11 +18,9 @@ static const char * scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - u32 lba = 0, txlen; + u32 lba, txlen; - lba |= ((cdb[1] & 0x1F) << 16); - lba |= (cdb[2] << 8); - lba |= cdb[3]; + lba = get_unaligned_be24(&cdb[1]) & 0x1fffff; /* * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256 * logical blocks shall be read (READ(6)) or written (WRITE(6)). diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index dfc726fa34e3..0ec1b31c75a9 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -86,9 +86,17 @@ struct iscsi_internal { struct transport_container session_cont; }; +/* Worker to perform connection failure on unresponsive connections + * completely in kernel space. + */ +static void stop_conn_work_fn(struct work_struct *work); +static DECLARE_WORK(stop_conn_work, stop_conn_work_fn); + static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ static struct workqueue_struct *iscsi_eh_timer_workq; +static struct workqueue_struct *iscsi_destroy_workq; + static DEFINE_IDA(iscsi_sess_ida); /* * list of registered transports and lock that must @@ -1609,8 +1617,10 @@ static struct sock *nls; static DEFINE_MUTEX(rx_queue_mutex); static LIST_HEAD(sesslist); +static LIST_HEAD(sessdestroylist); static DEFINE_SPINLOCK(sesslock); static LIST_HEAD(connlist); +static LIST_HEAD(connlist_err); static DEFINE_SPINLOCK(connlock); static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn) @@ -2028,6 +2038,14 @@ static void __iscsi_unbind_session(struct work_struct *work) ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); } +static void __iscsi_destroy_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, destroy_work); + + session->transport->destroy_session(session); +} + struct iscsi_cls_session * iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, int dd_size) @@ -2050,6 +2068,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, INIT_WORK(&session->block_work, __iscsi_block_session); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); INIT_WORK(&session->scan_work, iscsi_scan_session); + INIT_WORK(&session->destroy_work, __iscsi_destroy_session); spin_lock_init(&session->lock); /* this is released in the dev's release function */ @@ -2254,8 +2273,10 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) mutex_init(&conn->ep_mutex); INIT_LIST_HEAD(&conn->conn_list); + INIT_LIST_HEAD(&conn->conn_list_err); conn->transport = transport; conn->cid = cid; + conn->state = ISCSI_CONN_DOWN; /* this is released in the dev's release function */ if (!get_device(&session->dev)) @@ -2307,6 +2328,7 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) spin_lock_irqsave(&connlock, flags); list_del(&conn->conn_list); + list_del(&conn->conn_list_err); spin_unlock_irqrestore(&connlock, flags); transport_unregister_device(&conn->dev); @@ -2421,6 +2443,51 @@ int iscsi_offload_mesg(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(iscsi_offload_mesg); +static void stop_conn_work_fn(struct work_struct *work) +{ + struct iscsi_cls_conn *conn, *tmp; + unsigned long flags; + LIST_HEAD(recovery_list); + + spin_lock_irqsave(&connlock, flags); + if (list_empty(&connlist_err)) { + spin_unlock_irqrestore(&connlock, flags); + return; + } + list_splice_init(&connlist_err, &recovery_list); + spin_unlock_irqrestore(&connlock, flags); + + list_for_each_entry_safe(conn, tmp, &recovery_list, conn_list_err) { + uint32_t sid = iscsi_conn_get_sid(conn); + struct iscsi_cls_session *session; + + mutex_lock(&rx_queue_mutex); + + session = iscsi_session_lookup(sid); + if (session) { + if (system_state != SYSTEM_RUNNING) { + session->recovery_tmo = 0; + conn->transport->stop_conn(conn, + STOP_CONN_TERM); + } else { + conn->transport->stop_conn(conn, + STOP_CONN_RECOVER); + } + } + + list_del_init(&conn->conn_list_err); + + mutex_unlock(&rx_queue_mutex); + + /* we don't want to hold rx_queue_mutex for too long, + * for instance if many conns failed at the same time, + * since this stall other iscsi maintenance operations. + * Give other users a chance to proceed. + */ + cond_resched(); + } +} + void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) { struct nlmsghdr *nlh; @@ -2428,6 +2495,12 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = nlmsg_total_size(sizeof(*ev)); + unsigned long flags; + + spin_lock_irqsave(&connlock, flags); + list_add(&conn->conn_list_err, &connlist_err); + spin_unlock_irqrestore(&connlock, flags); + queue_work(system_unbound_wq, &stop_conn_work); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) @@ -2757,11 +2830,19 @@ static int iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) { struct iscsi_cls_conn *conn; + unsigned long flags; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) return -EINVAL; + spin_lock_irqsave(&connlock, flags); + if (!list_empty(&conn->conn_list_err)) { + spin_unlock_irqrestore(&connlock, flags); + return -EAGAIN; + } + spin_unlock_irqrestore(&connlock, flags); + ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n"); if (transport->destroy_conn) transport->destroy_conn(conn); @@ -3563,6 +3644,23 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) else transport->destroy_session(session); break; + case ISCSI_UEVENT_DESTROY_SESSION_ASYNC: + session = iscsi_session_lookup(ev->u.d_session.sid); + if (!session) + err = -EINVAL; + else if (iscsi_session_has_conns(ev->u.d_session.sid)) + err = -EBUSY; + else { + unsigned long flags; + + /* Prevent this session from being found again */ + spin_lock_irqsave(&sesslock, flags); + list_move(&session->sess_list, &sessdestroylist); + spin_unlock_irqrestore(&sesslock, flags); + + queue_work(iscsi_destroy_workq, &session->destroy_work); + } + break; case ISCSI_UEVENT_UNBIND_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); if (session) @@ -3612,8 +3710,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) break; case ISCSI_UEVENT_START_CONN: conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); - if (conn) + if (conn) { ev->r.retcode = transport->start_conn(conn); + if (!ev->r.retcode) + conn->state = ISCSI_CONN_UP; + } else err = -EINVAL; break; @@ -3810,6 +3911,26 @@ iscsi_conn_attr(tcp_xmit_wsf, ISCSI_PARAM_TCP_XMIT_WSF); iscsi_conn_attr(tcp_recv_wsf, ISCSI_PARAM_TCP_RECV_WSF); iscsi_conn_attr(local_ipaddr, ISCSI_PARAM_LOCAL_IPADDR); +static const char *const connection_state_names[] = { + [ISCSI_CONN_UP] = "up", + [ISCSI_CONN_DOWN] = "down", + [ISCSI_CONN_FAILED] = "failed" +}; + +static ssize_t show_conn_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); + const char *state = "unknown"; + + if (conn->state >= 0 && + conn->state < ARRAY_SIZE(connection_state_names)) + state = connection_state_names[conn->state]; + + return sprintf(buf, "%s\n", state); +} +static ISCSI_CLASS_ATTR(conn, state, S_IRUGO, show_conn_state, + NULL); #define iscsi_conn_ep_attr_show(param) \ static ssize_t show_conn_ep_param_##param(struct device *dev, \ @@ -3879,6 +4000,7 @@ static struct attribute *iscsi_conn_attrs[] = { &dev_attr_conn_tcp_xmit_wsf.attr, &dev_attr_conn_tcp_recv_wsf.attr, &dev_attr_conn_local_ipaddr.attr, + &dev_attr_conn_state.attr, NULL, }; @@ -3950,6 +4072,8 @@ static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj, param = ISCSI_PARAM_TCP_RECV_WSF; else if (attr == &dev_attr_conn_local_ipaddr.attr) param = ISCSI_PARAM_LOCAL_IPADDR; + else if (attr == &dev_attr_conn_state.attr) + return S_IRUGO; else { WARN_ONCE(1, "Invalid conn attr"); return 0; @@ -4608,8 +4732,16 @@ static __init int iscsi_transport_init(void) goto release_nls; } + iscsi_destroy_workq = create_singlethread_workqueue("iscsi_destroy"); + if (!iscsi_destroy_workq) { + err = -ENOMEM; + goto destroy_wq; + } + return 0; +destroy_wq: + destroy_workqueue(iscsi_eh_timer_workq); release_nls: netlink_kernel_release(nls); unregister_flashnode_bus: @@ -4631,6 +4763,7 @@ unregister_transport_class: static void __exit iscsi_transport_exit(void) { + destroy_workqueue(iscsi_destroy_workq); destroy_workqueue(iscsi_eh_timer_workq); netlink_kernel_release(nls); bus_unregister(&iscsi_flashnode_bus); diff --git a/drivers/scsi/smartpqi/Kconfig b/drivers/scsi/smartpqi/Kconfig index bc6506884e3b..d3311c014863 100644 --- a/drivers/scsi/smartpqi/Kconfig +++ b/drivers/scsi/smartpqi/Kconfig @@ -53,4 +53,4 @@ config SCSI_SMARTPQI Note: the aacraid driver will not manage a smartpqi controller. You need to enable smartpqi for smartpqi controllers. For more information, please see - Documentation/scsi/smartpqi.txt + Documentation/scsi/smartpqi.rst diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index b7492568e02f..cd157f11eb22 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1614,28 +1614,28 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info, "%d:%d:", ctrl_info->scsi_host->host_no, device->bus); if (device->target_lun_valid) - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, "%d:%d", device->target, device->lun); else - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, "-:-"); if (pqi_is_logical_device(device)) - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %08x%08x", *((u32 *)&device->scsi3addr), *((u32 *)&device->scsi3addr[4])); else - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %016llx", device->sas_address); - count += snprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %s %.8s %.16s ", pqi_device_type(device), device->vendor, @@ -1643,19 +1643,19 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info, if (pqi_is_logical_device(device)) { if (device->devtype == TYPE_DISK) - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, "SSDSmartPathCap%c En%c %-12s", device->raid_bypass_configured ? '+' : '-', device->raid_bypass_enabled ? '+' : '-', pqi_raid_level_to_string(device->raid_level)); } else { - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, "AIO%c", device->aio_enabled ? '+' : '-'); if (device->devtype == TYPE_DISK || device->devtype == TYPE_ZBC) - count += snprintf(buffer + count, + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " qd=%-6d", device->queue_depth); } @@ -6191,14 +6191,14 @@ static ssize_t pqi_lockup_action_show(struct device *dev, for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) { if (pqi_lockup_actions[i].action == pqi_lockup_action) - count += snprintf(buffer + count, PAGE_SIZE - count, + count += scnprintf(buffer + count, PAGE_SIZE - count, "[%s] ", pqi_lockup_actions[i].name); else - count += snprintf(buffer + count, PAGE_SIZE - count, + count += scnprintf(buffer + count, PAGE_SIZE - count, "%s ", pqi_lockup_actions[i].name); } - count += snprintf(buffer + count, PAGE_SIZE - count, "\n"); + count += scnprintf(buffer + count, PAGE_SIZE - count, "\n"); return count; } diff --git a/drivers/scsi/snic/vnic_devcmd.h b/drivers/scsi/snic/vnic_devcmd.h index d81b4f0ceaaa..0e0fa38f8d90 100644 --- a/drivers/scsi/snic/vnic_devcmd.h +++ b/drivers/scsi/snic/vnic_devcmd.h @@ -208,7 +208,7 @@ struct vnic_devcmd_notify { struct vnic_devcmd_provinfo { u8 oui[3]; u8 type; - u8 data[0]; + u8 data[]; }; /* diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index e4240e4ae8bb..1c270e6034d5 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -79,7 +79,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ CDC_MRW|CDC_MRW_W|CDC_RAM) -static DEFINE_MUTEX(sr_mutex); static int sr_probe(struct device *); static int sr_remove(struct device *); static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); @@ -536,9 +535,9 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) scsi_autopm_get_device(sdev); check_disk_change(bdev); - mutex_lock(&sr_mutex); + mutex_lock(&cd->lock); ret = cdrom_open(&cd->cdi, bdev, mode); - mutex_unlock(&sr_mutex); + mutex_unlock(&cd->lock); scsi_autopm_put_device(sdev); if (ret) @@ -551,10 +550,10 @@ out: static void sr_block_release(struct gendisk *disk, fmode_t mode) { struct scsi_cd *cd = scsi_cd(disk); - mutex_lock(&sr_mutex); + mutex_lock(&cd->lock); cdrom_release(&cd->cdi, mode); scsi_cd_put(cd); - mutex_unlock(&sr_mutex); + mutex_unlock(&cd->lock); } static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, @@ -565,7 +564,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, void __user *argp = (void __user *)arg; int ret; - mutex_lock(&sr_mutex); + mutex_lock(&cd->lock); ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, (mode & FMODE_NDELAY) != 0); @@ -595,7 +594,7 @@ put: scsi_autopm_put_device(sdev); out: - mutex_unlock(&sr_mutex); + mutex_unlock(&cd->lock); return ret; } @@ -608,7 +607,7 @@ static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsign void __user *argp = compat_ptr(arg); int ret; - mutex_lock(&sr_mutex); + mutex_lock(&cd->lock); ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, (mode & FMODE_NDELAY) != 0); @@ -638,7 +637,7 @@ put: scsi_autopm_put_device(sdev); out: - mutex_unlock(&sr_mutex); + mutex_unlock(&cd->lock); return ret; } @@ -745,6 +744,7 @@ static int sr_probe(struct device *dev) disk = alloc_disk(1); if (!disk) goto fail_free; + mutex_init(&cd->lock); spin_lock(&sr_index_lock); minor = find_first_zero_bit(sr_index_bits, SR_DISKS); @@ -1055,6 +1055,8 @@ static void sr_kref_release(struct kref *kref) put_disk(disk); + mutex_destroy(&cd->lock); + kfree(cd); } diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index a2bb7b8bace5..339c624e04d8 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -20,6 +20,7 @@ #include <linux/genhd.h> #include <linux/kref.h> +#include <linux/mutex.h> #define MAX_RETRIES 3 #define SR_TIMEOUT (30 * HZ) @@ -51,6 +52,7 @@ typedef struct scsi_cd { bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */ struct cdrom_device_info cdi; + struct mutex lock; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ struct kref kref; diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index 17a56c87d383..1f988a1b9166 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -67,9 +67,6 @@ void sr_vendor_init(Scsi_CD *cd) { -#ifndef CONFIG_BLK_DEV_SR_VENDOR - cd->vendor = VENDOR_SCSI3; -#else const char *vendor = cd->device->vendor; const char *model = cd->device->model; @@ -118,7 +115,6 @@ void sr_vendor_init(Scsi_CD *cd) CDC_PLAY_AUDIO ); } -#endif } @@ -132,10 +128,8 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) struct ccs_modesel_head *modesel; int rc, density = 0; -#ifdef CONFIG_BLK_DEV_SR_VENDOR if (cd->vendor == VENDOR_TOSHIBA) density = (blocklength > 2048) ? 0x81 : 0x83; -#endif buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) @@ -223,7 +217,6 @@ int sr_cd_check(struct cdrom_device_info *cdi) } break; -#ifdef CONFIG_BLK_DEV_SR_VENDOR case VENDOR_NEC:{ unsigned long min, sec, frame; cgc.cmd[0] = 0xde; @@ -316,7 +309,6 @@ int sr_cd_check(struct cdrom_device_info *cdi) sector = buffer[11] + (buffer[10] << 8) + (buffer[9] << 16) + (buffer[8] << 24); break; -#endif /* CONFIG_BLK_DEV_SR_VENDOR */ default: /* should not happen */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 393f3019ccac..c5f9b348b438 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file Documentation/scsi/st.txt for more information. + file Documentation/scsi/st.rst for more information. History: Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. @@ -45,6 +45,7 @@ static const char *verstr = "20160209"; #include <linux/uaccess.h> #include <asm/dma.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_dbg.h> @@ -2680,8 +2681,7 @@ static void deb_space_print(struct scsi_tape *STp, int direction, char *units, u if (!debugging) return; - sc = cmd[2] & 0x80 ? 0xff000000 : 0; - sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23); if (direction) sc = -sc; st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n", diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 33287b6bdf0e..d4f10c0d813c 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -236,7 +236,7 @@ struct req_msg { u8 data_dir; u8 payload_sz; /* payload size in 4-byte, not used */ u8 cdb[STEX_CDB_LENGTH]; - u32 variable[0]; + u32 variable[]; }; struct status_msg { diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index d14c2243e02a..e2005aeddc2d 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -46,7 +46,7 @@ config SCSI_UFSHCD The module will be called ufshcd. To compile this driver as a module, choose M here and read - <file:Documentation/scsi/ufs.txt>. + <file:Documentation/scsi/ufs.rst>. However, do not compile this as a module if your root file system (the one containing the directory /) is located on a UFS device. diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index 56a6a1ed5ec2..da065a259f6e 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -192,7 +192,7 @@ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba, * and device TX LCC are disabled once link startup is * completed. */ - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + ufshcd_disable_host_tx_lcc(hba); /* * Disabling Autohibern8 feature in cadence UFS diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 5d6487350a6c..074a6a055a4c 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -235,7 +235,7 @@ static int ufs_hisi_link_startup_pre_change(struct ufs_hba *hba) ufshcd_writel(hba, reg, REG_AUTO_HIBERNATE_IDLE_TIMER); /* Unipro PA_Local_TX_LCC_Enable */ - ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x155E, 0x0), 0x0); + ufshcd_disable_host_tx_lcc(hba); /* close Unipro VS_Mk2ExtnSupport */ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), 0x0); ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), &value); diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index 53eae5fe2ade..40a66b31b31f 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -66,6 +66,21 @@ static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) } } +static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (status == PRE_CHANGE) { + if (host->unipro_lpm) + hba->hba_enable_delay_us = 0; + else + hba->hba_enable_delay_us = 600; + } + + return 0; +} + static int ufs_mtk_bind_mphy(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); @@ -107,6 +122,7 @@ static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on) if (on) { ufs_mtk_ref_clk_notify(on, res); + ufshcd_delay_us(host->ref_clk_ungating_wait_us, 10); ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL); } else { ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL); @@ -132,12 +148,40 @@ static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on) out: host->ref_clk_enabled = on; - if (!on) + if (!on) { + ufshcd_delay_us(host->ref_clk_gating_wait_us, 10); ufs_mtk_ref_clk_notify(on, res); + } return 0; } +static void ufs_mtk_setup_ref_clk_wait_us(struct ufs_hba *hba, + u16 gating_us, u16 ungating_us) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (hba->dev_info.clk_gating_wait_us) { + host->ref_clk_gating_wait_us = + hba->dev_info.clk_gating_wait_us; + } else { + host->ref_clk_gating_wait_us = gating_us; + } + + host->ref_clk_ungating_wait_us = ungating_us; +} + +static u32 ufs_mtk_link_get_state(struct ufs_hba *hba) +{ + u32 val; + + ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL); + val = ufshcd_readl(hba, REG_UFS_PROBE); + val = val >> 28; + + return val; +} + /** * ufs_mtk_setup_clocks - enables/disable clocks * @hba: host controller instance @@ -150,7 +194,7 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - int ret = -EINVAL; + int ret = 0; /* * In case ufs_mtk_init() is not yet done, simply ignore. @@ -160,19 +204,24 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, if (!host) return 0; - switch (status) { - case PRE_CHANGE: - if (!on) { + if (!on && status == PRE_CHANGE) { + if (!ufshcd_is_link_active(hba)) { ufs_mtk_setup_ref_clk(hba, on); ret = phy_power_off(host->mphy); + } else { + /* + * Gate ref-clk if link state is in Hibern8 + * triggered by Auto-Hibern8. + */ + if (!ufshcd_can_hibern8_during_gating(hba) && + ufshcd_is_auto_hibern8_enabled(hba) && + ufs_mtk_link_get_state(hba) == + VS_LINK_HIBERN8) + ufs_mtk_setup_ref_clk(hba, on); } - break; - case POST_CHANGE: - if (on) { - ret = phy_power_on(host->mphy); - ufs_mtk_setup_ref_clk(hba, on); - } - break; + } else if (on && status == POST_CHANGE) { + ret = phy_power_on(host->mphy); + ufs_mtk_setup_ref_clk(hba, on); } return ret; @@ -285,11 +334,36 @@ static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, return ret; } +static int ufs_mtk_unipro_set_pm(struct ufs_hba *hba, u32 lpm) +{ + int ret; + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + ret = ufshcd_dme_set(hba, + UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), + lpm); + if (!ret) + host->unipro_lpm = lpm; + + return ret; +} + static int ufs_mtk_pre_link(struct ufs_hba *hba) { int ret; u32 tmp; + ufs_mtk_unipro_set_pm(hba, 0); + + /* + * Setting PA_Local_TX_LCC_Enable to 0 before link startup + * to make sure that both host and device TX LCC are disabled + * once link startup is completed. + */ + ret = ufshcd_disable_host_tx_lcc(hba); + if (ret) + return ret; + /* disable deep stall */ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); if (ret) @@ -321,9 +395,6 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba) static int ufs_mtk_post_link(struct ufs_hba *hba) { - /* disable device LCC */ - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); - /* enable unipro clock gating feature */ ufs_mtk_cfg_unipro_cg(hba, true); @@ -390,9 +461,7 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) if (err) return err; - err = ufshcd_dme_set(hba, - UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), - 0); + err = ufs_mtk_unipro_set_pm(hba, 0); if (err) return err; @@ -413,14 +482,10 @@ static int ufs_mtk_link_set_lpm(struct ufs_hba *hba) { int err; - err = ufshcd_dme_set(hba, - UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), - 1); + err = ufs_mtk_unipro_set_pm(hba, 1); if (err) { /* Resume UniPro state for following error recovery */ - ufshcd_dme_set(hba, - UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), - 0); + ufs_mtk_unipro_set_pm(hba, 0); return err; } @@ -436,10 +501,11 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) err = ufs_mtk_link_set_lpm(hba); if (err) return -EAGAIN; - phy_power_off(host->mphy); - ufs_mtk_setup_ref_clk(hba, false); } + if (!ufshcd_is_link_active(hba)) + phy_power_off(host->mphy); + return 0; } @@ -448,9 +514,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) struct ufs_mtk_host *host = ufshcd_get_variant(hba); int err; - if (ufshcd_is_link_hibern8(hba)) { - ufs_mtk_setup_ref_clk(hba, true); + if (!ufshcd_is_link_active(hba)) phy_power_on(host->mphy); + + if (ufshcd_is_link_hibern8(hba)) { err = ufs_mtk_link_set_hpm(hba); if (err) return err; @@ -477,9 +544,24 @@ static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba) static int ufs_mtk_apply_dev_quirks(struct ufs_hba *hba) { struct ufs_dev_info *dev_info = &hba->dev_info; + u16 mid = dev_info->wmanufacturerid; - if (dev_info->wmanufacturerid == UFS_VENDOR_SAMSUNG) + if (mid == UFS_VENDOR_SAMSUNG) { + hba->dev_quirks &= ~UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE; ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 6); + } + + /* + * Decide waiting time before gating reference clock and + * after ungating reference clock according to vendors' + * requirements. + */ + if (mid == UFS_VENDOR_SAMSUNG) + ufs_mtk_setup_ref_clk_wait_us(hba, 1, 1); + else if (mid == UFS_VENDOR_SKHYNIX) + ufs_mtk_setup_ref_clk_wait_us(hba, 30, 30); + else if (mid == UFS_VENDOR_TOSHIBA) + ufs_mtk_setup_ref_clk_wait_us(hba, 100, 32); return 0; } @@ -494,6 +576,7 @@ static struct ufs_hba_variant_ops ufs_hba_mtk_vops = { .name = "mediatek.ufshci", .init = ufs_mtk_init, .setup_clocks = ufs_mtk_setup_clocks, + .hce_enable_notify = ufs_mtk_hce_enable_notify, .link_startup_notify = ufs_mtk_link_startup_notify, .pwr_change_notify = ufs_mtk_pwr_change_notify, .apply_dev_quirks = ufs_mtk_apply_dev_quirks, diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h index fccdd979d6fb..5bbd3e9cbae2 100644 --- a/drivers/scsi/ufs/ufs-mediatek.h +++ b/drivers/scsi/ufs/ufs-mediatek.h @@ -54,6 +54,18 @@ #define VS_UNIPROPOWERDOWNCONTROL 0xD0A8 /* + * Vendor specific link state + */ +enum { + VS_LINK_DISABLED = 0, + VS_LINK_DOWN = 1, + VS_LINK_UP = 2, + VS_LINK_HIBERN8 = 3, + VS_LINK_LOST = 4, + VS_LINK_CFG = 5, +}; + +/* * SiP commands */ #define MTK_SIP_UFS_CONTROL MTK_SIP_SMC_CMD(0x276) @@ -79,7 +91,10 @@ enum { struct ufs_mtk_host { struct ufs_hba *hba; struct phy *mphy; + bool unipro_lpm; bool ref_clk_enabled; + u16 ref_clk_ungating_wait_us; + u16 ref_clk_gating_wait_us; }; #endif /* !_UFS_MEDIATEK_H */ diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index c69c29a1ceb9..19aa5c44e0da 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -10,6 +10,7 @@ #include <linux/phy/phy.h> #include <linux/gpio/consumer.h> #include <linux/reset-controller.h> +#include <linux/devfreq.h> #include "ufshcd.h" #include "ufshcd-pltfrm.h" @@ -38,7 +39,6 @@ enum { static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, u32 clk_cycles); @@ -554,9 +554,7 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, * completed. */ if (ufshcd_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41) - err = ufshcd_dme_set(hba, - UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), - 0); + err = ufshcd_disable_host_tx_lcc(hba); break; case POST_CHANGE: @@ -674,7 +672,7 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) } } -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) { int err = 0; @@ -705,7 +703,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) vote = ufs_qcom_get_bus_vote(host, mode); if (vote >= 0) - err = ufs_qcom_set_bus_vote(host, vote); + err = __ufs_qcom_set_bus_vote(host, vote); else err = vote; @@ -716,6 +714,35 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int vote, err; + + /* + * In case ufs_qcom_init() is not yet done, simply ignore. + * This ufs_qcom_set_bus_vote() shall be called from + * ufs_qcom_init() after init is done. + */ + if (!host) + return 0; + + if (on) { + vote = host->bus_vote.saved_vote; + if (vote == host->bus_vote.min_bw_vote) + ufs_qcom_update_bus_bw_vote(host); + } else { + vote = host->bus_vote.min_bw_vote; + } + + err = __ufs_qcom_set_bus_vote(host, vote); + if (err) + dev_err(hba->dev, "%s: set bus vote failed %d\n", + __func__, err); + + return err; +} + static ssize_t show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) @@ -792,7 +819,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return 0; } -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +static int ufs_qcom_set_bus_vote(struct ufs_hba *host, bool on) { return 0; } @@ -817,11 +844,27 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) /* * If we are here to disable this clock it might be immediately * after entering into hibern8 in which case we need to make - * sure that device ref_clk is active at least 1us after the + * sure that device ref_clk is active for specific time after * hibern8 enter. */ - if (!enable) - udelay(1); + if (!enable) { + unsigned long gating_wait; + + gating_wait = host->hba->dev_info.clk_gating_wait_us; + if (!gating_wait) { + udelay(1); + } else { + /* + * bRefClkGatingWaitTime defines the minimum + * time for which the reference clock is + * required by device during transition from + * HS-MODE to LS-MODE or HIBERN8 state. Give it + * more delay to be on the safe side. + */ + gating_wait += 10; + usleep_range(gating_wait, gating_wait + 10); + } + } writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); @@ -898,6 +941,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, if (!ufshcd_is_hs_mode(&hba->pwr_info) && ufshcd_is_hs_mode(dev_req_params)) ufs_qcom_dev_ref_clk_ctrl(host, true); + + if (host->hw_ver.major >= 0x4) { + if (dev_req_params->gear_tx == UFS_HS_G4) { + /* INITIAL ADAPT */ + ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + PA_INITIAL_ADAPT); + } else { + /* NO ADAPT */ + ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + PA_NO_ADAPT); + } + } break; case POST_CHANGE: if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, @@ -956,6 +1013,9 @@ static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); + if (hba->dev_info.wmanufacturerid == UFS_VENDOR_WDC) + hba->dev_quirks |= UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE; + return err; } @@ -1030,8 +1090,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err; - int vote = 0; + int err = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -1041,28 +1100,28 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (!host) return 0; - if (on && (status == POST_CHANGE)) { - /* enable the device ref clock for HS mode*/ - if (ufshcd_is_hs_mode(&hba->pwr_info)) - ufs_qcom_dev_ref_clk_ctrl(host, true); - vote = host->bus_vote.saved_vote; - if (vote == host->bus_vote.min_bw_vote) - ufs_qcom_update_bus_bw_vote(host); - - } else if (!on && (status == PRE_CHANGE)) { - if (!ufs_qcom_is_link_active(hba)) { - /* disable device ref_clk */ - ufs_qcom_dev_ref_clk_ctrl(host, false); + switch (status) { + case PRE_CHANGE: + if (on) { + err = ufs_qcom_set_bus_vote(hba, true); + } else { + if (!ufs_qcom_is_link_active(hba)) { + /* disable device ref_clk */ + ufs_qcom_dev_ref_clk_ctrl(host, false); + } } - - vote = host->bus_vote.min_bw_vote; + break; + case POST_CHANGE: + if (on) { + /* enable the device ref clock for HS mode*/ + if (ufshcd_is_hs_mode(&hba->pwr_info)) + ufs_qcom_dev_ref_clk_ctrl(host, true); + } else { + err = ufs_qcom_set_bus_vote(hba, false); + } + break; } - err = ufs_qcom_set_bus_vote(host, vote); - if (err) - dev_err(hba->dev, "%s: set bus vote failed %d\n", - __func__, err); - return err; } @@ -1238,6 +1297,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_bus_vote(hba, true); ufs_qcom_setup_clocks(hba, true, POST_CHANGE); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) @@ -1630,6 +1690,29 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba) usleep_range(10, 15); } +#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) +static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, + struct devfreq_dev_profile *p, + void *data) +{ + static struct devfreq_simple_ondemand_data *d; + + if (!data) + return; + + d = (struct devfreq_simple_ondemand_data *)data; + p->polling_ms = 60; + d->upthreshold = 70; + d->downdifferential = 5; +} +#else +static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, + struct devfreq_dev_profile *p, + void *data) +{ +} +#endif + /** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * @@ -1651,6 +1734,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .resume = ufs_qcom_resume, .dbg_register_dump = ufs_qcom_dump_dbg_regs, .device_reset = ufs_qcom_device_reset, + .config_scaling_param = ufs_qcom_config_scaling_param, }; /** diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index dbdf8b01abed..92a63eebdca9 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -210,8 +210,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, if (param_size > 8) return -EINVAL; + pm_runtime_get_sync(hba->dev); ret = ufshcd_read_desc_param(hba, desc_id, desc_index, param_offset, desc_buf, param_size); + pm_runtime_put_sync(hba->dev); if (ret) return -EINVAL; switch (param_size) { @@ -558,6 +560,7 @@ static ssize_t _name##_show(struct device *dev, \ desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_ATOMIC); \ if (!desc_buf) \ return -ENOMEM; \ + pm_runtime_get_sync(hba->dev); \ ret = ufshcd_query_descriptor_retry(hba, \ UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \ 0, 0, desc_buf, &desc_len); \ @@ -574,6 +577,7 @@ static ssize_t _name##_show(struct device *dev, \ goto out; \ ret = snprintf(buf, PAGE_SIZE, "%s\n", desc_buf); \ out: \ + pm_runtime_put_sync(hba->dev); \ kfree(desc_buf); \ return ret; \ } \ @@ -604,9 +608,13 @@ static ssize_t _name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ bool flag; \ + int ret; \ struct ufs_hba *hba = dev_get_drvdata(dev); \ - if (ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \ - QUERY_FLAG_IDN##_uname, &flag)) \ + pm_runtime_get_sync(hba->dev); \ + ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \ + QUERY_FLAG_IDN##_uname, &flag); \ + pm_runtime_put_sync(hba->dev); \ + if (ret) \ return -EINVAL; \ return sprintf(buf, "%s\n", flag ? "true" : "false"); \ } \ @@ -644,8 +652,12 @@ static ssize_t _name##_show(struct device *dev, \ { \ struct ufs_hba *hba = dev_get_drvdata(dev); \ u32 value; \ - if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \ - QUERY_ATTR_IDN##_uname, 0, 0, &value)) \ + int ret; \ + pm_runtime_get_sync(hba->dev); \ + ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \ + QUERY_ATTR_IDN##_uname, 0, 0, &value); \ + pm_runtime_put_sync(hba->dev); \ + if (ret) \ return -EINVAL; \ return sprintf(buf, "0x%08X\n", value); \ } \ @@ -766,9 +778,13 @@ static ssize_t dyn_cap_needed_attribute_show(struct device *dev, struct scsi_device *sdev = to_scsi_device(dev); struct ufs_hba *hba = shost_priv(sdev->host); u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); + int ret; - if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, - QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value)) + pm_runtime_get_sync(hba->dev); + ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value); + pm_runtime_put_sync(hba->dev); + if (ret) return -EINVAL; return sprintf(buf, "0x%08X\n", value); } diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index cfe380348bf0..990cb48e2403 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -167,6 +167,7 @@ enum attr_idn { QUERY_ATTR_IDN_FFU_STATUS = 0x14, QUERY_ATTR_IDN_PSA_STATE = 0x15, QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16, + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17, }; /* Descriptor idn for Query requests */ @@ -534,6 +535,8 @@ struct ufs_dev_info { u16 wmanufacturerid; /*UFS device Product Name */ u8 *model; + u16 wspecversion; + u32 clk_gating_wait_us; }; /** diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index d0ab147f98d3..df7a1e6805a3 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -15,6 +15,7 @@ #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD +#define UFS_VENDOR_WDC 0x145 /** * ufs_dev_fix - ufs device quirk info diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index 3b19de3ae9a3..8f78a8151499 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -44,7 +44,7 @@ static int ufs_intel_disable_lcc(struct ufs_hba *hba) ufshcd_dme_get(hba, attr, &lcc_enable); if (lcc_enable) - ufshcd_dme_set(hba, attr, 0); + ufshcd_disable_host_tx_lcc(hba); return 0; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2d705694636c..e04e8b8bdca6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -42,6 +42,7 @@ #include <linux/nls.h> #include <linux/of.h> #include <linux/bitfield.h> +#include <linux/blk-pm.h> #include "ufshcd.h" #include "ufs_quirks.h" #include "unipro.h" @@ -91,6 +92,9 @@ /* default delay of autosuspend: 2000 ms */ #define RPM_AUTOSUSPEND_DELAY_MS 2000 +/* Default value of wait time before gating device ref clock */ +#define UFSHCD_REF_CLK_GATING_WAIT_US 0xFF /* microsecs */ + #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ int _ret; \ @@ -532,6 +536,18 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) hba->pwr_info.hs_rate); } +void ufshcd_delay_us(unsigned long us, unsigned long tolerance) +{ + if (!us) + return; + + if (us < 10) + udelay(us); + else + usleep_range(us, us + tolerance); +} +EXPORT_SYMBOL_GPL(ufshcd_delay_us); + /* * ufshcd_wait_for_register - wait for register value to change * @hba - per-adapter interface @@ -642,11 +658,7 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) */ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) { - if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR) - ufshcd_writel(hba, (1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR); - else - ufshcd_writel(hba, ~(1 << pos), - REG_UTP_TRANSFER_REQ_LIST_CLEAR); + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR); } /** @@ -656,10 +668,7 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) */ static inline void ufshcd_utmrl_clear(struct ufs_hba *hba, u32 pos) { - if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR) - ufshcd_writel(hba, (1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); - else - ufshcd_writel(hba, ~(1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); } /** @@ -1191,6 +1200,9 @@ static int ufshcd_devfreq_target(struct device *dev, if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; + clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list); + /* Override with the closest supported frequency */ + *freq = (unsigned long) clk_round_rate(clki->clk, *freq); spin_lock_irqsave(hba->host->host_lock, irq_flags); if (ufshcd_eh_in_progress(hba)) { spin_unlock_irqrestore(hba->host->host_lock, irq_flags); @@ -1205,8 +1217,11 @@ static int ufshcd_devfreq_target(struct device *dev, goto out; } - clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list); + /* Decide based on the rounded-off frequency and update */ scale_up = (*freq == clki->max_freq) ? true : false; + if (!scale_up) + *freq = clki->min_freq; + /* Update the frequency */ if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) { spin_unlock_irqrestore(hba->host->host_lock, irq_flags); ret = 0; @@ -1254,6 +1269,8 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_clk_scaling *scaling = &hba->clk_scaling; unsigned long flags; + struct list_head *clk_list = &hba->clk_list_head; + struct ufs_clk_info *clki; if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; @@ -1264,6 +1281,13 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, if (!scaling->window_start_t) goto start_window; + clki = list_first_entry(clk_list, struct ufs_clk_info, list); + /* + * If current frequency is 0, then the ondemand governor considers + * there's no initial frequency set. And it always requests to set + * to max. frequency. + */ + stat->current_frequency = clki->curr_freq; if (scaling->is_busy_started) scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(), scaling->busy_start_t)); @@ -1292,6 +1316,17 @@ static struct devfreq_dev_profile ufs_devfreq_profile = { .get_dev_status = ufshcd_devfreq_get_dev_status, }; +#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) +static struct devfreq_simple_ondemand_data ufs_ondemand_data = { + .upthreshold = 70, + .downdifferential = 5, +}; + +static void *gov_data = &ufs_ondemand_data; +#else +static void *gov_data; /* NULL */ +#endif + static int ufshcd_devfreq_init(struct ufs_hba *hba) { struct list_head *clk_list = &hba->clk_list_head; @@ -1307,10 +1342,12 @@ static int ufshcd_devfreq_init(struct ufs_hba *hba) dev_pm_opp_add(hba->dev, clki->min_freq, 0); dev_pm_opp_add(hba->dev, clki->max_freq, 0); + ufshcd_vops_config_scaling_param(hba, &ufs_devfreq_profile, + gov_data); devfreq = devfreq_add_device(hba->dev, &ufs_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, - NULL); + gov_data); if (IS_ERR(devfreq)) { ret = PTR_ERR(devfreq); dev_err(hba->dev, "Unable to register with devfreq %d\n", ret); @@ -1518,6 +1555,11 @@ start: */ if (ufshcd_can_hibern8_during_gating(hba) && ufshcd_is_link_hibern8(hba)) { + if (async) { + rc = -EAGAIN; + hba->clk_gating.active_reqs--; + break; + } spin_unlock_irqrestore(hba->host->host_lock, flags); flush_work(&hba->clk_gating.ungate_work); spin_lock_irqsave(hba->host->host_lock, flags); @@ -2093,13 +2135,8 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) return sg_segments; if (sg_segments) { - if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) - lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16((u16)(sg_segments * - sizeof(struct ufshcd_sg_entry))); - else - lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16((u16) (sg_segments)); + lrbp->utr_descriptor_ptr->prd_table_length = + cpu_to_le16((u16)sg_segments); prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; @@ -2363,6 +2400,27 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id) return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE; } +static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) +{ + struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr; + struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; + dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr + + i * sizeof(struct utp_transfer_cmd_desc); + u16 response_offset = offsetof(struct utp_transfer_cmd_desc, + response_upiu); + u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); + + lrb->utr_descriptor_ptr = utrdlp + i; + lrb->utrd_dma_addr = hba->utrdl_dma_addr + + i * sizeof(struct utp_transfer_req_desc); + lrb->ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i); + lrb->ucd_req_dma_addr = cmd_desc_element_addr; + lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; + lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; + lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; + lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; +} + /** * ufshcd_queuecommand - main entry point for SCSI requests * @host: SCSI host pointer @@ -2452,7 +2510,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) /* issue command to the controller */ spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_vops_setup_xfer_req(hba, tag, (lrbp->cmd ? true : false)); + ufshcd_vops_setup_xfer_req(hba, tag, true); ufshcd_send_command(hba, tag); out_unlock: spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2639,7 +2697,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, /* Make sure descriptors are ready before ringing the doorbell */ wmb(); spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_vops_setup_xfer_req(hba, tag, (lrbp->cmd ? true : false)); + ufshcd_vops_setup_xfer_req(hba, tag, false); ufshcd_send_command(hba, tag); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -3276,6 +3334,31 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba, param_offset, param_read_buf, param_size); } +static int ufshcd_get_ref_clk_gating_wait(struct ufs_hba *hba) +{ + int err = 0; + u32 gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + + if (hba->dev_info.wspecversion >= 0x300) { + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME, 0, 0, + &gating_wait); + if (err) + dev_err(hba->dev, "Failed reading bRefClkGatingWait. err = %d, use default %uus\n", + err, gating_wait); + + if (gating_wait == 0) { + gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + dev_err(hba->dev, "Undefined ref clk gating wait time, use default %uus\n", + gating_wait); + } + + hba->dev_info.clk_gating_wait_us = gating_wait; + } + + return err; +} + /** * ufshcd_memory_alloc - allocate memory for host memory space data structures * @hba: per adapter instance @@ -3373,7 +3456,6 @@ out: */ static void ufshcd_host_memory_configure(struct ufs_hba *hba) { - struct utp_transfer_cmd_desc *cmd_descp; struct utp_transfer_req_desc *utrdlp; dma_addr_t cmd_desc_dma_addr; dma_addr_t cmd_desc_element_addr; @@ -3383,7 +3465,6 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) int i; utrdlp = hba->utrdl_base_addr; - cmd_descp = hba->ucdl_base_addr; response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); @@ -3403,36 +3484,13 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) cpu_to_le32(upper_32_bits(cmd_desc_element_addr)); /* Response upiu and prdt offset should be in double words */ - if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) { - utrdlp[i].response_upiu_offset = - cpu_to_le16(response_offset); - utrdlp[i].prd_table_offset = - cpu_to_le16(prdt_offset); - utrdlp[i].response_upiu_length = - cpu_to_le16(ALIGNED_UPIU_SIZE); - } else { - utrdlp[i].response_upiu_offset = - cpu_to_le16((response_offset >> 2)); - utrdlp[i].prd_table_offset = - cpu_to_le16((prdt_offset >> 2)); - utrdlp[i].response_upiu_length = - cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); - } + utrdlp[i].response_upiu_offset = + cpu_to_le16(response_offset >> 2); + utrdlp[i].prd_table_offset = cpu_to_le16(prdt_offset >> 2); + utrdlp[i].response_upiu_length = + cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); - hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); - hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr + - (i * sizeof(struct utp_transfer_req_desc)); - hba->lrb[i].ucd_req_ptr = - (struct utp_upiu_req *)(cmd_descp + i); - hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr; - hba->lrb[i].ucd_rsp_ptr = - (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; - hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr + - response_offset; - hba->lrb[i].ucd_prdt_ptr = - (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; - hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr + - prdt_offset; + ufshcd_init_lrb(hba, &hba->lrb[i], i); } } @@ -3460,52 +3518,6 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) "dme-link-startup: error code %d\n", ret); return ret; } -/** - * ufshcd_dme_reset - UIC command for DME_RESET - * @hba: per adapter instance - * - * DME_RESET command is issued in order to reset UniPro stack. - * This function now deal with cold reset. - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_dme_reset(struct ufs_hba *hba) -{ - struct uic_command uic_cmd = {0}; - int ret; - - uic_cmd.command = UIC_CMD_DME_RESET; - - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_err(hba->dev, - "dme-reset: error code %d\n", ret); - - return ret; -} - -/** - * ufshcd_dme_enable - UIC command for DME_ENABLE - * @hba: per adapter instance - * - * DME_ENABLE command is issued in order to enable UniPro stack. - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_dme_enable(struct ufs_hba *hba) -{ - struct uic_command uic_cmd = {0}; - int ret; - - uic_cmd.command = UIC_CMD_DME_ENABLE; - - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_err(hba->dev, - "dme-reset: error code %d\n", ret); - - return ret; -} static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba) { @@ -4224,7 +4236,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep) } /** - * ufshcd_hba_execute_hce - initialize the controller + * ufshcd_hba_enable - initialize the controller * @hba: per adapter instance * * The controller resets itself and controller firmware initialization @@ -4233,7 +4245,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep) * * Returns 0 on success, non-zero value on failure */ -static int ufshcd_hba_execute_hce(struct ufs_hba *hba) +int ufshcd_hba_enable(struct ufs_hba *hba) { int retry; @@ -4259,10 +4271,10 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) * instruction might be read back. * This delay can be changed based on the controller. */ - usleep_range(1000, 1100); + ufshcd_delay_us(hba->hba_enable_delay_us, 100); /* wait for the host controller to complete initialization */ - retry = 10; + retry = 50; while (ufshcd_is_hba_active(hba)) { if (retry) { retry--; @@ -4271,7 +4283,7 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) "Controller enable failed\n"); return -EIO; } - usleep_range(5000, 5100); + usleep_range(1000, 1100); } /* enable UIC related interrupts */ @@ -4281,37 +4293,11 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) return 0; } - -int ufshcd_hba_enable(struct ufs_hba *hba) -{ - int ret; - - if (hba->quirks & UFSHCI_QUIRK_BROKEN_HCE) { - ufshcd_set_link_off(hba); - ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); - - /* enable UIC related interrupts */ - ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); - ret = ufshcd_dme_reset(hba); - if (!ret) { - ret = ufshcd_dme_enable(hba); - if (!ret) - ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); - if (ret) - dev_err(hba->dev, - "Host controller enable failed with non-hce\n"); - } - } else { - ret = ufshcd_hba_execute_hce(hba); - } - - return ret; -} EXPORT_SYMBOL_GPL(ufshcd_hba_enable); static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer) { - int tx_lanes, i, err = 0; + int tx_lanes = 0, i, err = 0; if (!peer) ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), @@ -4737,8 +4723,15 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * UFS device needs urgent BKOPs. */ if (!hba->pm_op_in_progress && - ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) - schedule_work(&hba->eeh_work); + ufshcd_is_exception_event(lrbp->ucd_rsp_ptr) && + schedule_work(&hba->eeh_work)) { + /* + * Prevent suspend once eeh_work is scheduled + * to avoid deadlock between ufshcd_suspend + * and exception event handler. + */ + pm_runtime_get_noresume(hba->dev); + } break; case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ @@ -4876,8 +4869,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) * false interrupt if device completes another request after resetting * aggregation and before reading the DB. */ - if (ufshcd_is_intr_aggr_allowed(hba) && - !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) + if (ufshcd_is_intr_aggr_allowed(hba)) ufshcd_reset_intr_aggr(hba); tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); @@ -5191,7 +5183,14 @@ static void ufshcd_exception_event_handler(struct work_struct *work) out: ufshcd_scsi_unblock_requests(hba); - pm_runtime_put_sync(hba->dev); + /* + * pm_runtime_get_noresume is called while scheduling + * eeh_work to avoid suspend racing with exception work. + * Hence decrement usage counter using pm_runtime_put_noidle + * to allow suspend on completion of exception event handler. + */ + pm_runtime_put_noidle(hba->dev); + pm_runtime_put(hba->dev); return; } @@ -5486,7 +5485,8 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, u32 intr_mask) { - if (!ufshcd_is_auto_hibern8_supported(hba)) + if (!ufshcd_is_auto_hibern8_supported(hba) || + !ufshcd_is_auto_hibern8_enabled(hba)) return false; if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK)) @@ -6482,11 +6482,12 @@ out: return icc_level; } -static void ufshcd_init_icc_levels(struct ufs_hba *hba) +static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba) { int ret; int buff_len = hba->desc_size.pwr_desc; u8 *desc_buf; + u32 icc_level; desc_buf = kmalloc(buff_len, GFP_KERNEL); if (!desc_buf) @@ -6501,25 +6502,32 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) goto out; } - hba->init_prefetch_data.icc_level = - ufshcd_find_max_sup_active_icc_level(hba, - desc_buf, buff_len); - dev_dbg(hba->dev, "%s: setting icc_level 0x%x", - __func__, hba->init_prefetch_data.icc_level); + icc_level = ufshcd_find_max_sup_active_icc_level(hba, desc_buf, + buff_len); + dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, icc_level); ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, - &hba->init_prefetch_data.icc_level); + QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, &icc_level); if (ret) dev_err(hba->dev, "%s: Failed configuring bActiveICCLevel = %d ret = %d", - __func__, hba->init_prefetch_data.icc_level , ret); + __func__, icc_level, ret); out: kfree(desc_buf); } +static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev) +{ + scsi_autopm_get_device(sdev); + blk_pm_runtime_init(sdev->request_queue, &sdev->sdev_gendev); + if (sdev->rpm_autosuspend) + pm_runtime_set_autosuspend_delay(&sdev->sdev_gendev, + RPM_AUTOSUSPEND_DELAY_MS); + scsi_autopm_put_device(sdev); +} + /** * ufshcd_scsi_add_wlus - Adds required W-LUs * @hba: per-adapter instance @@ -6559,6 +6567,7 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) hba->sdev_ufs_device = NULL; goto out; } + ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device); scsi_device_put(hba->sdev_ufs_device); sdev_rpmb = __scsi_add_device(hba->host, 0, 0, @@ -6567,14 +6576,17 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) ret = PTR_ERR(sdev_rpmb); goto remove_sdev_ufs_device; } + ufshcd_blk_pm_runtime_init(sdev_rpmb); scsi_device_put(sdev_rpmb); sdev_boot = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL); - if (IS_ERR(sdev_boot)) + if (IS_ERR(sdev_boot)) { dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__); - else + } else { + ufshcd_blk_pm_runtime_init(sdev_boot); scsi_device_put(sdev_boot); + } goto out; remove_sdev_ufs_device: @@ -6614,6 +6626,10 @@ static int ufs_get_device_desc(struct ufs_hba *hba) dev_info->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + /* getting Specification Version in big endian format */ + dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, &dev_info->model, SD_ASCII_STD); @@ -6811,14 +6827,14 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_tune_pa_hibern8time(hba); } + ufshcd_vops_apply_dev_quirks(hba); + if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE) /* set 1ms timeout for PA_TACTIVATE */ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10); if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) ufshcd_quirk_tune_host_pa_tactivate(hba); - - ufshcd_vops_apply_dev_quirks(hba); } static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) @@ -6991,6 +7007,8 @@ static int ufshcd_device_params_init(struct ufs_hba *hba) goto out; } + ufshcd_get_ref_clk_gating_wait(hba); + ufs_fixup_device_setup(hba); if (!ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, @@ -7014,8 +7032,6 @@ static int ufshcd_add_lus(struct ufs_hba *hba) { int ret; - ufshcd_init_icc_levels(hba); - /* Add required well known logical units to scsi mid layer */ ret = ufshcd_scsi_add_wlus(hba); if (ret) @@ -7113,6 +7129,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async) } } + /* + * bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec) + * and for removable UFS card as well, hence always set the parameter. + * Note: Error handler may issue the device reset hence resetting + * bActiveICCLevel as well so it is always safe to set this here. + */ + ufshcd_set_active_icc_lvl(hba); + /* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; @@ -7241,6 +7265,11 @@ static int ufshcd_config_vreg(struct device *dev, name = vreg->name; if (regulator_count_voltages(reg) > 0) { + uA_load = on ? vreg->max_uA : 0; + ret = ufshcd_config_vreg_load(dev, vreg, uA_load); + if (ret) + goto out; + if (vreg->min_uV && vreg->max_uV) { min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); @@ -7251,11 +7280,6 @@ static int ufshcd_config_vreg(struct device *dev, goto out; } } - - uA_load = on ? vreg->max_uA : 0; - ret = ufshcd_config_vreg_load(dev, vreg, uA_load); - if (ret) - goto out; } out: return ret; @@ -7395,16 +7419,9 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (list_empty(head)) goto out; - /* - * vendor specific setup_clocks ops may depend on clocks managed by - * this standard driver hence call the vendor specific setup_clocks - * before disabling the clocks managed here. - */ - if (!on) { - ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); - if (ret) - return ret; - } + ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); + if (ret) + return ret; list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { @@ -7428,16 +7445,9 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, } } - /* - * vendor specific setup_clocks ops may depend on clocks managed by - * this standard driver hence call the vendor specific setup_clocks - * after enabling the clocks managed here. - */ - if (on) { - ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); - if (ret) - return ret; - } + ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); + if (ret) + return ret; out: if (ret) { @@ -7931,6 +7941,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto enable_gating; } + flush_work(&hba->eeh_work); ret = ufshcd_link_state_transition(hba, req_link_state, 1); if (ret) goto set_dev_active; @@ -8402,6 +8413,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->mmio_base = mmio_base; hba->irq = irq; + hba->hba_enable_delay_us = 1000; err = ufshcd_hba_init(hba); if (err) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 2ae6c7c8528c..dd1ee277069a 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -55,6 +55,8 @@ #include <linux/clk.h> #include <linux/completion.h> #include <linux/regulator/consumer.h> +#include <linux/bitfield.h> +#include <linux/devfreq.h> #include "unipro.h" #include <asm/irq.h> @@ -326,6 +328,9 @@ struct ufs_hba_variant_ops { void (*dbg_register_dump)(struct ufs_hba *hba); int (*phy_initialization)(struct ufs_hba *); void (*device_reset)(struct ufs_hba *hba); + void (*config_scaling_param)(struct ufs_hba *hba, + struct devfreq_dev_profile *profile, + void *data); }; /* clock gating state */ @@ -403,15 +408,6 @@ struct ufs_clk_scaling { bool is_suspended; }; -/** - * struct ufs_init_prefetch - contains data that is pre-fetched once during - * initialization - * @icc_level: icc level which was read during initialization - */ -struct ufs_init_prefetch { - u32 icc_level; -}; - #define UFS_ERR_REG_HIST_LENGTH 8 /** * struct ufs_err_reg_hist - keeps history of errors @@ -469,6 +465,85 @@ struct ufs_stats { struct ufs_err_reg_hist task_abort; }; +enum ufshcd_quirks { + /* Interrupt aggregation support is broken */ + UFSHCD_QUIRK_BROKEN_INTR_AGGR = 1 << 0, + + /* + * delay before each dme command is required as the unipro + * layer has shown instabilities + */ + UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS = 1 << 1, + + /* + * If UFS host controller is having issue in processing LCC (Line + * Control Command) coming from device then enable this quirk. + * When this quirk is enabled, host controller driver should disable + * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE + * attribute of device to 0). + */ + UFSHCD_QUIRK_BROKEN_LCC = 1 << 2, + + /* + * The attribute PA_RXHSUNTERMCAP specifies whether or not the + * inbound Link supports unterminated line in HS mode. Setting this + * attribute to 1 fixes moving to HS gear. + */ + UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP = 1 << 3, + + /* + * This quirk needs to be enabled if the host controller only allows + * accessing the peer dme attributes in AUTO mode (FAST AUTO or + * SLOW AUTO). + */ + UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE = 1 << 4, + + /* + * This quirk needs to be enabled if the host controller doesn't + * advertise the correct version in UFS_VER register. If this quirk + * is enabled, standard UFS host driver will call the vendor specific + * ops (get_ufs_hci_version) to get the correct version. + */ + UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION = 1 << 5, +}; + +enum ufshcd_caps { + /* Allow dynamic clk gating */ + UFSHCD_CAP_CLK_GATING = 1 << 0, + + /* Allow hiberb8 with clk gating */ + UFSHCD_CAP_HIBERN8_WITH_CLK_GATING = 1 << 1, + + /* Allow dynamic clk scaling */ + UFSHCD_CAP_CLK_SCALING = 1 << 2, + + /* Allow auto bkops to enabled during runtime suspend */ + UFSHCD_CAP_AUTO_BKOPS_SUSPEND = 1 << 3, + + /* + * This capability allows host controller driver to use the UFS HCI's + * interrupt aggregation capability. + * CAUTION: Enabling this might reduce overall UFS throughput. + */ + UFSHCD_CAP_INTR_AGGR = 1 << 4, + + /* + * This capability allows the device auto-bkops to be always enabled + * except during suspend (both runtime and suspend). + * Enabling this capability means that device will always be allowed + * to do background operation when it's active but it might degrade + * the performance of ongoing read/write operations. + */ + UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND = 1 << 5, + + /* + * This capability allows host controller driver to automatically + * enable runtime power management by itself instead of waiting + * for userspace to control the power management. + */ + UFSHCD_CAP_RPM_AUTOSUSPEND = 1 << 6, +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -501,7 +576,6 @@ struct ufs_stats { * @intr_mask: Interrupt Mask Bits * @ee_ctrl_mask: Exception event control mask * @is_powered: flag to check if HBA is powered - * @init_prefetch_data: data pre-fetched during initialization * @eh_work: Worker to handle UFS errors that require s/w attention * @eeh_work: Worker to handle exception events * @errors: HBA errors @@ -572,68 +646,6 @@ struct ufs_hba { bool is_irq_enabled; enum ufs_ref_clk_freq dev_ref_clk_freq; - /* Interrupt aggregation support is broken */ - #define UFSHCD_QUIRK_BROKEN_INTR_AGGR 0x1 - - /* - * delay before each dme command is required as the unipro - * layer has shown instabilities - */ - #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS 0x2 - - /* - * If UFS host controller is having issue in processing LCC (Line - * Control Command) coming from device then enable this quirk. - * When this quirk is enabled, host controller driver should disable - * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE - * attribute of device to 0). - */ - #define UFSHCD_QUIRK_BROKEN_LCC 0x4 - - /* - * The attribute PA_RXHSUNTERMCAP specifies whether or not the - * inbound Link supports unterminated line in HS mode. Setting this - * attribute to 1 fixes moving to HS gear. - */ - #define UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP 0x8 - - /* - * This quirk needs to be enabled if the host contoller only allows - * accessing the peer dme attributes in AUTO mode (FAST AUTO or - * SLOW AUTO). - */ - #define UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE 0x10 - - /* - * This quirk needs to be enabled if the host contoller doesn't - * advertise the correct version in UFS_VER register. If this quirk - * is enabled, standard UFS host driver will call the vendor specific - * ops (get_ufs_hci_version) to get the correct version. - */ - #define UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION 0x20 - - /* - * This quirk needs to be enabled if the host contoller regards - * resolution of the values of PRDTO and PRDTL in UTRD as byte. - */ - #define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80 - - /* - * Clear handling for transfer/task request list is just opposite. - */ - #define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR 0x100 - - /* - * This quirk needs to be enabled if host controller doesn't allow - * that the interrupt aggregation timer and counter are reset by s/w. - */ - #define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR 0x200 - - /* - * This quirks needs to be enabled if host controller cannot be - * enabled via HCE register. - */ - #define UFSHCI_QUIRK_BROKEN_HCE 0x400 unsigned int quirks; /* Deviations from standard UFSHCI spec. */ /* Device deviations from standard UFS device spec. */ @@ -650,8 +662,8 @@ struct ufs_hba { u32 eh_flags; u32 intr_mask; u16 ee_ctrl_mask; + u16 hba_enable_delay_us; bool is_powered; - struct ufs_init_prefetch init_prefetch_data; /* Work Queues */ struct work_struct eh_work; @@ -688,34 +700,6 @@ struct ufs_hba { struct ufs_clk_gating clk_gating; /* Control to enable/disable host capabilities */ u32 caps; - /* Allow dynamic clk gating */ -#define UFSHCD_CAP_CLK_GATING (1 << 0) - /* Allow hiberb8 with clk gating */ -#define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1 << 1) - /* Allow dynamic clk scaling */ -#define UFSHCD_CAP_CLK_SCALING (1 << 2) - /* Allow auto bkops to enabled during runtime suspend */ -#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1 << 3) - /* - * This capability allows host controller driver to use the UFS HCI's - * interrupt aggregation capability. - * CAUTION: Enabling this might reduce overall UFS throughput. - */ -#define UFSHCD_CAP_INTR_AGGR (1 << 4) - /* - * This capability allows the device auto-bkops to be always enabled - * except during suspend (both runtime and suspend). - * Enabling this capability means that device will always be allowed - * to do background operation when it's active but it might degrade - * the performance of ongoing read/write operations. - */ -#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5) - /* - * This capability allows host controller driver to automatically - * enable runtime power management by itself instead of waiting - * for userspace to control the power management. - */ -#define UFSHCD_CAP_RPM_AUTOSUSPEND (1 << 6) struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; @@ -773,6 +757,11 @@ static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT); } +static inline bool ufshcd_is_auto_hibern8_enabled(struct ufs_hba *hba) +{ + return FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit) ? true : false; +} + #define ufshcd_writel(hba, val, reg) \ writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ @@ -802,6 +791,7 @@ int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int); int ufshcd_make_hba_operational(struct ufs_hba *hba); void ufshcd_remove(struct ufs_hba *); int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); +void ufshcd_delay_us(unsigned long us, unsigned long tolerance); int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, u32 val, unsigned long interval_us, unsigned long timeout_ms, bool can_sleep); @@ -908,6 +898,11 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) pwr_info->pwr_tx == FASTAUTO_MODE); } +static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba) +{ + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); +} + /* Expose Query-Request API */ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, @@ -1092,6 +1087,14 @@ static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) } } +static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba, + struct devfreq_dev_profile + *profile, void *data) +{ + if (hba->vops && hba->vops->config_scaling_param) + hba->vops->config_scaling_param(hba, profile, data); +} + extern struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /* diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index 3dc4d8b76509..766d551df3fc 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -146,6 +146,12 @@ #define PA_SLEEPNOCONFIGTIME 0x15A2 #define PA_STALLNOCONFIGTIME 0x15A3 #define PA_SAVECONFIGTIME 0x15A4 +#define PA_TXHSADAPTTYPE 0x15D4 + +/* Adpat type for PA_TXHSADAPTTYPE attribute */ +#define PA_REFRESH_ADAPT 0x00 +#define PA_INITIAL_ADAPT 0x01 +#define PA_NO_ADAPT 0x03 #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 @@ -203,6 +209,7 @@ enum ufs_hs_gear_tag { UFS_HS_G1, /* HS Gear 1 (default for reset) */ UFS_HS_G2, /* HS Gear 2 */ UFS_HS_G3, /* HS Gear 3 */ + UFS_HS_G4, /* HS Gear 4 */ }; enum ufs_unipro_ver { diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index bfec84aacd90..0e0910c5b942 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -742,7 +742,6 @@ static struct scsi_host_template virtscsi_host_template = { .dma_boundary = UINT_MAX, .map_queues = virtscsi_map_queues, .track_queue_depth = 1, - .force_blk_mq = 1, }; #define virtscsi_config_get(vdev, fld) \ diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index bdd82e497d5f..c6727bcbc2e3 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -801,8 +801,7 @@ static int zorro_esp_probe(struct zorro_dev *z, /* additional setup required for Fastlane */ if (zep->zorro3 && ent->driver_data == ZORRO_BLZ1230II) { /* map full address space up to ESP base for DMA */ - zep->board_base = ioremap(board, - FASTLANE_ESP_ADDR-1); + zep->board_base = ioremap(board, FASTLANE_ESP_ADDR - 1); if (!zep->board_base) { pr_err("Cannot allocate board address space\n"); err = -ENOMEM; @@ -843,7 +842,7 @@ static int zorro_esp_probe(struct zorro_dev *z, * dma_registers size if adding any more */ esp->dma_regs = ioremap(dmaaddr, - sizeof(struct fastlane_dma_registers)); + sizeof(struct fastlane_dma_registers)); } else /* ZorroII address space remapped nocache by early startup */ esp->dma_regs = ZTWO_VADDR(dmaaddr); |