diff options
Diffstat (limited to 'drivers/scsi')
371 files changed, 12374 insertions, 17334 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 883d4a12a172..9b93a2440af8 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1184,7 +1184,7 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev) } /* Allocate event info space */ - tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); + tw_dev->event_queue[0] = kzalloc_objs(TW_Event, TW_Q_LENGTH); if (!tw_dev->event_queue[0]) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); goto out; @@ -1695,7 +1695,7 @@ out: } /* End twa_reset_sequence() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +static int twa_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; @@ -1746,7 +1746,7 @@ out: } /* End twa_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; int request_id, retval; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index e057ab9c7b90..52dc1aa639f7 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -122,7 +122,7 @@ static const struct bin_attribute twl_sysfs_aen_read_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = twl_sysfs_aen_read + .read = twl_sysfs_aen_read }; /* This function returns driver compatibility info through sysfs */ @@ -153,7 +153,7 @@ static const struct bin_attribute twl_sysfs_compat_info_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = twl_sysfs_compat_info + .read = twl_sysfs_compat_info }; /* Show some statistics about the card */ @@ -1052,7 +1052,7 @@ static int twl_initialize_device_extension(TW_Device_Extension *tw_dev) } /* Allocate event info space */ - tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); + tw_dev->event_queue[0] = kzalloc_objs(TW_Event, TW_Q_LENGTH); if (!tw_dev->event_queue[0]) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed"); goto out; @@ -1404,7 +1404,7 @@ out: } /* End twl_reset_device_extension() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +static int twl_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors; @@ -1453,11 +1453,13 @@ out: } /* End twl_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) { + TW_Device_Extension *tw_dev = + (TW_Device_Extension *)SCpnt->device->host->hostdata; void (*done)(struct scsi_cmnd *) = scsi_done; - int request_id, retval; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + enum scsi_qc_status retval; + int request_id; /* If we are resetting due to timed out ioctl, report as busy */ if (test_bit(TW_IN_RESET, &tw_dev->flags)) { diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 89bd56f78ef9..c68678fa72c1 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1340,7 +1340,7 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev) } /* End tw_reset_device_extension() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int tw_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; @@ -1920,7 +1920,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r } /* End tw_scsiop_test_unit_ready_complete() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char *command = SCpnt->cmnd; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 71b7ac027f48..c78f74b8f45c 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -152,8 +152,8 @@ MODULE_LICENSE("GPL"); /* This is the script */ #include "53c700_d.h" - -STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); +STATIC enum scsi_qc_status NCR_700_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *); STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); @@ -1751,7 +1751,7 @@ NCR_700_intr(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) +static enum scsi_qc_status NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) { struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; @@ -2020,8 +2020,7 @@ NCR_700_set_offset(struct scsi_target *STp, int offset) STATIC int NCR_700_sdev_init(struct scsi_device *SDp) { - SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), - GFP_KERNEL); + SDp->hostdata = kzalloc_obj(struct NCR_700_Device_Parameters); if (!SDp->hostdata) return -ENOMEM; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 1f100270cd38..5304d2febd63 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -920,7 +920,8 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter) a particular probe order. */ -static void __init blogic_init_probeinfo_list(struct blogic_adapter *adapter) +static noinline_for_stack void __init +blogic_init_probeinfo_list(struct blogic_adapter *adapter) { /* If a PCI BIOS is present, interrogate it for MultiMaster and @@ -1631,8 +1632,8 @@ common: /* Initialize the Host Adapter Full Model Name from the Model Name. */ - strcpy(adapter->full_model, "BusLogic "); - strcat(adapter->full_model, adapter->model); + scnprintf(adapter->full_model, sizeof(adapter->full_model), + "BusLogic %s", adapter->model); /* Select an appropriate value for the Tagged Queue Depth either from a BusLogic Driver Options specification, or based on whether this Host @@ -1690,7 +1691,8 @@ common: blogic_reportconfig reports the configuration of Host Adapter. */ -static bool __init blogic_reportconfig(struct blogic_adapter *adapter) +static noinline_for_stack bool __init +blogic_reportconfig(struct blogic_adapter *adapter) { unsigned short alltgt_mask = (1 << adapter->maxdev) - 1; unsigned short sync_ok, fast_ok; @@ -2212,15 +2214,14 @@ static int __init blogic_init(void) if (blogic_probe_options.noprobe) return -ENODEV; blogic_probeinfo_list = - kcalloc(BLOGIC_MAX_ADAPTERS, sizeof(struct blogic_probeinfo), - GFP_KERNEL); + kzalloc_objs(struct blogic_probeinfo, BLOGIC_MAX_ADAPTERS); if (blogic_probeinfo_list == NULL) { blogic_err("BusLogic: Unable to allocate Probe Info List\n", NULL); return -ENOMEM; } - adapter = kzalloc(sizeof(struct blogic_adapter), GFP_KERNEL); + adapter = kzalloc_obj(struct blogic_adapter); if (adapter == NULL) { kfree(blogic_probeinfo_list); blogic_err("BusLogic: Unable to allocate Prototype Host Adapter\n", NULL); @@ -2877,7 +2878,7 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) Outgoing Mailbox for execution by the associated Host Adapter. */ -static int blogic_qcmd_lck(struct scsi_cmnd *command) +static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) { void (*comp_cb)(struct scsi_cmnd *) = scsi_done; struct blogic_adapter *adapter = @@ -3240,7 +3241,7 @@ static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) the BIOS, and a warning may be displayed. */ -static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, +static int blogic_diskparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *params) { struct blogic_adapter *adapter = @@ -3261,7 +3262,7 @@ static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, diskparam->sectors = 32; } diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors); - buf = scsi_bios_ptable(dev); + buf = scsi_bios_ptable(disk); if (buf == NULL) return 0; /* @@ -3715,7 +3716,6 @@ static void __exit blogic_exit(void) __setup("BusLogic=", blogic_setup); -#ifdef MODULE /*static const struct pci_device_id blogic_pci_tbl[] = { { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -3725,13 +3725,12 @@ __setup("BusLogic=", blogic_setup); PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } };*/ -static const struct pci_device_id blogic_pci_tbl[] = { +static const struct pci_device_id blogic_pci_tbl[] __maybe_unused = { {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER)}, {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC)}, {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT)}, {0, }, }; -#endif MODULE_DEVICE_TABLE(pci, blogic_pci_tbl); module_init(blogic_init); diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 61bf26d4fc10..24697a5bedc8 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1272,8 +1272,9 @@ static inline void blogic_incszbucket(unsigned int *cmdsz_buckets, */ static const char *blogic_drvr_info(struct Scsi_Host *); -static int blogic_qcmd(struct Scsi_Host *h, struct scsi_cmnd *); -static int blogic_diskparam(struct scsi_device *, struct block_device *, sector_t, int *); +static enum scsi_qc_status blogic_qcmd(struct Scsi_Host *h, + struct scsi_cmnd *command); +static int blogic_diskparam(struct scsi_device *, struct gendisk *, sector_t, int *); static int blogic_sdev_configure(struct scsi_device *, struct queue_limits *lim); static void blogic_qcompleted_ccb(struct blogic_ccb *); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 37c24ffea65c..fc8e8b0bfa39 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -303,9 +303,7 @@ if SCSI_LOWLEVEL && SCSI config ISCSI_TCP tristate "iSCSI Initiator over TCP/IP" depends on SCSI && INET - select CRYPTO - select CRYPTO_MD5 - select CRYPTO_CRC32C + select CRC32 select SCSI_ISCSI_ATTRS help The iSCSI Driver provides a host with the ability to access storage @@ -336,7 +334,6 @@ source "drivers/scsi/cxgbi/Kconfig" source "drivers/scsi/bnx2i/Kconfig" source "drivers/scsi/bnx2fc/Kconfig" source "drivers/scsi/be2iscsi/Kconfig" -source "drivers/scsi/cxlflash/Kconfig" config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" @@ -404,6 +401,7 @@ config SCSI_ACARD config SCSI_AHA152X tristate "Adaptec AHA152X/2825 support" depends on ISA && SCSI + depends on !HIGHMEM select SCSI_SPI_ATTRS select CHECK_SIGNATURE help @@ -589,7 +587,7 @@ config XEN_SCSI_FRONTEND config HYPERV_STORAGE tristate "Microsoft Hyper-V virtual storage driver" - depends on SCSI && HYPERV + depends on SCSI && HYPERV_VMBUS depends on m || SCSI_FC_ATTRS != m default HYPERV help @@ -796,6 +794,7 @@ config SCSI_PPA tristate "IOMEGA parallel port (ppa - older drives)" depends on SCSI && PARPORT_PC depends on HAS_IOPORT + depends on !HIGHMEM help This driver supports older versions of IOMEGA's parallel port ZIP drive (a 100 MB removable media device). @@ -823,6 +822,7 @@ config SCSI_PPA config SCSI_IMM tristate "IOMEGA parallel port (imm - newer drives)" depends on SCSI && PARPORT_PC + depends on !HIGHMEM help This driver supports newer versions of IOMEGA's parallel port ZIP drive (a 100 MB removable media device). @@ -1149,6 +1149,7 @@ config SCSI_LPFC depends on NVME_TARGET_FC || NVME_TARGET_FC=n depends on NVME_FC || NVME_FC=n select CRC_T10DIF + select CRC32 select IRQ_POLL help This lpfc driver supports the Emulex LightPulse diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1313ddf2fd1a..16de3e41f94c 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -96,7 +96,6 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o -obj-$(CONFIG_CXLFLASH) += cxlflash/ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 0e10502660de..006dcf981218 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -555,8 +555,8 @@ static void complete_cmd(struct Scsi_Host *instance, * main coroutine is not running, it is restarted. */ -static int NCR5380_queue_command(struct Scsi_Host *instance, - struct scsi_cmnd *cmd) +static enum scsi_qc_status NCR5380_queue_command(struct Scsi_Host *instance, + struct scsi_cmnd *cmd) { struct NCR5380_hostdata *hostdata = shost_priv(instance); struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index a8979f9e30ff..4365b896f5c4 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -909,7 +909,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc * block, build the host specific scb structures and if there is room * queue the command down to the controller */ -static int inia100_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status inia100_queue_lck(struct scsi_cmnd *cmd) { struct orc_scb *scb; struct orc_host *host; /* Point to Host adapter control block */ diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index 75b43047a155..a02638b477de 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -47,8 +47,7 @@ static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev) "A4000T builtin SCSI")) return -EBUSY; - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), - GFP_KERNEL); + hostdata = kzalloc_obj(struct NCR_700_Host_Parameters); if (!hostdata) { dev_err(&pdev->dev, "Failed to allocate host data\n"); goto out_release; diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index abf6a82b74af..df9492247631 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -492,8 +492,8 @@ int aac_get_containers(struct aac_dev *dev) fsa_dev_ptr = dev->fsa_dev; - dev->fsa_dev = kcalloc(maximum_num_containers, - sizeof(*fsa_dev_ptr), GFP_KERNEL); + dev->fsa_dev = kzalloc_objs(*fsa_dev_ptr, + maximum_num_containers); kfree(fsa_dev_ptr); fsa_dev_ptr = NULL; @@ -820,7 +820,7 @@ int aac_probe_container(struct aac_dev *dev, int cid) { struct aac_cmd_priv *cmd_priv; struct scsi_cmnd *scsicmd = kzalloc(sizeof(*scsicmd) + sizeof(*cmd_priv), GFP_KERNEL); - struct scsi_device *scsidev = kzalloc(sizeof(*scsidev), GFP_KERNEL); + struct scsi_device *scsidev = kzalloc_obj(*scsidev); int status; if (!scsicmd || !scsidev) { @@ -3221,8 +3221,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) break; } fallthrough; - case RESERVE: - case RELEASE: + case RESERVE_6: + case RELEASE_6: case REZERO_UNIT: case REASSIGN_BLOCKS: case SEEK_10: @@ -4010,7 +4010,7 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int if (aac_convert_sgl == 0) return 0; - sge = kmalloc_array(nseg_new, sizeof(*sge), GFP_ATOMIC); + sge = kmalloc_objs(*sge, nseg_new, GFP_ATOMIC); if (sge == NULL) return -ENOMEM; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 8c384c25dca1..0a5888b53d6d 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -93,7 +93,6 @@ enum { #define AAC_NUM_MGT_FIB 8 #define AAC_NUM_IO_FIB (1024 - AAC_NUM_MGT_FIB) -#define AAC_NUM_FIB (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB) #define AAC_MAX_LUN 256 diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 68240d6f27ab..bd82aeb679ae 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) struct aac_fib_context * fibctx; int status; - fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); + fibctx = kmalloc_obj(struct aac_fib_context); if (fibctx == NULL) { status = -ENOMEM; } else { diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 28cf18955a08..9bd3f5b868bc 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -481,8 +481,7 @@ void aac_define_int_mode(struct aac_dev *dev) pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { min_msix = 2; i = pci_alloc_irq_vectors(dev->pdev, - min_msix, msi_count, - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); + min_msix, msi_count, PCI_IRQ_MSIX); if (i > 0) { dev->msi_enabled = 1; msi_count = i; @@ -633,7 +632,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) * Ok now init the communication subsystem */ - dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL); + dev->queues = kzalloc_obj(struct aac_queue_block); if (dev->queues == NULL) { printk(KERN_ERR "Error could not allocate comm region.\n"); return NULL; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index ffef61c4aa01..c4485629f792 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -48,15 +48,7 @@ static int fib_map_alloc(struct aac_dev *dev) { - if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE) - dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; - else - dev->max_cmd_size = dev->max_fib_size; - if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) { - dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; - } else { - dev->max_cmd_size = dev->max_fib_size; - } + dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; dprintk((KERN_INFO "allocate hardware fibs dma_alloc_coherent(%p, %d * (%d + %d), %p)\n", @@ -1915,13 +1907,13 @@ static int fillup_pools(struct aac_dev *dev, struct hw_fib **hw_fib_pool, hw_fib_p = hw_fib_pool; fib_p = fib_pool; while (hw_fib_p < &hw_fib_pool[num]) { - *(hw_fib_p) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL); + *(hw_fib_p) = kmalloc_obj(struct hw_fib); if (!(*(hw_fib_p++))) { --hw_fib_p; break; } - *(fib_p) = kmalloc(sizeof(struct fib), GFP_KERNEL); + *(fib_p) = kmalloc_obj(struct fib); if (!(*(fib_p++))) { kfree(*(--hw_fib_p)); break; @@ -2109,12 +2101,11 @@ static void aac_process_events(struct aac_dev *dev) if (!num) goto free_fib; - hw_fib_pool = kmalloc_array(num, sizeof(struct hw_fib *), - GFP_KERNEL); + hw_fib_pool = kmalloc_objs(struct hw_fib *, num); if (!hw_fib_pool) goto free_fib; - fib_pool = kmalloc_array(num, sizeof(struct fib *), GFP_KERNEL); + fib_pool = kmalloc_objs(struct fib *, num); if (!fib_pool) goto free_hw_fib_pool; diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index fbe334c59f37..169c41d080a1 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -184,7 +184,7 @@ unsigned int aac_command_normal(struct aac_queue *q) * a fib object in order to manage the linked lists */ if (dev->aif_thread) - if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL) + if((fib = kmalloc_obj(struct fib, GFP_ATOMIC)) == NULL) fib = &fibctx; memset(fib, 0, sizeof(struct fib)); @@ -284,9 +284,9 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif, * manage the linked lists. */ if ((!dev->aif_thread) - || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC)))) + || (!(fib = kzalloc_obj(struct fib, GFP_ATOMIC)))) return 1; - if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) { + if (!(hw_fib = kzalloc_obj(struct hw_fib, GFP_ATOMIC))) { kfree (fib); return 1; } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 91170a67cc91..2fa8f7ddb703 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -237,12 +237,12 @@ static struct aac_driver_ident aac_drivers[] = { * TODO: unify with aac_scsi_cmd(). */ -static int aac_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static enum scsi_qc_status aac_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { aac_priv(cmd)->owner = AAC_OWNER_LOWLEVEL; - return aac_scsi_cmd(cmd) ? FAILED : 0; + return aac_scsi_cmd(cmd) ? SCSI_MLQUEUE_HOST_BUSY : 0; } /** @@ -273,7 +273,7 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype) /** * aac_biosparm - return BIOS parameters for disk * @sdev: The scsi device corresponding to the disk - * @bdev: the block device corresponding to the disk + * @disk: the gendisk corresponding to the disk * @capacity: the sector capacity of the disk * @geom: geometry block to fill in * @@ -292,7 +292,7 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype) * be displayed. */ -static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, +static int aac_biosparm(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *geom) { struct diskparm *param = (struct diskparm *)geom; @@ -324,7 +324,7 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, * entry whose end_head matches one of the standard geometry * translations ( 64/32, 128/32, 255/63 ). */ - buf = scsi_bios_ptable(bdev); + buf = scsi_bios_ptable(disk); if (!buf) return 0; if (*(__le16 *)(buf + 0x40) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { @@ -1661,9 +1661,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (aac_reset_devices || reset_devices) aac->init_reset = true; - aac->fibs = kcalloc(shost->can_queue + AAC_NUM_MGT_FIB, - sizeof(struct fib), - GFP_KERNEL); + aac->fibs = kzalloc_objs(struct fib, shost->can_queue + AAC_NUM_MGT_FIB); if (!aac->fibs) { error = -ENOMEM; goto out_free_host; @@ -2029,7 +2027,7 @@ static void aac_pci_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "aacraid: PCI error - resume\n"); } -static struct pci_error_handlers aac_pci_err_handler = { +static const struct pci_error_handlers aac_pci_err_handler = { .error_detected = aac_pci_error_detected, .mmio_enabled = aac_pci_mmio_enabled, .slot_reset = aac_pci_slot_reset, diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index e06ff83b69ce..ba9f3256c258 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -17,6 +17,7 @@ */ #include <linux/kernel.h> +#include <linux/hex.h> #include <linux/init.h> #include <linux/types.h> #include <linux/pci.h> diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 3a2c336307c0..fcf059bf41e8 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2401,8 +2401,7 @@ static void asc_prt_scsi_host(struct Scsi_Host *s) struct asc_board *boardp = shost_priv(s); printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev)); - printk(" host_busy %d, host_no %d,\n", - scsi_host_busy(s), s->host_no); + printk(" host_no %d,\n", s->host_no); printk(" base 0x%lx, io_port 0x%lx, irq %d,\n", (ulong)s->base, (ulong)s->io_port, boardp->irq); @@ -7096,7 +7095,7 @@ static int advansys_reset(struct scsi_cmnd *scp) * ip[2]: cylinders */ static int -advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, +advansys_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { struct asc_board *boardp = shost_priv(sdev->host); @@ -7487,8 +7486,8 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, return ASC_ERROR; } - asc_sg_head = kzalloc(struct_size(asc_sg_head, sg_list, use_sg), - GFP_ATOMIC); + asc_sg_head = kzalloc_flex(*asc_sg_head, sg_list, use_sg, + GFP_ATOMIC); if (!asc_sg_head) { scsi_dma_unmap(scp); set_host_byte(scp, DID_SOFT_ERROR); @@ -8463,10 +8462,11 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) * This function always returns 0. Command return status is saved * in the 'scp' result field. */ -static int advansys_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status advansys_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *shost = scp->device->host; - int asc_res, result = 0; + enum scsi_qc_status result = 0; + int asc_res; ASC_STATS(shost, queuecommand); @@ -11314,7 +11314,7 @@ static int advansys_eisa_probe(struct device *dev) struct eisa_scsi_data *data; err = -ENOMEM; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = kzalloc_obj(*data); if (!data) goto fail; ioport = edev->base_addr + 0xc30; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 4276f868cd91..e3ccb6bb62c0 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -746,7 +746,6 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) /* need to have host registered before triggering any interrupt */ list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list); - shpnt->no_highmem = true; shpnt->io_port = setup->io_port; shpnt->n_io_port = IO_RANGE; shpnt->irq = setup->irq; @@ -925,7 +924,7 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt) /* * Queue a command and setup interrupts for a free bus. */ -static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, +static enum scsi_qc_status aha152x_internal_queue(struct scsi_cmnd *SCpnt, struct completion *complete, int phase) { struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt); @@ -940,13 +939,13 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, if (acp->phase & (resetting | check_condition)) { if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } else { SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); if(!SCpnt->host_scribble) { scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } @@ -996,7 +995,7 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, * queue a command * */ -static int aha152x_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha152x_queue_lck(struct scsi_cmnd *SCpnt) { return aha152x_internal_queue(SCpnt, NULL, 0); } @@ -1247,7 +1246,7 @@ int aha152x_host_reset_host(struct Scsi_Host *shpnt) * Return the "logical geometry" * */ -static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int aha152x_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *info_array) { struct Scsi_Host *shpnt = sdev->host; @@ -1262,7 +1261,7 @@ static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev int info[3]; /* try to figure out the geometry from the partition table */ - if (scsicam_bios_param(bdev, capacity, info) < 0 || + if (scsicam_bios_param(disk, capacity, info) < 0 || !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { if (EXT_TRANS) { printk(KERN_NOTICE diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 389499d3e00a..fd766282d4a4 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -411,7 +411,8 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id) } } -static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status aha1542_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); struct aha1542_hostdata *aha1542 = shost_priv(sh); @@ -992,7 +993,7 @@ static int aha1542_host_reset(struct scsi_cmnd *cmd) } static int aha1542_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int geom[]) + struct gendisk *unused, sector_t capacity, int geom[]) { struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index be7ebbbb9ba8..c435769359f2 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -319,7 +319,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unchar direction; @@ -510,7 +510,7 @@ static void aha1740_getconfig(unsigned int base, unsigned int *irq_level, } static int aha1740_biosparam(struct scsi_device *sdev, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int* ip) { int size = capacity; diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 3e3100dbfda3..3602a1fc40e4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -3604,7 +3604,7 @@ ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel) && ahd->enabled_targets[scsi_id] != master_tstate) panic("%s: ahd_alloc_tstate - Target already allocated", ahd_name(ahd)); - tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); + tstate = kmalloc_obj(*tstate, GFP_ATOMIC); if (tstate == NULL) return (NULL); @@ -6037,14 +6037,14 @@ ahd_alloc(void *platform_arg, char *name) { struct ahd_softc *ahd; - ahd = kzalloc(sizeof(*ahd), GFP_ATOMIC); + ahd = kzalloc_obj(*ahd, GFP_ATOMIC); if (!ahd) { printk("aic7xxx: cannot malloc softc!\n"); kfree(name); return NULL; } - ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); + ahd->seep_config = kmalloc_obj(*ahd->seep_config, GFP_ATOMIC); if (ahd->seep_config == NULL) { kfree(ahd); kfree(name); @@ -6181,7 +6181,7 @@ ahd_shutdown(void *arg) /* * Stop periodic timer callbacks. */ - del_timer_sync(&ahd->stat_timer); + timer_delete_sync(&ahd->stat_timer); /* This will reset most registers to 0, but not all */ ahd_reset(ahd, /*reinit*/FALSE); @@ -6777,7 +6777,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb)); } else { - hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC); + hscb_map = kmalloc_obj(*hscb_map, GFP_ATOMIC); if (hscb_map == NULL) return; @@ -6810,7 +6810,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) segs = sg_map->vaddr + offset; sg_busaddr = sg_map->physaddr + offset; } else { - sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); + sg_map = kmalloc_obj(*sg_map, GFP_ATOMIC); if (sg_map == NULL) return; @@ -6847,7 +6847,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) sense_data = sense_map->vaddr + offset; sense_busaddr = sense_map->physaddr + offset; } else { - sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC); + sense_map = kmalloc_obj(*sense_map, GFP_ATOMIC); if (sense_map == NULL) return; @@ -6882,11 +6882,11 @@ ahd_alloc_scbs(struct ahd_softc *ahd) struct scb_platform_data *pdata; u_int col_tag; - next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC); + next_scb = kmalloc_obj(*next_scb, GFP_ATOMIC); if (next_scb == NULL) break; - pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); + pdata = kmalloc_obj(*pdata, GFP_ATOMIC); if (pdata == NULL) { kfree(next_scb); break; @@ -6975,7 +6975,7 @@ static const char *termstat_strings[] = { static void ahd_timer_reset(struct timer_list *timer, int usec) { - del_timer(timer); + timer_delete(timer); timer->expires = jiffies + (usec * HZ)/1000000; add_timer(timer); } @@ -8784,7 +8784,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) static void ahd_stat_timer(struct timer_list *t) { - struct ahd_softc *ahd = from_timer(ahd, t, stat_timer); + struct ahd_softc *ahd = timer_container_of(ahd, t, stat_timer); u_long s; int enint_coal; @@ -10339,7 +10339,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) return; } } - lstate = kzalloc(sizeof(*lstate), GFP_ATOMIC); + lstate = kzalloc_obj(*lstate, GFP_ATOMIC); if (lstate == NULL) { xpt_print_path(ccb->ccb_h.path); printk("Couldn't allocate lstate\n"); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 17dfc3c72110..feb1707feb7e 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -359,7 +359,7 @@ static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static void ahd_linux_device_queue_depth(struct scsi_device *); -static int ahd_linux_run_command(struct ahd_softc*, +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc*, struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); @@ -577,11 +577,11 @@ ahd_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahd_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahd_linux_queue_lck(struct scsi_cmnd *cmd) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_softc *ahd; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -720,7 +720,7 @@ ahd_linux_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * Return the disk geometry for the given SCSI device. */ static int -ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, +ahd_linux_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { int heads; @@ -731,7 +731,7 @@ ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; heads = 64; @@ -923,7 +923,7 @@ ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, { bus_dma_tag_t dmat; - dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); + dmat = kmalloc_obj(*dmat, GFP_ATOMIC); if (dmat == NULL) return (ENOMEM); @@ -1309,7 +1309,7 @@ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) { ahd->platform_data = - kzalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC); + kzalloc_obj(struct ahd_platform_data, GFP_ATOMIC); if (ahd->platform_data == NULL) return (ENOMEM); ahd->platform_data->irq = AHD_LINUX_NOIRQ; @@ -1535,7 +1535,7 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) } } -static int +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, struct scsi_cmnd *cmd) { diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 746d0ca2a657..aa37838b78a6 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -242,8 +242,8 @@ ahd_proc_write_seeprom(struct Scsi_Host *shost, char *buffer, int length) u_int start_addr; if (ahd->seep_config == NULL) { - ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), - GFP_ATOMIC); + ahd->seep_config = kmalloc_obj(*ahd->seep_config, + GFP_ATOMIC); if (ahd->seep_config == NULL) { printk("aic79xx: Unable to allocate serial " "eeprom buffer. Write failing\n"); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index a396f048a031..b9761f9f0bbc 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -2128,7 +2128,7 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) && ahc->enabled_targets[scsi_id] != master_tstate) panic("%s: ahc_alloc_tstate - Target already allocated", ahc_name(ahc)); - tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); + tstate = kmalloc_obj(*tstate, GFP_ATOMIC); if (tstate == NULL) return (NULL); @@ -4381,14 +4381,14 @@ ahc_alloc(void *platform_arg, char *name) struct ahc_softc *ahc; int i; - ahc = kzalloc(sizeof(*ahc), GFP_ATOMIC); + ahc = kzalloc_obj(*ahc, GFP_ATOMIC); if (!ahc) { printk("aic7xxx: cannot malloc softc!\n"); kfree(name); return NULL; } - ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC); + ahc->seep_config = kmalloc_obj(*ahc->seep_config, GFP_ATOMIC); if (ahc->seep_config == NULL) { kfree(ahc); kfree(name); @@ -4433,7 +4433,7 @@ ahc_softc_init(struct ahc_softc *ahc) ahc->pause = ahc->unpause | PAUSE; /* XXX The shared scb data stuff should be deprecated */ if (ahc->scb_data == NULL) { - ahc->scb_data = kzalloc(sizeof(*ahc->scb_data), GFP_ATOMIC); + ahc->scb_data = kzalloc_obj(*ahc->scb_data, GFP_ATOMIC); if (ahc->scb_data == NULL) return (ENOMEM); } @@ -4738,8 +4738,8 @@ ahc_init_scbdata(struct ahc_softc *ahc) SLIST_INIT(&scb_data->sg_maps); /* Allocate SCB resources */ - scb_data->scbarray = kcalloc(AHC_SCB_MAX_ALLOC, sizeof(struct scb), - GFP_ATOMIC); + scb_data->scbarray = kzalloc_objs(struct scb, AHC_SCB_MAX_ALLOC, + GFP_ATOMIC); if (scb_data->scbarray == NULL) return (ENOMEM); @@ -4943,7 +4943,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) next_scb = &scb_data->scbarray[scb_data->numscbs]; - sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); + sg_map = kmalloc_obj(*sg_map, GFP_ATOMIC); if (sg_map == NULL) return; @@ -4970,7 +4970,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; - pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); + pdata = kmalloc_obj(*pdata, GFP_ATOMIC); if (pdata == NULL) break; next_scb->platform_data = pdata; @@ -7488,7 +7488,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) return; } } - lstate = kzalloc(sizeof(*lstate), GFP_ATOMIC); + lstate = kzalloc_obj(*lstate, GFP_ATOMIC); if (lstate == NULL) { xpt_print_path(ccb->ccb_h.path); printk("Couldn't allocate lstate\n"); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index cebf8c5d0caf..d93b522695eb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -519,11 +519,11 @@ ahc_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahc_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahc_linux_queue_lck(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; @@ -683,7 +683,7 @@ ahc_linux_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * Return the disk geometry for the given SCSI device. */ static int -ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, +ahc_linux_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { int heads; @@ -696,7 +696,7 @@ ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev_channel(sdev); - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; heads = 64; @@ -823,7 +823,7 @@ ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, { bus_dma_tag_t dmat; - dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); + dmat = kmalloc_obj(*dmat, GFP_ATOMIC); if (dmat == NULL) return (ENOMEM); @@ -1201,7 +1201,7 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) { ahc->platform_data = - kzalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC); + kzalloc_obj(struct ahc_platform_data, GFP_ATOMIC); if (ahc->platform_data == NULL) return (ENOMEM); ahc->platform_data->irq = AHC_LINUX_NOIRQ; diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 4bc9e2dfccf6..3b2ba7b4d61b 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -255,8 +255,8 @@ ahc_proc_write_seeprom(struct Scsi_Host *shost, char *buffer, int length) u_int start_addr; if (ahc->seep_config == NULL) { - ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), - GFP_ATOMIC); + ahc->seep_config = kmalloc_obj(*ahc->seep_config, + GFP_ATOMIC); if (ahc->seep_config == NULL) { printk("aic7xxx: Unable to allocate serial " "eeprom buffer. Write failing\n"); diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.h b/drivers/scsi/aic7xxx/aicasm/aicasm.h index 716a2aefc925..f290b50c6475 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.h +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.h @@ -82,7 +82,7 @@ extern int src_mode; extern int dst_mode; struct symbol; -void stop(const char *errstring, int err_code); +void __attribute__((noreturn)) stop(const char *errstring, int err_code); void include_file(char *file_name, include_type type); void expand_macro(struct symbol *macro_symbol); struct instruction *seq_alloc(void); diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index b1c9ce477cbd..f6dbb9855daa 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -1104,7 +1104,7 @@ conditional: last_scope = TAILQ_LAST(&scope_context->inner_scope, scope_tailq); if (last_scope == NULL - || last_scope->type == T_ELSE) { + || last_scope->type == (int)T_ELSE) { stop("'else if' without leading 'if'", EX_DATAERR); /* NOTREACHED */ diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l index fc7e6c58148d..c0d92cf5f9b5 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l @@ -389,7 +389,7 @@ nop { return T_NOP; } char c; yptr = yytext; - while (c = *yptr++) { + while ((c = *yptr++)) { /* * Strip carriage returns. */ diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 9dda296c0152..caa9d7143894 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -272,8 +272,7 @@ static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags) struct asd_seq_data *seq = &asd_ha->seq; int i; - seq->edb_arr = kmalloc_array(seq->num_edbs, sizeof(*seq->edb_arr), - gfp_flags); + seq->edb_arr = kmalloc_objs(*seq->edb_arr, seq->num_edbs, gfp_flags); if (!seq->edb_arr) return -ENOMEM; @@ -305,8 +304,7 @@ static int asd_alloc_escbs(struct asd_ha_struct *asd_ha, struct asd_ascb *escb; int i, escbs; - seq->escb_arr = kmalloc_array(seq->num_escbs, sizeof(*seq->escb_arr), - gfp_flags); + seq->escb_arr = kmalloc_objs(*seq->escb_arr, seq->num_escbs, gfp_flags); if (!seq->escb_arr) return -ENOMEM; @@ -731,7 +729,7 @@ static void asd_dl_tasklet_handler(unsigned long data) goto next_1; } else if (ascb->scb->header.opcode == EMPTY_SCB) { goto out; - } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) { + } else if (!ascb->uldd_timer && !timer_delete(&ascb->timer)) { goto next_1; } spin_lock_irqsave(&seq->pend_q_lock, flags); diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 538a5867e8ab..4400a3661d90 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -642,9 +642,9 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) { int i; struct asd_sas_phy **sas_phys = - kcalloc(ASD_MAX_PHYS, sizeof(*sas_phys), GFP_KERNEL); + kzalloc_objs(*sas_phys, ASD_MAX_PHYS); struct asd_sas_port **sas_ports = - kcalloc(ASD_MAX_PHYS, sizeof(*sas_ports), GFP_KERNEL); + kzalloc_objs(*sas_ports, ASD_MAX_PHYS); if (!sas_phys || !sas_ports) { kfree(sas_phys); @@ -710,7 +710,7 @@ static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) asd_dev = &asd_pcidev_data[asd_id]; - asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); + asd_ha = kzalloc_obj(*asd_ha); if (!asd_ha) { asd_printk("out of memory\n"); goto Err_put; @@ -851,7 +851,7 @@ static void asd_free_queues(struct asd_ha_struct *asd_ha) * times out. Apparently we don't wait for the CONTROL PHY * to complete, so it doesn't matter if we kill the timer. */ - del_timer_sync(&ascb->timer); + timer_delete_sync(&ascb->timer); WARN_ON(ascb->scb->header.opcode != CONTROL_PHY); list_del_init(pos); @@ -882,6 +882,9 @@ static void asd_pci_remove(struct pci_dev *dev) asd_disable_ints(asd_ha); + /* Ensure all scheduled tasklets complete before freeing resources */ + tasklet_kill(&asd_ha->seq.dl_tasklet); + asd_remove_dev_attrs(asd_ha); /* XXX more here as needed */ diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 68214a58b160..08c8dad9ad62 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -862,7 +862,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, */ void asd_ascb_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct asd_seq_data *seq = &ascb->ha->seq; unsigned long flags; diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index 5def83c88f13..57818393f9f0 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -207,7 +207,7 @@ static int asd_get_bios_chim(struct asd_ha_struct *asd_ha, goto out; } err = -ENOMEM; - bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL); + bc_struct = kmalloc_obj(*bc_struct); if (!bc_struct) { asd_printk("no memory for bios_chim struct\n"); goto out; @@ -341,7 +341,7 @@ int asd_read_ocm(struct asd_ha_struct *asd_ha) if (asd_hwi_check_ocm_access(asd_ha)) return -1; - dir = kmalloc(sizeof(*dir), GFP_KERNEL); + dir = kmalloc_obj(*dir); if (!dir) { asd_printk("no memory for ocm dir\n"); return -ENOMEM; @@ -1040,7 +1040,7 @@ int asd_read_flash(struct asd_ha_struct *asd_ha) if (err) return err; - flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL); + flash_dir = kmalloc_obj(*flash_dir); if (!flash_dir) return -ENOMEM; diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 4bfd03724ad6..b26a468ddc98 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -488,7 +488,6 @@ static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task, scb->ssp_task.conn_handle = cpu_to_le16( (u16)(unsigned long)dev->lldd_dev); scb->ssp_task.data_dir = data_dir_flags[task->data_dir]; - scb->ssp_task.retry_count = scb->ssp_task.retry_count; ascb->tasklet_complete = asd_task_tasklet_complete; diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 27d32b8c2987..28ac92b041fe 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -31,7 +31,7 @@ static int asd_enqueue_internal(struct asd_ascb *ascb, res = asd_post_ascb_list(ascb->ha, ascb, 1); if (unlikely(res)) - del_timer(&ascb->timer); + timer_delete(&ascb->timer); return res; } @@ -58,7 +58,7 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, { struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("%s: here\n", __func__); - if (!del_timer(&ascb->timer)) { + if (!timer_delete(&ascb->timer)) { ASD_DPRINTK("%s: couldn't delete timer\n", __func__); return; } @@ -70,7 +70,7 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, static void asd_clear_nexus_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("%s: here\n", __func__); @@ -244,7 +244,7 @@ static int asd_clear_nexus_index(struct sas_task *task) static void asd_tmf_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("tmf timed out\n"); @@ -303,7 +303,7 @@ static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, { struct tasklet_completion_status *tcs; - if (!del_timer(&ascb->timer)) + if (!timer_delete(&ascb->timer)) return; tcs = ascb->uldd_task; diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c index 003e61831e33..f972a3c90a2f 100644 --- a/drivers/scsi/am53c974.c +++ b/drivers/scsi/am53c974.c @@ -396,7 +396,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev, goto fail_disable_device; } - pep = kzalloc(sizeof(struct pci_esp_priv), GFP_KERNEL); + pep = kzalloc_obj(struct pci_esp_priv); if (!pep) { dev_printk(KERN_INFO, &pdev->dev, "failed to allocate esp_priv\n"); diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 8e3d4799ce93..1990af2bef95 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -194,7 +194,7 @@ static const struct bin_attribute arcmsr_sysfs_message_read_attr = { .mode = S_IRUSR , }, .size = ARCMSR_API_DATA_BUFLEN, - .read_new = arcmsr_sysfs_iop_message_read, + .read = arcmsr_sysfs_iop_message_read, }; static const struct bin_attribute arcmsr_sysfs_message_write_attr = { @@ -203,7 +203,7 @@ static const struct bin_attribute arcmsr_sysfs_message_write_attr = { .mode = S_IWUSR, }, .size = ARCMSR_API_DATA_BUFLEN, - .write_new = arcmsr_sysfs_iop_message_write, + .write = arcmsr_sysfs_iop_message_write, }; static const struct bin_attribute arcmsr_sysfs_message_clear_attr = { @@ -212,7 +212,7 @@ static const struct bin_attribute arcmsr_sysfs_message_clear_attr = { .mode = S_IWUSR, }, .size = 1, - .write_new = arcmsr_sysfs_iop_message_clear, + .write = arcmsr_sysfs_iop_message_clear, }; int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 221a520e8a9b..8aa948f06cac 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -112,8 +112,9 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info); -static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); + struct gendisk *disk, sector_t capacity, int *info); +static enum scsi_qc_status arcmsr_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); static int __maybe_unused arcmsr_suspend(struct device *dev); @@ -377,11 +378,11 @@ static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) } static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *geom) + struct gendisk *disk, sector_t capacity, int *geom) { int heads, sectors, cylinders, total_capacity; - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; total_capacity = capacity; @@ -1161,8 +1162,8 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; out_free_sysfs: if (set_date_time) - del_timer_sync(&acb->refresh_timer); - del_timer_sync(&acb->eternal_timer); + timer_delete_sync(&acb->refresh_timer); + timer_delete_sync(&acb->eternal_timer); flush_work(&acb->arcmsr_do_message_isr_bh); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); @@ -1204,9 +1205,9 @@ static int __maybe_unused arcmsr_suspend(struct device *dev) arcmsr_disable_outbound_ints(acb); arcmsr_free_irq(pdev, acb); - del_timer_sync(&acb->eternal_timer); + timer_delete_sync(&acb->eternal_timer); if (set_date_time) - del_timer_sync(&acb->refresh_timer); + timer_delete_sync(&acb->refresh_timer); flush_work(&acb->arcmsr_do_message_isr_bh); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); @@ -1685,9 +1686,9 @@ static void arcmsr_free_pcidev(struct AdapterControlBlock *acb) arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); flush_work(&acb->arcmsr_do_message_isr_bh); - del_timer_sync(&acb->eternal_timer); + timer_delete_sync(&acb->eternal_timer); if (set_date_time) - del_timer_sync(&acb->refresh_timer); + timer_delete_sync(&acb->refresh_timer); pdev = acb->pdev; arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); @@ -1718,9 +1719,9 @@ static void arcmsr_remove(struct pci_dev *pdev) arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); flush_work(&acb->arcmsr_do_message_isr_bh); - del_timer_sync(&acb->eternal_timer); + timer_delete_sync(&acb->eternal_timer); if (set_date_time) - del_timer_sync(&acb->refresh_timer); + timer_delete_sync(&acb->refresh_timer); arcmsr_disable_outbound_ints(acb); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); @@ -1765,9 +1766,9 @@ static void arcmsr_shutdown(struct pci_dev *pdev) (struct AdapterControlBlock *)host->hostdata; if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) return; - del_timer_sync(&acb->eternal_timer); + timer_delete_sync(&acb->eternal_timer); if (set_date_time) - del_timer_sync(&acb->refresh_timer); + timer_delete_sync(&acb->refresh_timer); arcmsr_disable_outbound_ints(acb); arcmsr_free_irq(pdev, acb); flush_work(&acb->arcmsr_do_message_isr_bh); @@ -3312,7 +3313,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, } } -static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status arcmsr_queue_command_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; @@ -3935,7 +3936,8 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, static void arcmsr_set_iop_datetime(struct timer_list *t) { - struct AdapterControlBlock *pacb = from_timer(pacb, t, refresh_timer); + struct AdapterControlBlock *pacb = timer_container_of(pacb, t, + refresh_timer); unsigned int next_time; struct tm tm; @@ -4263,7 +4265,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) static void arcmsr_request_device_map(struct timer_list *t) { - struct AdapterControlBlock *acb = from_timer(acb, t, eternal_timer); + struct AdapterControlBlock *acb = timer_container_of(acb, t, + eternal_timer); if (acb->acb_flags & (ACB_F_MSG_GET_CONFIG | ACB_F_BUS_RESET | ACB_F_ABORT)) { mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } else { diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index e50a3dbf9de3..79d7d7336b6a 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -591,7 +591,7 @@ datadir_t acornscsi_datadirection(int command) case CHANGE_DEFINITION: case COMPARE: case COPY: case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: - case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE_6: case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: case WRITE_6: case WRITE_10: case WRITE_VERIFY: case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: @@ -2408,7 +2408,7 @@ acornscsi_intr(int irq, void *dev_id) * Params : cmd - SCSI command * Returns : 0, or < 0 on error. */ -static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) { struct scsi_pointer *scsi_pointer = arm_scsi_pointer(SCpnt); void (*done)(struct scsi_cmnd *) = scsi_done; diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 4ce0b2d73614..fccfacaaf1d5 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2202,11 +2202,12 @@ no_command: * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) +static enum scsi_qc_status +fas216_queue_command_internal(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - int result; + enum scsi_qc_status result; fas216_checkmagic(info); @@ -2243,7 +2244,7 @@ static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, return result; } -static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_queue_command_lck(struct scsi_cmnd *SCpnt) { return fas216_queue_command_internal(SCpnt, scsi_done); } @@ -2273,7 +2274,7 @@ static void fas216_internal_done(struct scsi_cmnd *SCpnt) * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; @@ -2327,11 +2328,11 @@ DEF_SCSI_QCMD(fas216_noqueue_command) */ static void fas216_eh_timer(struct timer_list *t) { - FAS216_Info *info = from_timer(info, t, eh_timer); + FAS216_Info *info = timer_container_of(info, t, eh_timer); fas216_log(info, LOG_ERROR, "error handling timed out\n"); - del_timer(&info->eh_timer); + timer_delete(&info->eh_timer); if (info->rst_bus_status == 0) info->rst_bus_status = -1; @@ -2532,7 +2533,7 @@ int fas216_eh_device_reset(struct scsi_cmnd *SCpnt) */ wait_event(info->eh_wait, info->rst_dev_status); - del_timer_sync(&info->eh_timer); + timer_delete_sync(&info->eh_timer); spin_lock_irqsave(&info->host_lock, flags); info->rstSCpnt = NULL; @@ -2622,7 +2623,7 @@ int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt) * Wait one second for the interrupt. */ wait_event(info->eh_wait, info->rst_bus_status); - del_timer_sync(&info->eh_timer); + timer_delete_sync(&info->eh_timer); fas216_log(info, LOG_ERROR, "bus reset complete: %s\n", info->rst_bus_status == 1 ? "success" : "failed"); diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 08113277a2a9..29f710f9cb51 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -338,21 +338,24 @@ extern int fas216_init (struct Scsi_Host *instance); */ extern int fas216_add (struct Scsi_Host *instance, struct device *dev); -/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +extern enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); -/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + * struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process, and process it to completion. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *); +extern enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index 978df23ce188..797cf4971f5d 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -71,7 +71,7 @@ int queue_initialise (Queue_t *queue) * need to keep free lists or allocate this * memory. */ - queue->alloc = q = kmalloc_array(nqueues, sizeof(QE_t), GFP_KERNEL); + queue->alloc = q = kmalloc_objs(QE_t, nqueues); if (q) { for (; nqueues; q++, nqueues--) { SET_MAGIC(q, QUEUE_MAGIC_FREE); diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 401242912855..67459d81f479 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -617,7 +617,7 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) * * Queue a command to the ATP queue. Called with the host lock held. */ -static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p) +static enum scsi_qc_status atp870u_queuecommand_lck(struct scsi_cmnd *req_p) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char c; @@ -1692,7 +1692,7 @@ static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr) } -static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev, +static int atp870u_biosparam(struct scsi_device *disk, struct gendisk *unused, sector_t capacity, int *ip) { int heads, sectors, cylinders; diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 76a1e373386e..fd18d4d3d219 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -303,7 +303,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; - inv_tbl = kzalloc(sizeof(*inv_tbl), GFP_ATOMIC); + inv_tbl = kzalloc_obj(*inv_tbl, GFP_ATOMIC); if (!inv_tbl) { spin_unlock_bh(&session->frwd_lock); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, @@ -2476,25 +2476,21 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) /* Allocate memory for wrb_context */ phwi_ctrlr = phba->phwi_ctrlr; - phwi_ctrlr->wrb_context = kcalloc(phba->params.cxns_per_ctrl, - sizeof(struct hwi_wrb_context), - GFP_KERNEL); + phwi_ctrlr->wrb_context = kzalloc_objs(struct hwi_wrb_context, + phba->params.cxns_per_ctrl); if (!phwi_ctrlr->wrb_context) { kfree(phba->phwi_ctrlr); return -ENOMEM; } - phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr), - GFP_KERNEL); + phba->init_mem = kzalloc_objs(*mem_descr, SE_MEM_MAX); if (!phba->init_mem) { kfree(phwi_ctrlr->wrb_context); kfree(phba->phwi_ctrlr); return -ENOMEM; } - mem_arr_orig = kmalloc_array(BEISCSI_MAX_FRAGS_INIT, - sizeof(*mem_arr_orig), - GFP_KERNEL); + mem_arr_orig = kmalloc_objs(*mem_arr_orig, BEISCSI_MAX_FRAGS_INIT); if (!mem_arr_orig) { kfree(phba->init_mem); kfree(phwi_ctrlr->wrb_context); @@ -2542,8 +2538,7 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) } while (alloc_size); mem_descr->num_elements = j; mem_descr->size_in_bytes = phba->mem_req[i]; - mem_descr->mem_array = kmalloc_array(j, sizeof(*mem_arr), - GFP_KERNEL); + mem_descr->mem_array = kmalloc_objs(*mem_arr, j); if (!mem_descr->mem_array) goto free_mem; @@ -2629,9 +2624,8 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) /* Allocate memory for WRBQ */ phwi_ctxt = phwi_ctrlr->phwi_ctxt; - phwi_ctxt->be_wrbq = kcalloc(phba->params.cxns_per_ctrl, - sizeof(struct be_queue_info), - GFP_KERNEL); + phwi_ctxt->be_wrbq = kzalloc_objs(struct be_queue_info, + phba->params.cxns_per_ctrl); if (!phwi_ctxt->be_wrbq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : WRBQ Mem Alloc Failed\n"); @@ -2641,18 +2635,16 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) for (index = 0; index < phba->params.cxns_per_ctrl; index++) { pwrb_context = &phwi_ctrlr->wrb_context[index]; pwrb_context->pwrb_handle_base = - kcalloc(phba->params.wrbs_per_cxn, - sizeof(struct wrb_handle *), - GFP_KERNEL); + kzalloc_objs(struct wrb_handle *, + phba->params.wrbs_per_cxn); if (!pwrb_context->pwrb_handle_base) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); goto init_wrb_hndl_failed; } pwrb_context->pwrb_handle_basestd = - kcalloc(phba->params.wrbs_per_cxn, - sizeof(struct wrb_handle *), - GFP_KERNEL); + kzalloc_objs(struct wrb_handle *, + phba->params.wrbs_per_cxn); if (!pwrb_context->pwrb_handle_basestd) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); @@ -3363,9 +3355,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, idx = 0; mem_descr = phba->init_mem; mem_descr += HWI_MEM_WRB; - pwrb_arr = kmalloc_array(phba->params.cxns_per_ctrl, - sizeof(*pwrb_arr), - GFP_KERNEL); + pwrb_arr = kmalloc_objs(*pwrb_arr, phba->params.cxns_per_ctrl); if (!pwrb_arr) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Memory alloc failed in create wrb ring.\n"); @@ -3902,18 +3892,16 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) mem_descr_sglh = phba->init_mem; mem_descr_sglh += HWI_MEM_SGLH; if (1 == mem_descr_sglh->num_elements) { - phba->io_sgl_hndl_base = kcalloc(phba->params.ios_per_ctrl, - sizeof(struct sgl_handle *), - GFP_KERNEL); + phba->io_sgl_hndl_base = kzalloc_objs(struct sgl_handle *, + phba->params.ios_per_ctrl); if (!phba->io_sgl_hndl_base) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); return -ENOMEM; } phba->eh_sgl_hndl_base = - kcalloc(phba->params.icds_per_ctrl - - phba->params.ios_per_ctrl, - sizeof(struct sgl_handle *), GFP_KERNEL); + kzalloc_objs(struct sgl_handle *, + phba->params.icds_per_ctrl - phba->params.ios_per_ctrl); if (!phba->eh_sgl_hndl_base) { kfree(phba->io_sgl_hndl_base); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -4004,8 +3992,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { - ptr_cid_info = kzalloc(sizeof(struct ulp_cid_info), - GFP_KERNEL); + ptr_cid_info = kzalloc_obj(struct ulp_cid_info); if (!ptr_cid_info) { ret = -ENOMEM; @@ -4031,18 +4018,16 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) phba->cid_array_info[ulp_num] = ptr_cid_info; } } - phba->ep_array = kcalloc(phba->params.cxns_per_ctrl, - sizeof(struct iscsi_endpoint *), - GFP_KERNEL); + phba->ep_array = kzalloc_objs(struct iscsi_endpoint *, + phba->params.cxns_per_ctrl); if (!phba->ep_array) { ret = -ENOMEM; goto free_memory; } - phba->conn_table = kcalloc(phba->params.cxns_per_ctrl, - sizeof(struct beiscsi_conn *), - GFP_KERNEL); + phba->conn_table = kzalloc_objs(struct beiscsi_conn *, + phba->params.cxns_per_ctrl); if (!phba->conn_table) { kfree(phba->ep_array); phba->ep_array = NULL; @@ -5240,7 +5225,7 @@ static void beiscsi_eqd_update_work(struct work_struct *work) static void beiscsi_hw_tpe_check(struct timer_list *t) { - struct beiscsi_hba *phba = from_timer(phba, t, hw_check); + struct beiscsi_hba *phba = timer_container_of(phba, t, hw_check); u32 wait; /* if not TPE, do nothing */ @@ -5257,7 +5242,7 @@ static void beiscsi_hw_tpe_check(struct timer_list *t) static void beiscsi_hw_health_check(struct timer_list *t) { - struct beiscsi_hba *phba = from_timer(phba, t, hw_check); + struct beiscsi_hba *phba = timer_container_of(phba, t, hw_check); beiscsi_detect_ue(phba); if (beiscsi_detect_ue(phba)) { @@ -5448,7 +5433,7 @@ static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev, "BM_%d : EEH error detected\n"); /* first stop UE detection when PCI error detected */ - del_timer_sync(&phba->hw_check); + timer_delete_sync(&phba->hw_check); cancel_delayed_work_sync(&phba->recover_port); /* sessions are no longer valid, so first fail the sessions */ @@ -5633,7 +5618,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; - phba->wq = alloc_workqueue("beiscsi_%02x_wq", WQ_MEM_RECLAIM, 1, + phba->wq = alloc_workqueue("beiscsi_%02x_wq", + WQ_MEM_RECLAIM | WQ_PERCPU, 1, phba->shost->host_no); if (!phba->wq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -5746,7 +5732,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) } /* first stop UE detection before unloading */ - del_timer_sync(&phba->hw_check); + timer_delete_sync(&phba->hw_check); cancel_delayed_work_sync(&phba->recover_port); cancel_work_sync(&phba->sess_work); @@ -5776,7 +5762,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) } -static struct pci_error_handlers beiscsi_eeh_handlers = { +static const struct pci_error_handlers beiscsi_eeh_handlers = { .error_detected = beiscsi_eeh_err_detected, .slot_reset = beiscsi_eeh_reset, .resume = beiscsi_eeh_resume, diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 4e899ec1477d..b1cba986f0fb 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1025,6 +1025,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) &nonemb_cmd->dma, GFP_KERNEL); if (!nonemb_cmd->va) { + free_mcc_wrb(ctrl, tag); mutex_unlock(&ctrl->mbox_lock); return 0; } diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index a99a101b95ef..2559df8baa05 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -1282,7 +1282,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; - fwcfg->num_cqs = fwcfg->num_cqs; fwcfg->num_ioim_reqs = be16_to_cpu(fwcfg->num_ioim_reqs); fwcfg->num_fwtio_reqs = be16_to_cpu(fwcfg->num_fwtio_reqs); fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs); diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index e52ce9b01f49..9b57312f43f5 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -1169,7 +1169,7 @@ bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) * This function should be used only if there is any requirement * to check for FOS version below 6.3. * To check if the attached fabric is a brocade fabric, use - * bfa_lps_is_brcd_fabric() which works for FOS versions 6.3 + * fabric->lps->brcd_switch which works for FOS versions 6.3 * or above only. */ diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 9a85f417018f..2df399c537c1 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -1863,7 +1863,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) u8 *curr_ptr; u16 templen, count; - fcs_hba_attr = kzalloc(sizeof(*fcs_hba_attr), GFP_KERNEL); + fcs_hba_attr = kzalloc_obj(*fcs_hba_attr); if (!fcs_hba_attr) return -ENOMEM; diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 6aa1d3a7e24b..448f736457f0 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -327,7 +327,7 @@ bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event) case BFAD_E_EXIT_COMP: bfa_sm_set_state(bfad, bfad_sm_uninit); bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); + timer_delete_sync(&bfad->hal_tmo); break; default: @@ -376,7 +376,7 @@ bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event) case BFAD_E_EXIT_COMP: bfa_sm_set_state(bfad, bfad_sm_uninit); bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); + timer_delete_sync(&bfad->hal_tmo); bfad_im_probe_undo(bfad); bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; bfad_uncfg_pport(bfad); @@ -473,7 +473,7 @@ bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport, { bfa_status_t rc = BFA_STATUS_OK; - *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC); + *rport_drv = kzalloc_obj(struct bfad_rport_s, GFP_ATOMIC); if (*rport_drv == NULL) { rc = BFA_STATUS_ENOMEM; goto ext; @@ -496,7 +496,7 @@ bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) struct bfad_vport_s *vport; int rc; - vport = kzalloc(sizeof(struct bfad_vport_s), GFP_ATOMIC); + vport = kzalloc_obj(struct bfad_vport_s, GFP_ATOMIC); if (!vport) { bfa_trc(bfad, 0); return; @@ -640,7 +640,7 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id, unsigned long flags; struct completion fcomp; - vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); + vport = kzalloc_obj(struct bfad_vport_s); if (!vport) { rc = BFA_STATUS_ENOMEM; goto ext; @@ -685,7 +685,8 @@ ext: void bfad_bfa_tmo(struct timer_list *t) { - struct bfad_s *bfad = from_timer(bfad, t, hal_tmo); + struct bfad_s *bfad = timer_container_of(bfad, t, + hal_tmo); unsigned long flags; struct list_head doneq; @@ -1270,13 +1271,13 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) (PCI_FUNC(pdev->devfn) != 0)) return -ENODEV; - bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL); + bfad = kzalloc_obj(struct bfad_s); if (!bfad) { error = -ENOMEM; goto out; } - bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL); + bfad->trcmod = kzalloc_obj(struct bfa_trc_mod_s); if (!bfad->trcmod) { printk(KERN_WARNING "Error alloc trace buffer!\n"); error = -ENOMEM; @@ -1421,7 +1422,7 @@ bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) /* Suspend/fail all bfa operations */ bfa_ioc_suspend(&bfad->bfa.ioc); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - del_timer_sync(&bfad->hal_tmo); + timer_delete_sync(&bfad->hal_tmo); ret = PCI_ERS_RESULT_CAN_RECOVER; break; case pci_channel_io_frozen: /* fatal error */ @@ -1435,7 +1436,7 @@ bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) wait_for_completion(&bfad->comp); bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); + timer_delete_sync(&bfad->hal_tmo); pci_disable_device(pdev); ret = PCI_ERS_RESULT_NEED_RESET; break; @@ -1527,7 +1528,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev) goto out_disable_device; } - pci_save_state(pdev); pci_set_master(pdev); rc = dma_set_mask_and_coherent(&bfad->pcidev->dev, DMA_BIT_MASK(64)); @@ -1566,7 +1566,7 @@ bfad_pci_mmio_enabled(struct pci_dev *pdev) wait_for_completion(&bfad->comp); bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); + timer_delete_sync(&bfad->hal_tmo); pci_disable_device(pdev); return PCI_ERS_RESULT_NEED_RESET; @@ -1642,7 +1642,7 @@ MODULE_DEVICE_TABLE(pci, bfad_id_table); /* * PCI error recovery handlers. */ -static struct pci_error_handlers bfad_err_handler = { +static const struct pci_error_handlers bfad_err_handler = { .error_detected = bfad_pci_error_detected, .slot_reset = bfad_pci_slot_reset, .mmio_enabled = bfad_pci_mmio_enabled, diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 54bc1539e1e9..9751beff817d 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -264,7 +264,7 @@ bfad_im_get_stats(struct Scsi_Host *shost) bfa_status_t rc; unsigned long flags; - fcstats = kzalloc(sizeof(union bfa_port_stats_u), GFP_KERNEL); + fcstats = kzalloc_obj(union bfa_port_stats_u); if (fcstats == NULL) return NULL; @@ -907,8 +907,7 @@ bfad_im_num_of_discovered_ports_show(struct device *dev, struct bfa_rport_qualifier_s *rports = NULL; unsigned long flags; - rports = kcalloc(nrports, sizeof(struct bfa_rport_qualifier_s), - GFP_ATOMIC); + rports = kzalloc_objs(struct bfa_rport_qualifier_s, nrports, GFP_ATOMIC); if (rports == NULL) return sysfs_emit(buf, "Failed\n"); diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 54bd11e6d593..292bc9aa43f1 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -3410,7 +3410,7 @@ bfad_im_bsg_els_ct_request(struct bsg_job *job) goto out; } - drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL); + drv_fcxp = kzalloc_obj(struct bfad_fcxp); if (drv_fcxp == NULL) { kfree(bsg_fcpt); rc = -ENOMEM; diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index f6dd077d47c9..2f9bb8fa7fa7 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -46,7 +46,7 @@ bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file) struct bfad_s *bfad = port->bfad; struct bfad_debug_info *debug; - debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + debug = kzalloc_obj(struct bfad_debug_info); if (!debug) return -ENOMEM; @@ -67,7 +67,7 @@ bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file) unsigned long flags; int rc; - fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + fw_debug = kzalloc_obj(struct bfad_debug_info); if (!fw_debug) return -ENOMEM; @@ -109,7 +109,7 @@ bfad_debugfs_open_fwsave(struct inode *inode, struct file *file) unsigned long flags; int rc; - fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + fw_debug = kzalloc_obj(struct bfad_debug_info); if (!fw_debug) return -ENOMEM; @@ -147,7 +147,7 @@ bfad_debugfs_open_reg(struct inode *inode, struct file *file) { struct bfad_debug_info *reg_debug; - reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + reg_debug = kzalloc_obj(struct bfad_debug_info); if (!reg_debug) return -ENOMEM; diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index a719a18f0fbc..97990b285e17 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -24,7 +24,8 @@ DEFINE_IDR(bfad_im_port_index); struct scsi_transport_template *bfad_im_scsi_transport_template; struct scsi_transport_template *bfad_im_scsi_vport_transport_template; static void bfad_im_itnim_work_handler(struct work_struct *work); -static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd); +static enum scsi_qc_status bfad_im_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmnd); static int bfad_im_sdev_init(struct scsi_device *sdev); static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim); @@ -425,7 +426,7 @@ int bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, struct bfad_itnim_s **itnim_drv) { - *itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC); + *itnim_drv = kzalloc_obj(struct bfad_itnim_s, GFP_ATOMIC); if (*itnim_drv == NULL) return -ENOMEM; @@ -621,7 +622,7 @@ bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port) int rc = BFA_STATUS_OK; struct bfad_im_port_s *im_port; - im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC); + im_port = kzalloc_obj(struct bfad_im_port_s, GFP_ATOMIC); if (im_port == NULL) { rc = BFA_STATUS_ENOMEM; goto ext; @@ -697,7 +698,7 @@ bfad_im_probe(struct bfad_s *bfad) { struct bfad_im_s *im; - im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL); + im = kzalloc_obj(struct bfad_im_s); if (im == NULL) return BFA_STATUS_ENOMEM; @@ -706,6 +707,7 @@ bfad_im_probe(struct bfad_s *bfad) if (bfad_thread_workq(bfad) != BFA_STATUS_OK) { kfree(im); + bfad->im = NULL; return BFA_STATUS_FAILED; } @@ -992,7 +994,7 @@ bfad_im_supported_speeds(struct bfa_s *bfa) struct bfa_ioc_attr_s *ioc_attr; u32 supported_speed = 0; - ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL); + ioc_attr = kzalloc_obj(struct bfa_ioc_attr_s); if (!ioc_attr) return 0; @@ -1198,7 +1200,7 @@ bfad_im_itnim_work_handler(struct work_struct *work) /* * Scsi_Host template entry, queue a SCSI command to the BFAD. */ -static int bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct bfad_im_port_s *im_port = diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index ecdc0f0f4f4e..d12eeb13384a 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -2,10 +2,8 @@ config SCSI_BNX2X_FCOE tristate "QLogic FCoE offload support" depends on PCI - depends on (IPV6 || IPV6=n) depends on LIBFC depends on LIBFCOE - depends on MMU select NETDEVICES select ETHERNET select NET_VENDOR_BROADCOM diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 6d47a4d8eed6..8c8968ec8cb4 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -498,7 +498,8 @@ static inline struct bnx2fc_priv *bnx2fc_priv(struct scsi_cmnd *cmd) struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt); struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type); void bnx2fc_cmd_release(struct kref *ref); -int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd); +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba); int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba); int bnx2fc_send_session_ofld_req(struct fcoe_port *port, diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 754f2e82d955..749e30aaf926 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -80,7 +80,7 @@ int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req) aborted_io_req->xid); memset(&rrq, 0, sizeof(rrq)); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_NOIO); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n"); rc = -ENOMEM; @@ -189,7 +189,7 @@ int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp) int rc; fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n"); return -ENOMEM; @@ -217,7 +217,7 @@ int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp) int rc; fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); return -ENOMEM; @@ -245,7 +245,7 @@ int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp) int rc; fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); return -ENOMEM; @@ -592,7 +592,7 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) BNX2FC_IO_DBG(orig_io_req, "Sending REC\n"); memset(&rec, 0, sizeof(rec)); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n"); rc = -ENOMEM; @@ -633,7 +633,7 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n"); memset(&srr, 0, sizeof(srr)); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n"); rc = -ENOMEM; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 5ac20c93637c..26e0ff380860 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -837,7 +837,7 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) static void bnx2fc_destroy_timer(struct timer_list *t) { - struct bnx2fc_hba *hba = from_timer(hba, t, destroy_timer); + struct bnx2fc_hba *hba = timer_container_of(hba, t, destroy_timer); printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " "Destroy compl not received!!\n"); @@ -1356,7 +1356,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) struct fcoe_capabilities *fcoe_cap; int rc; - hba = kzalloc(sizeof(*hba), GFP_KERNEL); + hba = kzalloc_obj(*hba); if (!hba) { printk(KERN_ERR PFX "Unable to allocate hba structure\n"); return NULL; @@ -1381,8 +1381,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) hba->next_conn_id = 0; hba->tgt_ofld_list = - kcalloc(BNX2FC_NUM_MAX_SESS, sizeof(struct bnx2fc_rport *), - GFP_KERNEL); + kzalloc_objs(struct bnx2fc_rport *, BNX2FC_NUM_MAX_SESS); if (!hba->tgt_ofld_list) { printk(KERN_ERR PFX "Unable to allocate tgt offload list\n"); goto tgtofld_err; @@ -1492,7 +1491,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, struct bnx2fc_hba *hba = interface->hba; int rc = 0; - blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); + blport = kzalloc_obj(struct bnx2fc_lport); if (!blport) { BNX2FC_HBA_DBG(ctlr->lp, "Unable to alloc blport\n"); return NULL; @@ -1599,7 +1598,7 @@ static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) struct bnx2fc_hba *hba = interface->hba; /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); + timer_delete_sync(&port->timer); /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); @@ -1938,7 +1937,7 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba) if (signal_pending(current)) flush_signals(current); - del_timer_sync(&hba->destroy_timer); + timer_delete_sync(&hba->destroy_timer); } bnx2fc_unbind_adapter_devices(hba); } @@ -2200,7 +2199,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) if (!hba->cnic->get_fc_npiv_tbl) goto done; - npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL); + npiv_tbl = kzalloc_obj(struct cnic_fc_npiv_tbl); if (!npiv_tbl) goto done; @@ -2695,7 +2694,7 @@ static int __init bnx2fc_mod_init(void) if (rc) goto detach_ft; - bnx2fc_wq = alloc_workqueue("bnx2fc", 0, 0); + bnx2fc_wq = alloc_workqueue("bnx2fc", WQ_PERCPU, 0); if (!bnx2fc_wq) { rc = -ENOMEM; goto release_bt; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 090d436bcef8..a5ecb87d5b2d 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -561,7 +561,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, u8 op; - unsol_els = kzalloc(sizeof(*unsol_els), GFP_ATOMIC); + unsol_els = kzalloc_obj(*unsol_els, GFP_ATOMIC); if (!unsol_els) { BNX2FC_TGT_DBG(tgt, "Unable to allocate unsol_work\n"); return; @@ -972,7 +972,7 @@ static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe, struct fcoe_task_ctx_entry *task) { struct bnx2fc_work *work; - work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC); + work = kzalloc_obj(struct bnx2fc_work, GFP_ATOMIC); if (!work) return NULL; diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 33057908f147..9c7a541a4523 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -241,15 +241,13 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) } cmgr->hba = hba; - cmgr->free_list = kcalloc(arr_sz, sizeof(*cmgr->free_list), - GFP_KERNEL); + cmgr->free_list = kzalloc_objs(*cmgr->free_list, arr_sz); if (!cmgr->free_list) { printk(KERN_ERR PFX "failed to alloc free_list\n"); goto mem_err; } - cmgr->free_list_lock = kcalloc(arr_sz, sizeof(*cmgr->free_list_lock), - GFP_KERNEL); + cmgr->free_list_lock = kzalloc_objs(*cmgr->free_list_lock, arr_sz); if (!cmgr->free_list_lock) { printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); kfree(cmgr->free_list); @@ -272,7 +270,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) xid = BNX2FC_MIN_XID; num_pri_ios = num_ios - hba->elstm_xids; for (i = 0; i < num_ios; i++) { - io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); + io_req = kzalloc_obj(*io_req); if (!io_req) { printk(KERN_ERR PFX "failed to alloc io_req\n"); @@ -942,7 +940,7 @@ int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, port = orig_io_req->port; interface = port->priv; - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(struct bnx2fc_els_cb_arg, GFP_ATOMIC); if (!cb_arg) { printk(KERN_ERR PFX "Unable to alloc cb_arg for seq clnup\n"); rc = -ENOMEM; @@ -1836,8 +1834,8 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, * * This is the IO strategy routine, called by SCSI-ML **/ -int bnx2fc_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd) +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index eb3209103312..77dcdfc412b1 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -30,7 +30,7 @@ static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id); static void bnx2fc_upld_timer(struct timer_list *t) { - struct bnx2fc_rport *tgt = from_timer(tgt, t, upld_timer); + struct bnx2fc_rport *tgt = timer_container_of(tgt, t, upld_timer); BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); /* fake upload completion */ @@ -43,7 +43,7 @@ static void bnx2fc_upld_timer(struct timer_list *t) static void bnx2fc_ofld_timer(struct timer_list *t) { - struct bnx2fc_rport *tgt = from_timer(tgt, t, ofld_timer); + struct bnx2fc_rport *tgt = timer_container_of(tgt, t, ofld_timer); BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n"); /* NOTE: This function should never be called, as @@ -74,7 +74,7 @@ static void bnx2fc_ofld_wait(struct bnx2fc_rport *tgt) &tgt->flags))); if (signal_pending(current)) flush_signals(current); - del_timer_sync(&tgt->ofld_timer); + timer_delete_sync(&tgt->ofld_timer); } static void bnx2fc_offload_session(struct fcoe_port *port, @@ -283,7 +283,7 @@ static void bnx2fc_upld_wait(struct bnx2fc_rport *tgt) &tgt->flags))); if (signal_pending(current)) flush_signals(current); - del_timer_sync(&tgt->upld_timer); + timer_delete_sync(&tgt->upld_timer); } static void bnx2fc_upload_session(struct fcoe_port *port, diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig index 0cc06c2ce0b8..e649a04fab1d 100644 --- a/drivers/scsi/bnx2i/Kconfig +++ b/drivers/scsi/bnx2i/Kconfig @@ -3,8 +3,6 @@ config SCSI_BNX2_ISCSI tristate "QLogic NetXtreme II iSCSI support" depends on NET depends on PCI - depends on (IPV6 || IPV6=n) - depends on MMU select SCSI_ISCSI_ATTRS select NETDEVICES select ETHERNET diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 6c864b093ac9..d24cc2c795d6 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -685,7 +685,7 @@ void bnx2i_update_iscsi_conn(struct iscsi_conn *conn) */ void bnx2i_ep_ofld_timer(struct timer_list *t) { - struct bnx2i_endpoint *ep = from_timer(ep, t, ofld_timer); + struct bnx2i_endpoint *ep = timer_container_of(ep, t, ofld_timer); if (ep->state == EP_STATE_OFLD_START) { printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n"); @@ -1925,7 +1925,7 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, goto err; } /* Alloc and copy to the cqe */ - bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); + bnx2i_work = kzalloc_obj(struct bnx2i_work, GFP_ATOMIC); if (bnx2i_work) { INIT_LIST_HEAD(&bnx2i_work->list); bnx2i_work->session = session; diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 9971f32a663c..6c80e5b514fd 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1626,7 +1626,7 @@ static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn) if (signal_pending(current)) flush_signals(current); - del_timer_sync(&bnx2i_conn->ep->ofld_timer); + timer_delete_sync(&bnx2i_conn->ep->ofld_timer); iscsi_conn_start(cls_conn); return 0; @@ -1749,7 +1749,7 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, if (signal_pending(current)) flush_signals(current); - del_timer_sync(&ep->ofld_timer); + timer_delete_sync(&ep->ofld_timer); bnx2i_ep_destroy_list_del(hba, ep); @@ -1861,7 +1861,7 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, if (signal_pending(current)) flush_signals(current); - del_timer_sync(&bnx2i_ep->ofld_timer); + timer_delete_sync(&bnx2i_ep->ofld_timer); bnx2i_ep_ofld_list_del(hba, bnx2i_ep); @@ -2100,7 +2100,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (signal_pending(current)) flush_signals(current); - del_timer_sync(&bnx2i_ep->ofld_timer); + timer_delete_sync(&bnx2i_ep->ofld_timer); destroy_conn: bnx2i_ep_active_list_del(hba, bnx2i_ep); diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index baf5f4e47937..23301edf100d 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -44,7 +44,7 @@ bvme6000_probe(struct platform_device *dev) if (!MACH_IS_BVME6000) goto out; - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + hostdata = kzalloc_obj(struct NCR_700_Host_Parameters); if (!hostdata) { printk(KERN_ERR "bvme6000-scsi: " "Failed to allocate host data\n"); diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index fa07a6f54003..4010fdbf813c 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -364,8 +364,7 @@ ch_readconfig(scsi_changer *ch) } /* look up the devices of the data transfer elements */ - ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt), - GFP_KERNEL); + ch->dt = kzalloc_objs(*ch->dt, ch->counts[CHET_DT]); if (!ch->dt) { kfree(buffer); @@ -894,9 +893,9 @@ static long ch_ioctl(struct file *file, /* ------------------------------------------------------------------------ */ -static int ch_probe(struct device *dev) +static int ch_probe(struct scsi_device *sd) { - struct scsi_device *sd = to_scsi_device(dev); + struct device *dev = &sd->sdev_gendev; struct device *class_dev; int ret; scsi_changer *ch; @@ -904,7 +903,7 @@ static int ch_probe(struct device *dev) if (sd->type != TYPE_MEDIUM_CHANGER) return -ENODEV; - ch = kzalloc(sizeof(*ch), GFP_KERNEL); + ch = kzalloc_obj(*ch); if (NULL == ch) return -ENOMEM; @@ -967,8 +966,9 @@ free_ch: return ret; } -static int ch_remove(struct device *dev) +static void ch_remove(struct scsi_device *sd) { + struct device *dev = &sd->sdev_gendev; scsi_changer *ch = dev_get_drvdata(dev); spin_lock(&ch_index_lock); @@ -979,15 +979,14 @@ static int ch_remove(struct device *dev) device_destroy(&ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); scsi_device_put(ch->device); kref_put(&ch->ref, ch_destroy); - return 0; } static struct scsi_driver ch_template = { - .gendrv = { + .probe = ch_probe, + .remove = ch_remove, + .gendrv = { .name = "ch", .owner = THIS_MODULE, - .probe = ch_probe, - .remove = ch_remove, }, }; @@ -1014,7 +1013,7 @@ static int __init init_ch_module(void) SCSI_CHANGER_MAJOR); goto fail1; } - rc = scsi_register_driver(&ch_template.gendrv); + rc = scsi_register_driver(&ch_template); if (rc < 0) goto fail2; return 0; @@ -1028,7 +1027,7 @@ static int __init init_ch_module(void) static void __exit exit_ch_module(void) { - scsi_unregister_driver(&ch_template.gendrv); + scsi_unregister_driver(&ch_template); unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); class_unregister(&ch_sysfs_class); idr_destroy(&ch_index_idr); diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index e43c5413ce29..df9f81f29950 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -2429,7 +2429,7 @@ csio_hw_flash_fw(struct csio_hw *hw, int *reset) /* allocate memory to read the header of the firmware on the * card */ - card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); + card_fw = kmalloc_obj(*card_fw); if (!card_fw) return -ENOMEM; @@ -3701,7 +3701,7 @@ csio_mberr_worker(void *data) struct csio_mb *mbp_next; int rv; - del_timer_sync(&mbm->timer); + timer_delete_sync(&mbm->timer); spin_lock_irq(&hw->lock); if (list_empty(&mbm->cbfn_q)) { @@ -3738,7 +3738,7 @@ csio_mberr_worker(void *data) static void csio_hw_mb_timer(struct timer_list *t) { - struct csio_mbm *mbm = from_timer(mbm, t, timer); + struct csio_mbm *mbm = timer_container_of(mbm, t, timer); struct csio_hw *hw = mbm->hw; struct csio_mb *mbp = NULL; @@ -4107,7 +4107,7 @@ csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req) static void csio_mgmt_tmo_handler(struct timer_list *t) { - struct csio_mgmtm *mgmtm = from_timer(mgmtm, t, mgmt_timer); + struct csio_mgmtm *mgmtm = timer_container_of(mgmtm, t, mgmt_timer); struct list_head *tmp; struct csio_ioreq *io_req; @@ -4210,7 +4210,7 @@ csio_mgmtm_init(struct csio_mgmtm *mgmtm, struct csio_hw *hw) static void csio_mgmtm_exit(struct csio_mgmtm *mgmtm) { - del_timer_sync(&mgmtm->mgmt_timer); + timer_delete_sync(&mgmtm->mgmt_timer); } @@ -4389,7 +4389,7 @@ csio_hw_init(struct csio_hw *hw) INIT_LIST_HEAD(&hw->evt_free_q); for (i = 0; i < csio_evtq_sz; i++) { - evt_entry = kzalloc(sizeof(struct csio_evt_msg), GFP_KERNEL); + evt_entry = kzalloc_obj(struct csio_evt_msg); if (!evt_entry) { rv = -ENOMEM; csio_err(hw, "Failed to initialize eventq"); diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index 9a3f2ed050bd..238431524801 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -516,7 +516,7 @@ static struct csio_hw *csio_hw_alloc(struct pci_dev *pdev) { struct csio_hw *hw; - hw = kzalloc(sizeof(struct csio_hw), GFP_KERNEL); + hw = kzalloc_obj(struct csio_hw); if (!hw) goto err; @@ -1093,7 +1093,6 @@ csio_pci_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); - pci_save_state(pdev); /* Bring HW s/m to ready state. * but don't resume IOs. @@ -1162,7 +1161,7 @@ err_resume_exit: dev_err(&pdev->dev, "resume of device failed: %d\n", rv); } -static struct pci_error_handlers csio_err_handler = { +static const struct pci_error_handlers csio_err_handler = { .error_detected = csio_pci_error_detected, .slot_reset = csio_pci_slot_reset, .resume = csio_pci_resume, diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index 6cc1d53165a0..78d5ecd14f65 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -1837,7 +1837,7 @@ csio_ln_fdmi_init(struct csio_lnode *ln) struct csio_dma_buf *dma_buf; /* Allocate MGMT request required for FDMI */ - ln->mgmt_req = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL); + ln->mgmt_req = kzalloc_obj(struct csio_ioreq); if (!ln->mgmt_req) { csio_ln_err(ln, "Failed to alloc ioreq for FDMI\n"); CSIO_INC_STATS(hw, n_err_nomem); @@ -2002,7 +2002,7 @@ csio_ln_init(struct csio_lnode *ln) /* This is the lnode used during initialization */ - ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), GFP_KERNEL); + ln->fcfinfo = kzalloc_obj(struct csio_fcf_info); if (!ln->fcfinfo) { csio_ln_err(ln, "Failed to alloc FCF record\n"); CSIO_INC_STATS(hw, n_err_nomem); @@ -2029,8 +2029,7 @@ csio_ln_init(struct csio_lnode *ln) ln->fcfinfo = pln->fcfinfo; } else { /* Another non-root physical lnode (FCF) */ - ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), - GFP_KERNEL); + ln->fcfinfo = kzalloc_obj(struct csio_fcf_info); if (!ln->fcfinfo) { csio_ln_err(ln, "Failed to alloc FCF info\n"); CSIO_INC_STATS(hw, n_err_nomem); diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c index 94810b19e747..c7b4c464f6b8 100644 --- a/drivers/scsi/csiostor/csio_mb.c +++ b/drivers/scsi/csiostor/csio_mb.c @@ -1619,7 +1619,7 @@ csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q) mbp = mbm->mcurrent; /* Stop mailbox completion timer */ - del_timer_sync(&mbm->timer); + timer_delete_sync(&mbm->timer); /* Add completion to tail of cbfn queue */ list_add_tail(&mbp->list, cbfn_q); @@ -1682,7 +1682,7 @@ csio_mbm_init(struct csio_mbm *mbm, struct csio_hw *hw, void csio_mbm_exit(struct csio_mbm *mbm) { - del_timer_sync(&mbm->timer); + timer_delete_sync(&mbm->timer); CSIO_DB_ASSERT(mbm->mcurrent == NULL); CSIO_DB_ASSERT(list_empty(&mbm->req_q)); diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 34bde6650fae..b1de615cf316 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1775,8 +1775,8 @@ csio_scsi_cbfn(struct csio_hw *hw, struct csio_ioreq *req) * - Kicks off the SCSI state machine for this IO. * - Returns busy status on error. */ -static int -csio_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmnd) +static enum scsi_qc_status csio_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmnd) { struct csio_lnode *ln = shost_priv(host); struct csio_hw *hw = csio_lnode_to_hw(ln); @@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) struct csio_scsi_level_data sld; if (!rn) - goto fail; + goto fail_ret; csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", cmnd->device->lun, rn->flowid, rn->scsi_id); @@ -2220,6 +2220,7 @@ fail_ret_ioreq: csio_put_scsi_ioreq_lock(hw, scsim, ioreq); fail: CSIO_INC_STATS(rn, n_lun_rst_fail); +fail_ret: return FAILED; } @@ -2340,7 +2341,7 @@ csio_scsi_alloc_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw, for (n = 0; n < num_buf; n++) { /* Set unit size to request size */ unit_size = buf_size; - ddp_desc = kzalloc(sizeof(struct csio_dma_buf), GFP_KERNEL); + ddp_desc = kzalloc_obj(struct csio_dma_buf); if (!ddp_desc) { csio_err(hw, "Failed to allocate ddp descriptors," @@ -2434,7 +2435,7 @@ csio_scsim_init(struct csio_scsim *scm, struct csio_hw *hw) INIT_LIST_HEAD(&scm->ioreq_freelist); for (i = 0; i < csio_scsi_ioreqs; i++) { - ioreq = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL); + ioreq = kzalloc_obj(struct csio_ioreq); if (!ioreq) { csio_err(hw, "I/O request element allocation failed, " diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index a516df019c22..aa6007a21868 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -278,9 +278,8 @@ csio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize, q->un.iq.flq_idx = flq_idx; flq = wrm->q_arr[q->un.iq.flq_idx]; - flq->un.fl.bufs = kcalloc(flq->credits, - sizeof(struct csio_dma_buf), - GFP_KERNEL); + flq->un.fl.bufs = kzalloc_objs(struct csio_dma_buf, + flq->credits); if (!flq->un.fl.bufs) { csio_err(hw, "Failed to allocate FL queue bufs" @@ -960,7 +959,7 @@ csio_wr_copy_to_wrp(void *data_buf, struct csio_wr_pair *wrp, memcpy((uint8_t *) wrp->addr1 + wr_off, data_buf, nbytes); data_len -= nbytes; - /* Write the remaining data from the begining of circular buffer */ + /* Write the remaining data from the beginning of circular buffer */ if (data_len) { CSIO_DB_ASSERT(data_len <= wrp->size2); CSIO_DB_ASSERT(wrp->addr2 != NULL); @@ -1224,7 +1223,7 @@ csio_wr_process_iq(struct csio_hw *hw, struct csio_q *q, /* * We need to re-arm SGE interrupts in case we got a stray interrupt, - * especially in msix mode. With INTx, this may be a common occurence. + * especially in msix mode. With INTx, this may be a common occurrence. */ if (unlikely(!q->inc_idx)) { CSIO_INC_STATS(q, n_stray_comp); @@ -1651,12 +1650,12 @@ csio_wrm_init(struct csio_wrm *wrm, struct csio_hw *hw) return -EINVAL; } - wrm->q_arr = kcalloc(wrm->num_q, sizeof(struct csio_q *), GFP_KERNEL); + wrm->q_arr = kzalloc_objs(struct csio_q *, wrm->num_q); if (!wrm->q_arr) goto err; for (i = 0; i < wrm->num_q; i++) { - wrm->q_arr[i] = kzalloc(sizeof(struct csio_q), GFP_KERNEL); + wrm->q_arr[i] = kzalloc_obj(struct csio_q); if (!wrm->q_arr[i]) { while (--i >= 0) kfree(wrm->q_arr[i]); diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig index e20e6f3bfe64..143e881ec77e 100644 --- a/drivers/scsi/cxgbi/cxgb3i/Kconfig +++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config SCSI_CXGB3_ISCSI tristate "Chelsio T3 iSCSI support" - depends on PCI && INET && (IPV6 || IPV6=n) + depends on PCI && INET select NETDEVICES select ETHERNET select NET_VENDOR_CHELSIO diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index ec6530240707..69de9657f7cb 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -495,7 +495,7 @@ static int do_act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) spin_lock_bh(&csk->lock); if (csk->retry_timer.function) { - del_timer(&csk->retry_timer); + timer_delete(&csk->retry_timer); csk->retry_timer.function = NULL; } @@ -547,7 +547,7 @@ static int act_open_rpl_status_to_errno(int status) static void act_open_retry_timer(struct timer_list *t) { - struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); + struct cxgbi_sock *csk = timer_container_of(csk, t, retry_timer); struct sk_buff *skb; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig index 63c8a0f3cd0c..dd1c8ff36b00 100644 --- a/drivers/scsi/cxgbi/cxgb4i/Kconfig +++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config SCSI_CXGB4_ISCSI tristate "Chelsio T4 iSCSI support" - depends on PCI && INET && (IPV6 || IPV6=n) + depends on PCI && INET depends on PTP_1588_CLOCK_OPTIONAL depends on THERMAL || !THERMAL depends on ETHERNET diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index c07d2e3b4bcf..42676627c3af 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -930,7 +930,7 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) csk, csk->state, csk->flags, csk->tid); if (csk->retry_timer.function) { - del_timer(&csk->retry_timer); + timer_delete(&csk->retry_timer); csk->retry_timer.function = NULL; } @@ -988,7 +988,7 @@ static int act_open_rpl_status_to_errno(int status) static void csk_act_open_retry_timer(struct timer_list *t) { struct sk_buff *skb = NULL; - struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); + struct cxgbi_sock *csk = timer_container_of(csk, t, retry_timer); struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *, struct l2t_entry *); diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index bf75940f2be1..ea9631bfe2e2 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -556,7 +556,7 @@ EXPORT_SYMBOL_GPL(cxgbi_sock_free_cpl_skbs); static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) { - struct cxgbi_sock *csk = kzalloc(sizeof(*csk), GFP_NOIO); + struct cxgbi_sock *csk = kzalloc_obj(*csk, GFP_NOIO); if (!csk) { pr_info("alloc csk %zu failed.\n", sizeof(*csk)); diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig deleted file mode 100644 index c424d36e89a6..000000000000 --- a/drivers/scsi/cxlflash/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# IBM CXL-attached Flash Accelerator SCSI Driver -# - -config CXLFLASH - tristate "Support for IBM CAPI Flash (DEPRECATED)" - depends on PCI && SCSI && (CXL || OCXL) && EEH - select IRQ_POLL - help - The cxlflash driver is deprecated and will be removed in a future - kernel release. - - Allows CAPI Accelerated IO to Flash - If unsure, say N. diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile deleted file mode 100644 index fd2f0dd9daf9..000000000000 --- a/drivers/scsi/cxlflash/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CXLFLASH) += cxlflash.o -cxlflash-y += main.o superpipe.o lunmgt.o vlun.o -cxlflash-$(CONFIG_CXL) += cxl_hw.o -cxlflash-$(CONFIG_OCXL) += ocxl_hw.o diff --git a/drivers/scsi/cxlflash/backend.h b/drivers/scsi/cxlflash/backend.h deleted file mode 100644 index 181e0445ed42..000000000000 --- a/drivers/scsi/cxlflash/backend.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2018 IBM Corporation - */ - -#ifndef _CXLFLASH_BACKEND_H -#define _CXLFLASH_BACKEND_H - -extern const struct cxlflash_backend_ops cxlflash_cxl_ops; -extern const struct cxlflash_backend_ops cxlflash_ocxl_ops; - -struct cxlflash_backend_ops { - struct module *module; - void __iomem * (*psa_map)(void *ctx_cookie); - void (*psa_unmap)(void __iomem *addr); - int (*process_element)(void *ctx_cookie); - int (*map_afu_irq)(void *ctx_cookie, int num, irq_handler_t handler, - void *cookie, char *name); - void (*unmap_afu_irq)(void *ctx_cookie, int num, void *cookie); - u64 (*get_irq_objhndl)(void *ctx_cookie, int irq); - int (*start_context)(void *ctx_cookie); - int (*stop_context)(void *ctx_cookie); - int (*afu_reset)(void *ctx_cookie); - void (*set_master)(void *ctx_cookie); - void * (*get_context)(struct pci_dev *dev, void *afu_cookie); - void * (*dev_context_init)(struct pci_dev *dev, void *afu_cookie); - int (*release_context)(void *ctx_cookie); - void (*perst_reloads_same_image)(void *afu_cookie, bool image); - ssize_t (*read_adapter_vpd)(struct pci_dev *dev, void *buf, - size_t count); - int (*allocate_afu_irqs)(void *ctx_cookie, int num); - void (*free_afu_irqs)(void *ctx_cookie); - void * (*create_afu)(struct pci_dev *dev); - void (*destroy_afu)(void *afu_cookie); - struct file * (*get_fd)(void *ctx_cookie, struct file_operations *fops, - int *fd); - void * (*fops_get_context)(struct file *file); - int (*start_work)(void *ctx_cookie, u64 irqs); - int (*fd_mmap)(struct file *file, struct vm_area_struct *vm); - int (*fd_release)(struct inode *inode, struct file *file); -}; - -#endif /* _CXLFLASH_BACKEND_H */ diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h deleted file mode 100644 index de6229e27b48..000000000000 --- a/drivers/scsi/cxlflash/common.h +++ /dev/null @@ -1,340 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#ifndef _CXLFLASH_COMMON_H -#define _CXLFLASH_COMMON_H - -#include <linux/async.h> -#include <linux/cdev.h> -#include <linux/irq_poll.h> -#include <linux/list.h> -#include <linux/rwsem.h> -#include <linux/types.h> -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> - -#include "backend.h" - -extern const struct file_operations cxlflash_cxl_fops; - -#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ -#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* max ports per AFU */ -#define LEGACY_FC_PORTS 2 /* legacy ports per AFU */ - -#define CHAN2PORTBANK(_x) ((_x) >> ilog2(CXLFLASH_NUM_FC_PORTS_PER_BANK)) -#define CHAN2BANKPORT(_x) ((_x) & (CXLFLASH_NUM_FC_PORTS_PER_BANK - 1)) - -#define CHAN2PORTMASK(_x) (1 << (_x)) /* channel to port mask */ -#define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */ -#define PORTNUM2CHAN(_x) ((_x) - 1) /* port number to channel */ - -#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ -#define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ -#define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants - * max_sectors - * in units of - * 512 byte - * sectors - */ - -#define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry)) - -/* AFU command retry limit */ -#define MC_RETRY_CNT 5 /* Sufficient for SCSI and certain AFU errors */ - -/* Command management definitions */ -#define CXLFLASH_MAX_CMDS 256 -#define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS - -/* RRQ for master issued cmds */ -#define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS - -/* SQ for master issued cmds */ -#define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS - -/* Hardware queue definitions */ -#define CXLFLASH_DEF_HWQS 1 -#define CXLFLASH_MAX_HWQS 8 -#define PRIMARY_HWQ 0 - - -static inline void check_sizes(void) -{ - BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_FC_PORTS_PER_BANK); - BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_MAX_CMDS); -} - -/* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */ -#define CMD_BUFSIZE SIZE_4K - -enum cxlflash_lr_state { - LINK_RESET_INVALID, - LINK_RESET_REQUIRED, - LINK_RESET_COMPLETE -}; - -enum cxlflash_init_state { - INIT_STATE_NONE, - INIT_STATE_PCI, - INIT_STATE_AFU, - INIT_STATE_SCSI, - INIT_STATE_CDEV -}; - -enum cxlflash_state { - STATE_PROBING, /* Initial state during probe */ - STATE_PROBED, /* Temporary state, probe completed but EEH occurred */ - STATE_NORMAL, /* Normal running state, everything good */ - STATE_RESET, /* Reset state, trying to reset/recover */ - STATE_FAILTERM /* Failed/terminating state, error out users/threads */ -}; - -enum cxlflash_hwq_mode { - HWQ_MODE_RR, /* Roundrobin (default) */ - HWQ_MODE_TAG, /* Distribute based on block MQ tag */ - HWQ_MODE_CPU, /* CPU affinity */ - MAX_HWQ_MODE -}; - -/* - * Each context has its own set of resource handles that is visible - * only from that context. - */ - -struct cxlflash_cfg { - struct afu *afu; - - const struct cxlflash_backend_ops *ops; - struct pci_dev *dev; - struct pci_device_id *dev_id; - struct Scsi_Host *host; - int num_fc_ports; - struct cdev cdev; - struct device *chardev; - - ulong cxlflash_regs_pci; - - struct work_struct work_q; - enum cxlflash_init_state init_state; - enum cxlflash_lr_state lr_state; - int lr_port; - atomic_t scan_host_needed; - - void *afu_cookie; - - atomic_t recovery_threads; - struct mutex ctx_recovery_mutex; - struct mutex ctx_tbl_list_mutex; - struct rw_semaphore ioctl_rwsem; - struct ctx_info *ctx_tbl[MAX_CONTEXT]; - struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ - struct file_operations cxl_fops; - - /* Parameters that are LUN table related */ - int last_lun_index[MAX_FC_PORTS]; - int promote_lun_index; - struct list_head lluns; /* list of llun_info structs */ - - wait_queue_head_t tmf_waitq; - spinlock_t tmf_slock; - bool tmf_active; - bool ws_unmap; /* Write-same unmap supported */ - wait_queue_head_t reset_waitq; - enum cxlflash_state state; - async_cookie_t async_reset_cookie; -}; - -struct afu_cmd { - struct sisl_ioarcb rcb; /* IOARCB (cache line aligned) */ - struct sisl_ioasa sa; /* IOASA must follow IOARCB */ - struct afu *parent; - struct scsi_cmnd *scp; - struct completion cevent; - struct list_head queue; - u32 hwq_index; - - u8 cmd_tmf:1, - cmd_aborted:1; - - struct list_head list; /* Pending commands link */ - - /* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned. - * However for performance reasons the IOARCB/IOASA should be - * cache line aligned. - */ -} __aligned(cache_line_size()); - -static inline struct afu_cmd *sc_to_afuc(struct scsi_cmnd *sc) -{ - return PTR_ALIGN(scsi_cmd_priv(sc), __alignof__(struct afu_cmd)); -} - -static inline struct afu_cmd *sc_to_afuci(struct scsi_cmnd *sc) -{ - struct afu_cmd *afuc = sc_to_afuc(sc); - - INIT_LIST_HEAD(&afuc->queue); - return afuc; -} - -static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc) -{ - struct afu_cmd *afuc = sc_to_afuc(sc); - - memset(afuc, 0, sizeof(*afuc)); - return sc_to_afuci(sc); -} - -struct hwq { - /* Stuff requiring alignment go first. */ - struct sisl_ioarcb sq[NUM_SQ_ENTRY]; /* 16K SQ */ - u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ - - /* Beware of alignment till here. Preferably introduce new - * fields after this point - */ - struct afu *afu; - void *ctx_cookie; - struct sisl_host_map __iomem *host_map; /* MC host map */ - struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ - ctx_hndl_t ctx_hndl; /* master's context handle */ - u32 index; /* Index of this hwq */ - int num_irqs; /* Number of interrupts requested for context */ - struct list_head pending_cmds; /* Commands pending completion */ - - atomic_t hsq_credits; - spinlock_t hsq_slock; /* Hardware send queue lock */ - struct sisl_ioarcb *hsq_start; - struct sisl_ioarcb *hsq_end; - struct sisl_ioarcb *hsq_curr; - spinlock_t hrrq_slock; - u64 *hrrq_start; - u64 *hrrq_end; - u64 *hrrq_curr; - bool toggle; - bool hrrq_online; - - s64 room; - - struct irq_poll irqpoll; -} __aligned(cache_line_size()); - -struct afu { - struct hwq hwqs[CXLFLASH_MAX_HWQS]; - int (*send_cmd)(struct afu *afu, struct afu_cmd *cmd); - int (*context_reset)(struct hwq *hwq); - - /* AFU HW */ - struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ - - atomic_t cmds_active; /* Number of currently active AFU commands */ - struct mutex sync_active; /* Mutex to serialize AFU commands */ - u64 hb; - u32 internal_lun; /* User-desired LUN mode for this AFU */ - - u32 num_hwqs; /* Number of hardware queues */ - u32 desired_hwqs; /* Desired h/w queues, effective on AFU reset */ - enum cxlflash_hwq_mode hwq_mode; /* Steering mode for h/w queues */ - u32 hwq_rr_count; /* Count to distribute traffic for roundrobin */ - - char version[16]; - u64 interface_version; - - u32 irqpoll_weight; - struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ -}; - -static inline struct hwq *get_hwq(struct afu *afu, u32 index) -{ - WARN_ON(index >= CXLFLASH_MAX_HWQS); - - return &afu->hwqs[index]; -} - -static inline bool afu_is_irqpoll_enabled(struct afu *afu) -{ - return !!afu->irqpoll_weight; -} - -static inline bool afu_has_cap(struct afu *afu, u64 cap) -{ - u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT; - - return afu_cap & cap; -} - -static inline bool afu_is_ocxl_lisn(struct afu *afu) -{ - return afu_has_cap(afu, SISL_INTVER_CAP_OCXL_LISN); -} - -static inline bool afu_is_afu_debug(struct afu *afu) -{ - return afu_has_cap(afu, SISL_INTVER_CAP_AFU_DEBUG); -} - -static inline bool afu_is_lun_provision(struct afu *afu) -{ - return afu_has_cap(afu, SISL_INTVER_CAP_LUN_PROVISION); -} - -static inline bool afu_is_sq_cmd_mode(struct afu *afu) -{ - return afu_has_cap(afu, SISL_INTVER_CAP_SQ_CMD_MODE); -} - -static inline bool afu_is_ioarrin_cmd_mode(struct afu *afu) -{ - return afu_has_cap(afu, SISL_INTVER_CAP_IOARRIN_CMD_MODE); -} - -static inline u64 lun_to_lunid(u64 lun) -{ - __be64 lun_id; - - int_to_scsilun(lun, (struct scsi_lun *)&lun_id); - return be64_to_cpu(lun_id); -} - -static inline struct fc_port_bank __iomem *get_fc_port_bank( - struct cxlflash_cfg *cfg, int i) -{ - struct afu *afu = cfg->afu; - - return &afu->afu_map->global.bank[CHAN2PORTBANK(i)]; -} - -static inline __be64 __iomem *get_fc_port_regs(struct cxlflash_cfg *cfg, int i) -{ - struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); - - return &fcpb->fc_port_regs[CHAN2BANKPORT(i)][0]; -} - -static inline __be64 __iomem *get_fc_port_luns(struct cxlflash_cfg *cfg, int i) -{ - struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); - - return &fcpb->fc_port_luns[CHAN2BANKPORT(i)][0]; -} - -int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t c, res_hndl_t r, u8 mode); -void cxlflash_list_init(void); -void cxlflash_term_global_luns(void); -void cxlflash_free_errpage(void); -int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, - void __user *arg); -void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg); -int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg); -void cxlflash_term_local_luns(struct cxlflash_cfg *cfg); -void cxlflash_restore_luntable(struct cxlflash_cfg *cfg); - -#endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/cxl_hw.c b/drivers/scsi/cxlflash/cxl_hw.c deleted file mode 100644 index b814130f3f5c..000000000000 --- a/drivers/scsi/cxlflash/cxl_hw.c +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2018 IBM Corporation - */ - -#include <misc/cxl.h> - -#include "backend.h" - -/* - * The following routines map the cxlflash backend operations to existing CXL - * kernel API function and are largely simple shims that provide an abstraction - * for converting generic context and AFU cookies into cxl_context or cxl_afu - * pointers. - */ - -static void __iomem *cxlflash_psa_map(void *ctx_cookie) -{ - return cxl_psa_map(ctx_cookie); -} - -static void cxlflash_psa_unmap(void __iomem *addr) -{ - cxl_psa_unmap(addr); -} - -static int cxlflash_process_element(void *ctx_cookie) -{ - return cxl_process_element(ctx_cookie); -} - -static int cxlflash_map_afu_irq(void *ctx_cookie, int num, - irq_handler_t handler, void *cookie, char *name) -{ - return cxl_map_afu_irq(ctx_cookie, num, handler, cookie, name); -} - -static void cxlflash_unmap_afu_irq(void *ctx_cookie, int num, void *cookie) -{ - cxl_unmap_afu_irq(ctx_cookie, num, cookie); -} - -static u64 cxlflash_get_irq_objhndl(void *ctx_cookie, int irq) -{ - /* Dummy fop for cxl */ - return 0; -} - -static int cxlflash_start_context(void *ctx_cookie) -{ - return cxl_start_context(ctx_cookie, 0, NULL); -} - -static int cxlflash_stop_context(void *ctx_cookie) -{ - return cxl_stop_context(ctx_cookie); -} - -static int cxlflash_afu_reset(void *ctx_cookie) -{ - return cxl_afu_reset(ctx_cookie); -} - -static void cxlflash_set_master(void *ctx_cookie) -{ - cxl_set_master(ctx_cookie); -} - -static void *cxlflash_get_context(struct pci_dev *dev, void *afu_cookie) -{ - return cxl_get_context(dev); -} - -static void *cxlflash_dev_context_init(struct pci_dev *dev, void *afu_cookie) -{ - return cxl_dev_context_init(dev); -} - -static int cxlflash_release_context(void *ctx_cookie) -{ - return cxl_release_context(ctx_cookie); -} - -static void cxlflash_perst_reloads_same_image(void *afu_cookie, bool image) -{ - cxl_perst_reloads_same_image(afu_cookie, image); -} - -static ssize_t cxlflash_read_adapter_vpd(struct pci_dev *dev, - void *buf, size_t count) -{ - return cxl_read_adapter_vpd(dev, buf, count); -} - -static int cxlflash_allocate_afu_irqs(void *ctx_cookie, int num) -{ - return cxl_allocate_afu_irqs(ctx_cookie, num); -} - -static void cxlflash_free_afu_irqs(void *ctx_cookie) -{ - cxl_free_afu_irqs(ctx_cookie); -} - -static void *cxlflash_create_afu(struct pci_dev *dev) -{ - return cxl_pci_to_afu(dev); -} - -static void cxlflash_destroy_afu(void *afu) -{ - /* Dummy fop for cxl */ -} - -static struct file *cxlflash_get_fd(void *ctx_cookie, - struct file_operations *fops, int *fd) -{ - return cxl_get_fd(ctx_cookie, fops, fd); -} - -static void *cxlflash_fops_get_context(struct file *file) -{ - return cxl_fops_get_context(file); -} - -static int cxlflash_start_work(void *ctx_cookie, u64 irqs) -{ - struct cxl_ioctl_start_work work = { 0 }; - - work.num_interrupts = irqs; - work.flags = CXL_START_WORK_NUM_IRQS; - - return cxl_start_work(ctx_cookie, &work); -} - -static int cxlflash_fd_mmap(struct file *file, struct vm_area_struct *vm) -{ - return cxl_fd_mmap(file, vm); -} - -static int cxlflash_fd_release(struct inode *inode, struct file *file) -{ - return cxl_fd_release(inode, file); -} - -const struct cxlflash_backend_ops cxlflash_cxl_ops = { - .module = THIS_MODULE, - .psa_map = cxlflash_psa_map, - .psa_unmap = cxlflash_psa_unmap, - .process_element = cxlflash_process_element, - .map_afu_irq = cxlflash_map_afu_irq, - .unmap_afu_irq = cxlflash_unmap_afu_irq, - .get_irq_objhndl = cxlflash_get_irq_objhndl, - .start_context = cxlflash_start_context, - .stop_context = cxlflash_stop_context, - .afu_reset = cxlflash_afu_reset, - .set_master = cxlflash_set_master, - .get_context = cxlflash_get_context, - .dev_context_init = cxlflash_dev_context_init, - .release_context = cxlflash_release_context, - .perst_reloads_same_image = cxlflash_perst_reloads_same_image, - .read_adapter_vpd = cxlflash_read_adapter_vpd, - .allocate_afu_irqs = cxlflash_allocate_afu_irqs, - .free_afu_irqs = cxlflash_free_afu_irqs, - .create_afu = cxlflash_create_afu, - .destroy_afu = cxlflash_destroy_afu, - .get_fd = cxlflash_get_fd, - .fops_get_context = cxlflash_fops_get_context, - .start_work = cxlflash_start_work, - .fd_mmap = cxlflash_fd_mmap, - .fd_release = cxlflash_fd_release, -}; diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c deleted file mode 100644 index 962c797fda07..000000000000 --- a/drivers/scsi/cxlflash/lunmgt.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#include <linux/unaligned.h> - -#include <linux/interrupt.h> -#include <linux/pci.h> - -#include <scsi/scsi_host.h> -#include <uapi/scsi/cxlflash_ioctl.h> - -#include "sislite.h" -#include "common.h" -#include "vlun.h" -#include "superpipe.h" - -/** - * create_local() - allocate and initialize a local LUN information structure - * @sdev: SCSI device associated with LUN. - * @wwid: World Wide Node Name for LUN. - * - * Return: Allocated local llun_info structure on success, NULL on failure - */ -static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = NULL; - - lli = kzalloc(sizeof(*lli), GFP_KERNEL); - if (unlikely(!lli)) { - dev_err(dev, "%s: could not allocate lli\n", __func__); - goto out; - } - - lli->sdev = sdev; - lli->host_no = sdev->host->host_no; - lli->in_table = false; - - memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); -out: - return lli; -} - -/** - * create_global() - allocate and initialize a global LUN information structure - * @sdev: SCSI device associated with LUN. - * @wwid: World Wide Node Name for LUN. - * - * Return: Allocated global glun_info structure on success, NULL on failure - */ -static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct glun_info *gli = NULL; - - gli = kzalloc(sizeof(*gli), GFP_KERNEL); - if (unlikely(!gli)) { - dev_err(dev, "%s: could not allocate gli\n", __func__); - goto out; - } - - mutex_init(&gli->mutex); - memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); -out: - return gli; -} - -/** - * lookup_local() - find a local LUN information structure by WWID - * @cfg: Internal structure associated with the host. - * @wwid: WWID associated with LUN. - * - * Return: Found local lun_info structure on success, NULL on failure - */ -static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid) -{ - struct llun_info *lli, *temp; - - list_for_each_entry_safe(lli, temp, &cfg->lluns, list) - if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) - return lli; - - return NULL; -} - -/** - * lookup_global() - find a global LUN information structure by WWID - * @wwid: WWID associated with LUN. - * - * Return: Found global lun_info structure on success, NULL on failure - */ -static struct glun_info *lookup_global(u8 *wwid) -{ - struct glun_info *gli, *temp; - - list_for_each_entry_safe(gli, temp, &global.gluns, list) - if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) - return gli; - - return NULL; -} - -/** - * find_and_create_lun() - find or create a local LUN information structure - * @sdev: SCSI device associated with LUN. - * @wwid: WWID associated with LUN. - * - * The LUN is kept both in a local list (per adapter) and in a global list - * (across all adapters). Certain attributes of the LUN are local to the - * adapter (such as index, port selection mask, etc.). - * - * The block allocation map is shared across all adapters (i.e. associated - * wih the global list). Since different attributes are associated with - * the per adapter and global entries, allocate two separate structures for each - * LUN (one local, one global). - * - * Keep a pointer back from the local to the global entry. - * - * This routine assumes the caller holds the global mutex. - * - * Return: Found/Allocated local lun_info structure on success, NULL on failure - */ -static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = NULL; - struct glun_info *gli = NULL; - - if (unlikely(!wwid)) - goto out; - - lli = lookup_local(cfg, wwid); - if (lli) - goto out; - - lli = create_local(sdev, wwid); - if (unlikely(!lli)) - goto out; - - gli = lookup_global(wwid); - if (gli) { - lli->parent = gli; - list_add(&lli->list, &cfg->lluns); - goto out; - } - - gli = create_global(sdev, wwid); - if (unlikely(!gli)) { - kfree(lli); - lli = NULL; - goto out; - } - - lli->parent = gli; - list_add(&lli->list, &cfg->lluns); - - list_add(&gli->list, &global.gluns); - -out: - dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli); - return lli; -} - -/** - * cxlflash_term_local_luns() - Delete all entries from local LUN list, free. - * @cfg: Internal structure associated with the host. - */ -void cxlflash_term_local_luns(struct cxlflash_cfg *cfg) -{ - struct llun_info *lli, *temp; - - mutex_lock(&global.mutex); - list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { - list_del(&lli->list); - kfree(lli); - } - mutex_unlock(&global.mutex); -} - -/** - * cxlflash_list_init() - initializes the global LUN list - */ -void cxlflash_list_init(void) -{ - INIT_LIST_HEAD(&global.gluns); - mutex_init(&global.mutex); - global.err_page = NULL; -} - -/** - * cxlflash_term_global_luns() - frees resources associated with global LUN list - */ -void cxlflash_term_global_luns(void) -{ - struct glun_info *gli, *temp; - - mutex_lock(&global.mutex); - list_for_each_entry_safe(gli, temp, &global.gluns, list) { - list_del(&gli->list); - cxlflash_ba_terminate(&gli->blka.ba_lun); - kfree(gli); - } - mutex_unlock(&global.mutex); -} - -/** - * cxlflash_manage_lun() - handles LUN management activities - * @sdev: SCSI device associated with LUN. - * @arg: Manage ioctl data structure. - * - * This routine is used to notify the driver about a LUN's WWID and associate - * SCSI devices (sdev) with a global LUN instance. Additionally it serves to - * change a LUN's operating mode: legacy or superpipe. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_manage_lun(struct scsi_device *sdev, void *arg) -{ - struct dk_cxlflash_manage_lun *manage = arg; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = NULL; - int rc = 0; - u64 flags = manage->hdr.flags; - u32 chan = sdev->channel; - - mutex_lock(&global.mutex); - lli = find_and_create_lun(sdev, manage->wwid); - dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n", - __func__, get_unaligned_be64(&manage->wwid[0]), - get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); - if (unlikely(!lli)) { - rc = -ENOMEM; - goto out; - } - - if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { - /* - * Update port selection mask based upon channel, store off LUN - * in unpacked, AFU-friendly format, and hang LUN reference in - * the sdev. - */ - lli->port_sel |= CHAN2PORTMASK(chan); - lli->lun_id[chan] = lun_to_lunid(sdev->lun); - sdev->hostdata = lli; - } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { - if (lli->parent->mode != MODE_NONE) - rc = -EBUSY; - else { - /* - * Clean up local LUN for this port and reset table - * tracking when no more references exist. - */ - sdev->hostdata = NULL; - lli->port_sel &= ~CHAN2PORTMASK(chan); - if (lli->port_sel == 0U) - lli->in_table = false; - } - } - - dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n", - __func__, lli->port_sel, chan, lli->lun_id[chan]); - -out: - mutex_unlock(&global.mutex); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c deleted file mode 100644 index ae626e389c8b..000000000000 --- a/drivers/scsi/cxlflash/main.c +++ /dev/null @@ -1,3970 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#include <linux/delay.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/pci.h> - -#include <linux/unaligned.h> - -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_host.h> -#include <uapi/scsi/cxlflash_ioctl.h> - -#include "main.h" -#include "sislite.h" -#include "common.h" - -MODULE_DESCRIPTION(CXLFLASH_ADAPTER_NAME); -MODULE_AUTHOR("Manoj N. Kumar <manoj@linux.vnet.ibm.com>"); -MODULE_AUTHOR("Matthew R. Ochs <mrochs@linux.vnet.ibm.com>"); -MODULE_LICENSE("GPL"); - -static char *cxlflash_devnode(const struct device *dev, umode_t *mode); -static const struct class cxlflash_class = { - .name = "cxlflash", - .devnode = cxlflash_devnode, -}; - -static u32 cxlflash_major; -static DECLARE_BITMAP(cxlflash_minor, CXLFLASH_MAX_ADAPTERS); - -/** - * process_cmd_err() - command error handler - * @cmd: AFU command that experienced the error. - * @scp: SCSI command associated with the AFU command in error. - * - * Translates error bits from AFU command to SCSI command results. - */ -static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) -{ - struct afu *afu = cmd->parent; - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct sisl_ioasa *ioasa; - u32 resid; - - ioasa = &(cmd->sa); - - if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { - resid = ioasa->resid; - scsi_set_resid(scp, resid); - dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n", - __func__, cmd, scp, resid); - } - - if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { - dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n", - __func__, cmd, scp); - scp->result = (DID_ERROR << 16); - } - - dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x " - "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__, - ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, - ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); - - if (ioasa->rc.scsi_rc) { - /* We have a SCSI status */ - if (ioasa->rc.flags & SISL_RC_FLAGS_SENSE_VALID) { - memcpy(scp->sense_buffer, ioasa->sense_data, - SISL_SENSE_DATA_LEN); - scp->result = ioasa->rc.scsi_rc; - } else - scp->result = ioasa->rc.scsi_rc | (DID_ERROR << 16); - } - - /* - * We encountered an error. Set scp->result based on nature - * of error. - */ - if (ioasa->rc.fc_rc) { - /* We have an FC status */ - switch (ioasa->rc.fc_rc) { - case SISL_FC_RC_LINKDOWN: - scp->result = (DID_REQUEUE << 16); - break; - case SISL_FC_RC_RESID: - /* This indicates an FCP resid underrun */ - if (!(ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN)) { - /* If the SISL_RC_FLAGS_OVERRUN flag was set, - * then we will handle this error else where. - * If not then we must handle it here. - * This is probably an AFU bug. - */ - scp->result = (DID_ERROR << 16); - } - break; - case SISL_FC_RC_RESIDERR: - /* Resid mismatch between adapter and device */ - case SISL_FC_RC_TGTABORT: - case SISL_FC_RC_ABORTOK: - case SISL_FC_RC_ABORTFAIL: - case SISL_FC_RC_NOLOGI: - case SISL_FC_RC_ABORTPEND: - case SISL_FC_RC_WRABORTPEND: - case SISL_FC_RC_NOEXP: - case SISL_FC_RC_INUSE: - scp->result = (DID_ERROR << 16); - break; - } - } - - if (ioasa->rc.afu_rc) { - /* We have an AFU error */ - switch (ioasa->rc.afu_rc) { - case SISL_AFU_RC_NO_CHANNELS: - scp->result = (DID_NO_CONNECT << 16); - break; - case SISL_AFU_RC_DATA_DMA_ERR: - switch (ioasa->afu_extra) { - case SISL_AFU_DMA_ERR_PAGE_IN: - /* Retry */ - scp->result = (DID_IMM_RETRY << 16); - break; - case SISL_AFU_DMA_ERR_INVALID_EA: - default: - scp->result = (DID_ERROR << 16); - } - break; - case SISL_AFU_RC_OUT_OF_DATA_BUFS: - /* Retry */ - scp->result = (DID_ERROR << 16); - break; - default: - scp->result = (DID_ERROR << 16); - } - } -} - -/** - * cmd_complete() - command completion handler - * @cmd: AFU command that has completed. - * - * For SCSI commands this routine prepares and submits commands that have - * either completed or timed out to the SCSI stack. For internal commands - * (TMF or AFU), this routine simply notifies the originator that the - * command has completed. - */ -static void cmd_complete(struct afu_cmd *cmd) -{ - struct scsi_cmnd *scp; - ulong lock_flags; - struct afu *afu = cmd->parent; - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - list_del(&cmd->list); - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); - - if (cmd->scp) { - scp = cmd->scp; - if (unlikely(cmd->sa.ioasc)) - process_cmd_err(cmd, scp); - else - scp->result = (DID_OK << 16); - - dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n", - __func__, scp, scp->result, cmd->sa.ioasc); - scsi_done(scp); - } else if (cmd->cmd_tmf) { - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - cfg->tmf_active = false; - wake_up_all_locked(&cfg->tmf_waitq); - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - } else - complete(&cmd->cevent); -} - -/** - * flush_pending_cmds() - flush all pending commands on this hardware queue - * @hwq: Hardware queue to flush. - * - * The hardware send queue lock associated with this hardware queue must be - * held when calling this routine. - */ -static void flush_pending_cmds(struct hwq *hwq) -{ - struct cxlflash_cfg *cfg = hwq->afu->parent; - struct afu_cmd *cmd, *tmp; - struct scsi_cmnd *scp; - ulong lock_flags; - - list_for_each_entry_safe(cmd, tmp, &hwq->pending_cmds, list) { - /* Bypass command when on a doneq, cmd_complete() will handle */ - if (!list_empty(&cmd->queue)) - continue; - - list_del(&cmd->list); - - if (cmd->scp) { - scp = cmd->scp; - scp->result = (DID_IMM_RETRY << 16); - scsi_done(scp); - } else { - cmd->cmd_aborted = true; - - if (cmd->cmd_tmf) { - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - cfg->tmf_active = false; - wake_up_all_locked(&cfg->tmf_waitq); - spin_unlock_irqrestore(&cfg->tmf_slock, - lock_flags); - } else - complete(&cmd->cevent); - } - } -} - -/** - * context_reset() - reset context via specified register - * @hwq: Hardware queue owning the context to be reset. - * @reset_reg: MMIO register to perform reset. - * - * When the reset is successful, the SISLite specification guarantees that - * the AFU has aborted all currently pending I/O. Accordingly, these commands - * must be flushed. - * - * Return: 0 on success, -errno on failure - */ -static int context_reset(struct hwq *hwq, __be64 __iomem *reset_reg) -{ - struct cxlflash_cfg *cfg = hwq->afu->parent; - struct device *dev = &cfg->dev->dev; - int rc = -ETIMEDOUT; - int nretry = 0; - u64 val = 0x1; - ulong lock_flags; - - dev_dbg(dev, "%s: hwq=%p\n", __func__, hwq); - - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - - writeq_be(val, reset_reg); - do { - val = readq_be(reset_reg); - if ((val & 0x1) == 0x0) { - rc = 0; - break; - } - - /* Double delay each time */ - udelay(1 << nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); - - if (!rc) - flush_pending_cmds(hwq); - - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); - - dev_dbg(dev, "%s: returning rc=%d, val=%016llx nretry=%d\n", - __func__, rc, val, nretry); - return rc; -} - -/** - * context_reset_ioarrin() - reset context via IOARRIN register - * @hwq: Hardware queue owning the context to be reset. - * - * Return: 0 on success, -errno on failure - */ -static int context_reset_ioarrin(struct hwq *hwq) -{ - return context_reset(hwq, &hwq->host_map->ioarrin); -} - -/** - * context_reset_sq() - reset context via SQ_CONTEXT_RESET register - * @hwq: Hardware queue owning the context to be reset. - * - * Return: 0 on success, -errno on failure - */ -static int context_reset_sq(struct hwq *hwq) -{ - return context_reset(hwq, &hwq->host_map->sq_ctx_reset); -} - -/** - * send_cmd_ioarrin() - sends an AFU command via IOARRIN register - * @afu: AFU associated with the host. - * @cmd: AFU command to send. - * - * Return: - * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure - */ -static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - int rc = 0; - s64 room; - ulong lock_flags; - - /* - * To avoid the performance penalty of MMIO, spread the update of - * 'room' over multiple commands. - */ - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - if (--hwq->room < 0) { - room = readq_be(&hwq->host_map->cmd_room); - if (room <= 0) { - dev_dbg_ratelimited(dev, "%s: no cmd_room to send " - "0x%02X, room=0x%016llX\n", - __func__, cmd->rcb.cdb[0], room); - hwq->room = 0; - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - hwq->room = room - 1; - } - - list_add(&cmd->list, &hwq->pending_cmds); - writeq_be((u64)&cmd->rcb, &hwq->host_map->ioarrin); -out: - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); - dev_dbg_ratelimited(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", - __func__, cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc); - return rc; -} - -/** - * send_cmd_sq() - sends an AFU command via SQ ring - * @afu: AFU associated with the host. - * @cmd: AFU command to send. - * - * Return: - * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure - */ -static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - int rc = 0; - int newval; - ulong lock_flags; - - newval = atomic_dec_if_positive(&hwq->hsq_credits); - if (newval <= 0) { - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - cmd->rcb.ioasa = &cmd->sa; - - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - - *hwq->hsq_curr = cmd->rcb; - if (hwq->hsq_curr < hwq->hsq_end) - hwq->hsq_curr++; - else - hwq->hsq_curr = hwq->hsq_start; - - list_add(&cmd->list, &hwq->pending_cmds); - writeq_be((u64)hwq->hsq_curr, &hwq->host_map->sq_tail); - - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); -out: - dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p " - "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len, - cmd->rcb.data_ea, cmd->rcb.ioasa, rc, hwq->hsq_curr, - readq_be(&hwq->host_map->sq_head), - readq_be(&hwq->host_map->sq_tail)); - return rc; -} - -/** - * wait_resp() - polls for a response or timeout to a sent AFU command - * @afu: AFU associated with the host. - * @cmd: AFU command that was sent. - * - * Return: 0 on success, -errno on failure - */ -static int wait_resp(struct afu *afu, struct afu_cmd *cmd) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - int rc = 0; - ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); - - timeout = wait_for_completion_timeout(&cmd->cevent, timeout); - if (!timeout) - rc = -ETIMEDOUT; - - if (cmd->cmd_aborted) - rc = -EAGAIN; - - if (unlikely(cmd->sa.ioasc != 0)) { - dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n", - __func__, cmd->rcb.cdb[0], cmd->sa.ioasc); - rc = -EIO; - } - - return rc; -} - -/** - * cmd_to_target_hwq() - selects a target hardware queue for a SCSI command - * @host: SCSI host associated with device. - * @scp: SCSI command to send. - * @afu: SCSI command to send. - * - * Hashes a command based upon the hardware queue mode. - * - * Return: Trusted index of target hardware queue - */ -static u32 cmd_to_target_hwq(struct Scsi_Host *host, struct scsi_cmnd *scp, - struct afu *afu) -{ - u32 tag; - u32 hwq = 0; - - if (afu->num_hwqs == 1) - return 0; - - switch (afu->hwq_mode) { - case HWQ_MODE_RR: - hwq = afu->hwq_rr_count++ % afu->num_hwqs; - break; - case HWQ_MODE_TAG: - tag = blk_mq_unique_tag(scsi_cmd_to_rq(scp)); - hwq = blk_mq_unique_tag_to_hwq(tag); - break; - case HWQ_MODE_CPU: - hwq = smp_processor_id() % afu->num_hwqs; - break; - default: - WARN_ON_ONCE(1); - } - - return hwq; -} - -/** - * send_tmf() - sends a Task Management Function (TMF) - * @cfg: Internal structure associated with the host. - * @sdev: SCSI device destined for TMF. - * @tmfcmd: TMF command to send. - * - * Return: - * 0 on success, SCSI_MLQUEUE_HOST_BUSY or -errno on failure - */ -static int send_tmf(struct cxlflash_cfg *cfg, struct scsi_device *sdev, - u64 tmfcmd) -{ - struct afu *afu = cfg->afu; - struct afu_cmd *cmd = NULL; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); - bool needs_deletion = false; - char *buf = NULL; - ulong lock_flags; - int rc = 0; - ulong to; - - buf = kzalloc(sizeof(*cmd) + __alignof__(*cmd) - 1, GFP_KERNEL); - if (unlikely(!buf)) { - dev_err(dev, "%s: no memory for command\n", __func__); - rc = -ENOMEM; - goto out; - } - - cmd = (struct afu_cmd *)PTR_ALIGN(buf, __alignof__(*cmd)); - INIT_LIST_HEAD(&cmd->queue); - - /* When Task Management Function is active do not send another */ - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - if (cfg->tmf_active) - wait_event_interruptible_lock_irq(cfg->tmf_waitq, - !cfg->tmf_active, - cfg->tmf_slock); - cfg->tmf_active = true; - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - - cmd->parent = afu; - cmd->cmd_tmf = true; - cmd->hwq_index = hwq->index; - - cmd->rcb.ctx_id = hwq->ctx_hndl; - cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; - cmd->rcb.port_sel = CHAN2PORTMASK(sdev->channel); - cmd->rcb.lun_id = lun_to_lunid(sdev->lun); - cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID | - SISL_REQ_FLAGS_SUP_UNDERRUN | - SISL_REQ_FLAGS_TMF_CMD); - memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd)); - - rc = afu->send_cmd(afu, cmd); - if (unlikely(rc)) { - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - cfg->tmf_active = false; - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - goto out; - } - - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - to = msecs_to_jiffies(5000); - to = wait_event_interruptible_lock_irq_timeout(cfg->tmf_waitq, - !cfg->tmf_active, - cfg->tmf_slock, - to); - if (!to) { - dev_err(dev, "%s: TMF timed out\n", __func__); - rc = -ETIMEDOUT; - needs_deletion = true; - } else if (cmd->cmd_aborted) { - dev_err(dev, "%s: TMF aborted\n", __func__); - rc = -EAGAIN; - } else if (cmd->sa.ioasc) { - dev_err(dev, "%s: TMF failed ioasc=%08x\n", - __func__, cmd->sa.ioasc); - rc = -EIO; - } - cfg->tmf_active = false; - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - - if (needs_deletion) { - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - list_del(&cmd->list); - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); - } -out: - kfree(buf); - return rc; -} - -/** - * cxlflash_driver_info() - information handler for this host driver - * @host: SCSI host associated with device. - * - * Return: A string describing the device. - */ -static const char *cxlflash_driver_info(struct Scsi_Host *host) -{ - return CXLFLASH_ADAPTER_NAME; -} - -/** - * cxlflash_queuecommand() - sends a mid-layer request - * @host: SCSI host associated with device. - * @scp: SCSI command to send. - * - * Return: 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure - */ -static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) -{ - struct cxlflash_cfg *cfg = shost_priv(host); - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct afu_cmd *cmd = sc_to_afuci(scp); - struct scatterlist *sg = scsi_sglist(scp); - int hwq_index = cmd_to_target_hwq(host, scp, afu); - struct hwq *hwq = get_hwq(afu, hwq_index); - u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; - ulong lock_flags; - int rc = 0; - - dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08x-%08x-%08x-%08x)\n", - __func__, scp, host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - - /* - * If a Task Management Function is active, wait for it to complete - * before continuing with regular commands. - */ - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - if (cfg->tmf_active) { - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - - switch (cfg->state) { - case STATE_PROBING: - case STATE_PROBED: - case STATE_RESET: - dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - case STATE_FAILTERM: - dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__); - scp->result = (DID_NO_CONNECT << 16); - scsi_done(scp); - rc = 0; - goto out; - default: - atomic_inc(&afu->cmds_active); - break; - } - - if (likely(sg)) { - cmd->rcb.data_len = sg->length; - cmd->rcb.data_ea = (uintptr_t)sg_virt(sg); - } - - cmd->scp = scp; - cmd->parent = afu; - cmd->hwq_index = hwq_index; - - cmd->sa.ioasc = 0; - cmd->rcb.ctx_id = hwq->ctx_hndl; - cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; - cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); - cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); - - if (scp->sc_data_direction == DMA_TO_DEVICE) - req_flags |= SISL_REQ_FLAGS_HOST_WRITE; - - cmd->rcb.req_flags = req_flags; - memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); - - rc = afu->send_cmd(afu, cmd); - atomic_dec(&afu->cmds_active); -out: - return rc; -} - -/** - * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe - * @cfg: Internal structure associated with the host. - */ -static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) -{ - struct pci_dev *pdev = cfg->dev; - - if (pci_channel_offline(pdev)) - wait_event_timeout(cfg->reset_waitq, - !pci_channel_offline(pdev), - CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); -} - -/** - * free_mem() - free memory associated with the AFU - * @cfg: Internal structure associated with the host. - */ -static void free_mem(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - - if (cfg->afu) { - free_pages((ulong)afu, get_order(sizeof(struct afu))); - cfg->afu = NULL; - } -} - -/** - * cxlflash_reset_sync() - synchronizing point for asynchronous resets - * @cfg: Internal structure associated with the host. - */ -static void cxlflash_reset_sync(struct cxlflash_cfg *cfg) -{ - if (cfg->async_reset_cookie == 0) - return; - - /* Wait until all async calls prior to this cookie have completed */ - async_synchronize_cookie(cfg->async_reset_cookie + 1); - cfg->async_reset_cookie = 0; -} - -/** - * stop_afu() - stops the AFU command timers and unmaps the MMIO space - * @cfg: Internal structure associated with the host. - * - * Safe to call with AFU in a partially allocated/initialized state. - * - * Cancels scheduled worker threads, waits for any active internal AFU - * commands to timeout, disables IRQ polling and then unmaps the MMIO space. - */ -static void stop_afu(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct hwq *hwq; - int i; - - cancel_work_sync(&cfg->work_q); - if (!current_is_async()) - cxlflash_reset_sync(cfg); - - if (likely(afu)) { - while (atomic_read(&afu->cmds_active)) - ssleep(1); - - if (afu_is_irqpoll_enabled(afu)) { - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - irq_poll_disable(&hwq->irqpoll); - } - } - - if (likely(afu->afu_map)) { - cfg->ops->psa_unmap(afu->afu_map); - afu->afu_map = NULL; - } - } -} - -/** - * term_intr() - disables all AFU interrupts - * @cfg: Internal structure associated with the host. - * @level: Depth of allocation, where to begin waterfall tear down. - * @index: Index of the hardware queue. - * - * Safe to call with AFU/MC in partially allocated/initialized state. - */ -static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level, - u32 index) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq; - - if (!afu) { - dev_err(dev, "%s: returning with NULL afu\n", __func__); - return; - } - - hwq = get_hwq(afu, index); - - if (!hwq->ctx_cookie) { - dev_err(dev, "%s: returning with NULL MC\n", __func__); - return; - } - - switch (level) { - case UNMAP_THREE: - /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ - if (index == PRIMARY_HWQ) - cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 3, hwq); - fallthrough; - case UNMAP_TWO: - cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 2, hwq); - fallthrough; - case UNMAP_ONE: - cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 1, hwq); - fallthrough; - case FREE_IRQ: - cfg->ops->free_afu_irqs(hwq->ctx_cookie); - fallthrough; - case UNDO_NOOP: - /* No action required */ - break; - } -} - -/** - * term_mc() - terminates the master context - * @cfg: Internal structure associated with the host. - * @index: Index of the hardware queue. - * - * Safe to call with AFU/MC in partially allocated/initialized state. - */ -static void term_mc(struct cxlflash_cfg *cfg, u32 index) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq; - ulong lock_flags; - - if (!afu) { - dev_err(dev, "%s: returning with NULL afu\n", __func__); - return; - } - - hwq = get_hwq(afu, index); - - if (!hwq->ctx_cookie) { - dev_err(dev, "%s: returning with NULL MC\n", __func__); - return; - } - - WARN_ON(cfg->ops->stop_context(hwq->ctx_cookie)); - if (index != PRIMARY_HWQ) - WARN_ON(cfg->ops->release_context(hwq->ctx_cookie)); - hwq->ctx_cookie = NULL; - - spin_lock_irqsave(&hwq->hrrq_slock, lock_flags); - hwq->hrrq_online = false; - spin_unlock_irqrestore(&hwq->hrrq_slock, lock_flags); - - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - flush_pending_cmds(hwq); - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); -} - -/** - * term_afu() - terminates the AFU - * @cfg: Internal structure associated with the host. - * - * Safe to call with AFU/MC in partially allocated/initialized state. - */ -static void term_afu(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int k; - - /* - * Tear down is carefully orchestrated to ensure - * no interrupts can come in when the problem state - * area is unmapped. - * - * 1) Disable all AFU interrupts for each master - * 2) Unmap the problem state area - * 3) Stop each master context - */ - for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) - term_intr(cfg, UNMAP_THREE, k); - - stop_afu(cfg); - - for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) - term_mc(cfg, k); - - dev_dbg(dev, "%s: returning\n", __func__); -} - -/** - * notify_shutdown() - notifies device of pending shutdown - * @cfg: Internal structure associated with the host. - * @wait: Whether to wait for shutdown processing to complete. - * - * This function will notify the AFU that the adapter is being shutdown - * and will wait for shutdown processing to complete if wait is true. - * This notification should flush pending I/Os to the device and halt - * further I/Os until the next AFU reset is issued and device restarted. - */ -static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct dev_dependent_vals *ddv; - __be64 __iomem *fc_port_regs; - u64 reg, status; - int i, retry_cnt = 0; - - ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data; - if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN)) - return; - - if (!afu || !afu->afu_map) { - dev_dbg(dev, "%s: Problem state area not mapped\n", __func__); - return; - } - - /* Notify AFU */ - for (i = 0; i < cfg->num_fc_ports; i++) { - fc_port_regs = get_fc_port_regs(cfg, i); - - reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); - reg |= SISL_FC_SHUTDOWN_NORMAL; - writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); - } - - if (!wait) - return; - - /* Wait up to 1.5 seconds for shutdown processing to complete */ - for (i = 0; i < cfg->num_fc_ports; i++) { - fc_port_regs = get_fc_port_regs(cfg, i); - retry_cnt = 0; - - while (true) { - status = readq_be(&fc_port_regs[FC_STATUS / 8]); - if (status & SISL_STATUS_SHUTDOWN_COMPLETE) - break; - if (++retry_cnt >= MC_RETRY_CNT) { - dev_dbg(dev, "%s: port %d shutdown processing " - "not yet completed\n", __func__, i); - break; - } - msleep(100 * retry_cnt); - } - } -} - -/** - * cxlflash_get_minor() - gets the first available minor number - * - * Return: Unique minor number that can be used to create the character device. - */ -static int cxlflash_get_minor(void) -{ - int minor; - long bit; - - bit = find_first_zero_bit(cxlflash_minor, CXLFLASH_MAX_ADAPTERS); - if (bit >= CXLFLASH_MAX_ADAPTERS) - return -1; - - minor = bit & MINORMASK; - set_bit(minor, cxlflash_minor); - return minor; -} - -/** - * cxlflash_put_minor() - releases the minor number - * @minor: Minor number that is no longer needed. - */ -static void cxlflash_put_minor(int minor) -{ - clear_bit(minor, cxlflash_minor); -} - -/** - * cxlflash_release_chrdev() - release the character device for the host - * @cfg: Internal structure associated with the host. - */ -static void cxlflash_release_chrdev(struct cxlflash_cfg *cfg) -{ - device_unregister(cfg->chardev); - cfg->chardev = NULL; - cdev_del(&cfg->cdev); - cxlflash_put_minor(MINOR(cfg->cdev.dev)); -} - -/** - * cxlflash_remove() - PCI entry point to tear down host - * @pdev: PCI device associated with the host. - * - * Safe to use as a cleanup in partially allocated/initialized state. Note that - * the reset_waitq is flushed as part of the stop/termination of user contexts. - */ -static void cxlflash_remove(struct pci_dev *pdev) -{ - struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); - struct device *dev = &pdev->dev; - ulong lock_flags; - - if (!pci_is_enabled(pdev)) { - dev_dbg(dev, "%s: Device is disabled\n", __func__); - return; - } - - /* Yield to running recovery threads before continuing with remove */ - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && - cfg->state != STATE_PROBING); - spin_lock_irqsave(&cfg->tmf_slock, lock_flags); - if (cfg->tmf_active) - wait_event_interruptible_lock_irq(cfg->tmf_waitq, - !cfg->tmf_active, - cfg->tmf_slock); - spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); - - /* Notify AFU and wait for shutdown processing to complete */ - notify_shutdown(cfg, true); - - cfg->state = STATE_FAILTERM; - cxlflash_stop_term_user_contexts(cfg); - - switch (cfg->init_state) { - case INIT_STATE_CDEV: - cxlflash_release_chrdev(cfg); - fallthrough; - case INIT_STATE_SCSI: - cxlflash_term_local_luns(cfg); - scsi_remove_host(cfg->host); - fallthrough; - case INIT_STATE_AFU: - term_afu(cfg); - fallthrough; - case INIT_STATE_PCI: - cfg->ops->destroy_afu(cfg->afu_cookie); - pci_disable_device(pdev); - fallthrough; - case INIT_STATE_NONE: - free_mem(cfg); - scsi_host_put(cfg->host); - break; - } - - dev_dbg(dev, "%s: returning\n", __func__); -} - -/** - * alloc_mem() - allocates the AFU and its command pool - * @cfg: Internal structure associated with the host. - * - * A partially allocated state remains on failure. - * - * Return: - * 0 on success - * -ENOMEM on failure to allocate memory - */ -static int alloc_mem(struct cxlflash_cfg *cfg) -{ - int rc = 0; - struct device *dev = &cfg->dev->dev; - - /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */ - cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(sizeof(struct afu))); - if (unlikely(!cfg->afu)) { - dev_err(dev, "%s: cannot get %d free pages\n", - __func__, get_order(sizeof(struct afu))); - rc = -ENOMEM; - goto out; - } - cfg->afu->parent = cfg; - cfg->afu->desired_hwqs = CXLFLASH_DEF_HWQS; - cfg->afu->afu_map = NULL; -out: - return rc; -} - -/** - * init_pci() - initializes the host as a PCI device - * @cfg: Internal structure associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int init_pci(struct cxlflash_cfg *cfg) -{ - struct pci_dev *pdev = cfg->dev; - struct device *dev = &cfg->dev->dev; - int rc = 0; - - rc = pci_enable_device(pdev); - if (rc || pci_channel_offline(pdev)) { - if (pci_channel_offline(pdev)) { - cxlflash_wait_for_pci_err_recovery(cfg); - rc = pci_enable_device(pdev); - } - - if (rc) { - dev_err(dev, "%s: Cannot enable adapter\n", __func__); - cxlflash_wait_for_pci_err_recovery(cfg); - goto out; - } - } - -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * init_scsi() - adds the host to the SCSI stack and kicks off host scan - * @cfg: Internal structure associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int init_scsi(struct cxlflash_cfg *cfg) -{ - struct pci_dev *pdev = cfg->dev; - struct device *dev = &cfg->dev->dev; - int rc = 0; - - rc = scsi_add_host(cfg->host, &pdev->dev); - if (rc) { - dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc); - goto out; - } - - scsi_scan_host(cfg->host); - -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * set_port_online() - transitions the specified host FC port to online state - * @fc_regs: Top of MMIO region defined for specified port. - * - * The provided MMIO region must be mapped prior to call. Online state means - * that the FC link layer has synced, completed the handshaking process, and - * is ready for login to start. - */ -static void set_port_online(__be64 __iomem *fc_regs) -{ - u64 cmdcfg; - - cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); - cmdcfg &= (~FC_MTIP_CMDCONFIG_OFFLINE); /* clear OFF_LINE */ - cmdcfg |= (FC_MTIP_CMDCONFIG_ONLINE); /* set ON_LINE */ - writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); -} - -/** - * set_port_offline() - transitions the specified host FC port to offline state - * @fc_regs: Top of MMIO region defined for specified port. - * - * The provided MMIO region must be mapped prior to call. - */ -static void set_port_offline(__be64 __iomem *fc_regs) -{ - u64 cmdcfg; - - cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); - cmdcfg &= (~FC_MTIP_CMDCONFIG_ONLINE); /* clear ON_LINE */ - cmdcfg |= (FC_MTIP_CMDCONFIG_OFFLINE); /* set OFF_LINE */ - writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); -} - -/** - * wait_port_online() - waits for the specified host FC port come online - * @fc_regs: Top of MMIO region defined for specified port. - * @delay_us: Number of microseconds to delay between reading port status. - * @nretry: Number of cycles to retry reading port status. - * - * The provided MMIO region must be mapped prior to call. This will timeout - * when the cable is not plugged in. - * - * Return: - * TRUE (1) when the specified port is online - * FALSE (0) when the specified port fails to come online after timeout - */ -static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) -{ - u64 status; - - WARN_ON(delay_us < 1000); - - do { - msleep(delay_us / 1000); - status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); - if (status == U64_MAX) - nretry /= 2; - } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE && - nretry--); - - return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_ONLINE); -} - -/** - * wait_port_offline() - waits for the specified host FC port go offline - * @fc_regs: Top of MMIO region defined for specified port. - * @delay_us: Number of microseconds to delay between reading port status. - * @nretry: Number of cycles to retry reading port status. - * - * The provided MMIO region must be mapped prior to call. - * - * Return: - * TRUE (1) when the specified port is offline - * FALSE (0) when the specified port fails to go offline after timeout - */ -static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) -{ - u64 status; - - WARN_ON(delay_us < 1000); - - do { - msleep(delay_us / 1000); - status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); - if (status == U64_MAX) - nretry /= 2; - } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE && - nretry--); - - return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_OFFLINE); -} - -/** - * afu_set_wwpn() - configures the WWPN for the specified host FC port - * @afu: AFU associated with the host that owns the specified FC port. - * @port: Port number being configured. - * @fc_regs: Top of MMIO region defined for specified port. - * @wwpn: The world-wide-port-number previously discovered for port. - * - * The provided MMIO region must be mapped prior to call. As part of the - * sequence to configure the WWPN, the port is toggled offline and then back - * online. This toggling action can cause this routine to delay up to a few - * seconds. When configured to use the internal LUN feature of the AFU, a - * failure to come online is overridden. - */ -static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, - u64 wwpn) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - - set_port_offline(fc_regs); - if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, - FC_PORT_STATUS_RETRY_CNT)) { - dev_dbg(dev, "%s: wait on port %d to go offline timed out\n", - __func__, port); - } - - writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); - - set_port_online(fc_regs); - if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, - FC_PORT_STATUS_RETRY_CNT)) { - dev_dbg(dev, "%s: wait on port %d to go online timed out\n", - __func__, port); - } -} - -/** - * afu_link_reset() - resets the specified host FC port - * @afu: AFU associated with the host that owns the specified FC port. - * @port: Port number being configured. - * @fc_regs: Top of MMIO region defined for specified port. - * - * The provided MMIO region must be mapped prior to call. The sequence to - * reset the port involves toggling it offline and then back online. This - * action can cause this routine to delay up to a few seconds. An effort - * is made to maintain link with the device by switching to host to use - * the alternate port exclusively while the reset takes place. - * failure to come online is overridden. - */ -static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - u64 port_sel; - - /* first switch the AFU to the other links, if any */ - port_sel = readq_be(&afu->afu_map->global.regs.afu_port_sel); - port_sel &= ~(1ULL << port); - writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); - cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); - - set_port_offline(fc_regs); - if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, - FC_PORT_STATUS_RETRY_CNT)) - dev_err(dev, "%s: wait on port %d to go offline timed out\n", - __func__, port); - - set_port_online(fc_regs); - if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, - FC_PORT_STATUS_RETRY_CNT)) - dev_err(dev, "%s: wait on port %d to go online timed out\n", - __func__, port); - - /* switch back to include this port */ - port_sel |= (1ULL << port); - writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); - cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); - - dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel); -} - -/** - * afu_err_intr_init() - clears and initializes the AFU for error interrupts - * @afu: AFU associated with the host. - */ -static void afu_err_intr_init(struct afu *afu) -{ - struct cxlflash_cfg *cfg = afu->parent; - __be64 __iomem *fc_port_regs; - int i; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); - u64 reg; - - /* global async interrupts: AFU clears afu_ctrl on context exit - * if async interrupts were sent to that context. This prevents - * the AFU form sending further async interrupts when - * there is - * nobody to receive them. - */ - - /* mask all */ - writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_mask); - /* set LISN# to send and point to primary master context */ - reg = ((u64) (((hwq->ctx_hndl << 8) | SISL_MSI_ASYNC_ERROR)) << 40); - - if (afu->internal_lun) - reg |= 1; /* Bit 63 indicates local lun */ - writeq_be(reg, &afu->afu_map->global.regs.afu_ctrl); - /* clear all */ - writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); - /* unmask bits that are of interest */ - /* note: afu can send an interrupt after this step */ - writeq_be(SISL_ASTATUS_MASK, &afu->afu_map->global.regs.aintr_mask); - /* clear again in case a bit came on after previous clear but before */ - /* unmask */ - writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); - - /* Clear/Set internal lun bits */ - fc_port_regs = get_fc_port_regs(cfg, 0); - reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); - reg &= SISL_FC_INTERNAL_MASK; - if (afu->internal_lun) - reg |= ((u64)(afu->internal_lun - 1) << SISL_FC_INTERNAL_SHIFT); - writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); - - /* now clear FC errors */ - for (i = 0; i < cfg->num_fc_ports; i++) { - fc_port_regs = get_fc_port_regs(cfg, i); - - writeq_be(0xFFFFFFFFU, &fc_port_regs[FC_ERROR / 8]); - writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); - } - - /* sync interrupts for master's IOARRIN write */ - /* note that unlike asyncs, there can be no pending sync interrupts */ - /* at this time (this is a fresh context and master has not written */ - /* IOARRIN yet), so there is nothing to clear. */ - - /* set LISN#, it is always sent to the context that wrote IOARRIN */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - reg = readq_be(&hwq->host_map->ctx_ctrl); - WARN_ON((reg & SISL_CTX_CTRL_LISN_MASK) != 0); - reg |= SISL_MSI_SYNC_ERROR; - writeq_be(reg, &hwq->host_map->ctx_ctrl); - writeq_be(SISL_ISTATUS_MASK, &hwq->host_map->intr_mask); - } -} - -/** - * cxlflash_sync_err_irq() - interrupt handler for synchronous errors - * @irq: Interrupt number. - * @data: Private data provided at interrupt registration, the AFU. - * - * Return: Always return IRQ_HANDLED. - */ -static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) -{ - struct hwq *hwq = (struct hwq *)data; - struct cxlflash_cfg *cfg = hwq->afu->parent; - struct device *dev = &cfg->dev->dev; - u64 reg; - u64 reg_unmasked; - - reg = readq_be(&hwq->host_map->intr_status); - reg_unmasked = (reg & SISL_ISTATUS_UNMASK); - - if (reg_unmasked == 0UL) { - dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n", - __func__, reg); - goto cxlflash_sync_err_irq_exit; - } - - dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n", - __func__, reg); - - writeq_be(reg_unmasked, &hwq->host_map->intr_clear); - -cxlflash_sync_err_irq_exit: - return IRQ_HANDLED; -} - -/** - * process_hrrq() - process the read-response queue - * @hwq: HWQ associated with the host. - * @doneq: Queue of commands harvested from the RRQ. - * @budget: Threshold of RRQ entries to process. - * - * This routine must be called holding the disabled RRQ spin lock. - * - * Return: The number of entries processed. - */ -static int process_hrrq(struct hwq *hwq, struct list_head *doneq, int budget) -{ - struct afu *afu = hwq->afu; - struct afu_cmd *cmd; - struct sisl_ioasa *ioasa; - struct sisl_ioarcb *ioarcb; - bool toggle = hwq->toggle; - int num_hrrq = 0; - u64 entry, - *hrrq_start = hwq->hrrq_start, - *hrrq_end = hwq->hrrq_end, - *hrrq_curr = hwq->hrrq_curr; - - /* Process ready RRQ entries up to the specified budget (if any) */ - while (true) { - entry = *hrrq_curr; - - if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle) - break; - - entry &= ~SISL_RESP_HANDLE_T_BIT; - - if (afu_is_sq_cmd_mode(afu)) { - ioasa = (struct sisl_ioasa *)entry; - cmd = container_of(ioasa, struct afu_cmd, sa); - } else { - ioarcb = (struct sisl_ioarcb *)entry; - cmd = container_of(ioarcb, struct afu_cmd, rcb); - } - - list_add_tail(&cmd->queue, doneq); - - /* Advance to next entry or wrap and flip the toggle bit */ - if (hrrq_curr < hrrq_end) - hrrq_curr++; - else { - hrrq_curr = hrrq_start; - toggle ^= SISL_RESP_HANDLE_T_BIT; - } - - atomic_inc(&hwq->hsq_credits); - num_hrrq++; - - if (budget > 0 && num_hrrq >= budget) - break; - } - - hwq->hrrq_curr = hrrq_curr; - hwq->toggle = toggle; - - return num_hrrq; -} - -/** - * process_cmd_doneq() - process a queue of harvested RRQ commands - * @doneq: Queue of completed commands. - * - * Note that upon return the queue can no longer be trusted. - */ -static void process_cmd_doneq(struct list_head *doneq) -{ - struct afu_cmd *cmd, *tmp; - - WARN_ON(list_empty(doneq)); - - list_for_each_entry_safe(cmd, tmp, doneq, queue) - cmd_complete(cmd); -} - -/** - * cxlflash_irqpoll() - process a queue of harvested RRQ commands - * @irqpoll: IRQ poll structure associated with queue to poll. - * @budget: Threshold of RRQ entries to process per poll. - * - * Return: The number of entries processed. - */ -static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget) -{ - struct hwq *hwq = container_of(irqpoll, struct hwq, irqpoll); - unsigned long hrrq_flags; - LIST_HEAD(doneq); - int num_entries = 0; - - spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); - - num_entries = process_hrrq(hwq, &doneq, budget); - if (num_entries < budget) - irq_poll_complete(irqpoll); - - spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); - - process_cmd_doneq(&doneq); - return num_entries; -} - -/** - * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) - * @irq: Interrupt number. - * @data: Private data provided at interrupt registration, the AFU. - * - * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found. - */ -static irqreturn_t cxlflash_rrq_irq(int irq, void *data) -{ - struct hwq *hwq = (struct hwq *)data; - struct afu *afu = hwq->afu; - unsigned long hrrq_flags; - LIST_HEAD(doneq); - int num_entries = 0; - - spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); - - /* Silently drop spurious interrupts when queue is not online */ - if (!hwq->hrrq_online) { - spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); - return IRQ_HANDLED; - } - - if (afu_is_irqpoll_enabled(afu)) { - irq_poll_sched(&hwq->irqpoll); - spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); - return IRQ_HANDLED; - } - - num_entries = process_hrrq(hwq, &doneq, -1); - spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); - - if (num_entries == 0) - return IRQ_NONE; - - process_cmd_doneq(&doneq); - return IRQ_HANDLED; -} - -/* - * Asynchronous interrupt information table - * - * NOTE: - * - Order matters here as this array is indexed by bit position. - * - * - The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro - * as complex and complains due to a lack of parentheses/braces. - */ -#define ASTATUS_FC(_a, _b, _c, _d) \ - { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } - -#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ - ASTATUS_FC(_a, LINK_UP, "link up", 0), \ - ASTATUS_FC(_a, LINK_DN, "link down", 0), \ - ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ - ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ - ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ - ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ - ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ - ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET) - -static const struct asyc_intr_info ainfo[] = { - BUILD_SISL_ASTATUS_FC_PORT(1), - BUILD_SISL_ASTATUS_FC_PORT(0), - BUILD_SISL_ASTATUS_FC_PORT(3), - BUILD_SISL_ASTATUS_FC_PORT(2) -}; - -/** - * cxlflash_async_err_irq() - interrupt handler for asynchronous errors - * @irq: Interrupt number. - * @data: Private data provided at interrupt registration, the AFU. - * - * Return: Always return IRQ_HANDLED. - */ -static irqreturn_t cxlflash_async_err_irq(int irq, void *data) -{ - struct hwq *hwq = (struct hwq *)data; - struct afu *afu = hwq->afu; - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - const struct asyc_intr_info *info; - struct sisl_global_map __iomem *global = &afu->afu_map->global; - __be64 __iomem *fc_port_regs; - u64 reg_unmasked; - u64 reg; - u64 bit; - u8 port; - - reg = readq_be(&global->regs.aintr_status); - reg_unmasked = (reg & SISL_ASTATUS_UNMASK); - - if (unlikely(reg_unmasked == 0)) { - dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n", - __func__, reg); - goto out; - } - - /* FYI, it is 'okay' to clear AFU status before FC_ERROR */ - writeq_be(reg_unmasked, &global->regs.aintr_clear); - - /* Check each bit that is on */ - for_each_set_bit(bit, (ulong *)®_unmasked, BITS_PER_LONG) { - if (unlikely(bit >= ARRAY_SIZE(ainfo))) { - WARN_ON_ONCE(1); - continue; - } - - info = &ainfo[bit]; - if (unlikely(info->status != 1ULL << bit)) { - WARN_ON_ONCE(1); - continue; - } - - port = info->port; - fc_port_regs = get_fc_port_regs(cfg, port); - - dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n", - __func__, port, info->desc, - readq_be(&fc_port_regs[FC_STATUS / 8])); - - /* - * Do link reset first, some OTHER errors will set FC_ERROR - * again if cleared before or w/o a reset - */ - if (info->action & LINK_RESET) { - dev_err(dev, "%s: FC Port %d: resetting link\n", - __func__, port); - cfg->lr_state = LINK_RESET_REQUIRED; - cfg->lr_port = port; - schedule_work(&cfg->work_q); - } - - if (info->action & CLR_FC_ERROR) { - reg = readq_be(&fc_port_regs[FC_ERROR / 8]); - - /* - * Since all errors are unmasked, FC_ERROR and FC_ERRCAP - * should be the same and tracing one is sufficient. - */ - - dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n", - __func__, port, reg); - - writeq_be(reg, &fc_port_regs[FC_ERROR / 8]); - writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); - } - - if (info->action & SCAN_HOST) { - atomic_inc(&cfg->scan_host_needed); - schedule_work(&cfg->work_q); - } - } - -out: - return IRQ_HANDLED; -} - -/** - * read_vpd() - obtains the WWPNs from VPD - * @cfg: Internal structure associated with the host. - * @wwpn: Array of size MAX_FC_PORTS to pass back WWPNs - * - * Return: 0 on success, -errno on failure - */ -static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) -{ - struct device *dev = &cfg->dev->dev; - struct pci_dev *pdev = cfg->dev; - int i, k, rc = 0; - unsigned int kw_size; - ssize_t vpd_size; - char vpd_data[CXLFLASH_VPD_LEN]; - char tmp_buf[WWPN_BUF_LEN] = { 0 }; - const struct dev_dependent_vals *ddv = (struct dev_dependent_vals *) - cfg->dev_id->driver_data; - const bool wwpn_vpd_required = ddv->flags & CXLFLASH_WWPN_VPD_REQUIRED; - const char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6", "V7", "V8" }; - - /* Get the VPD data from the device */ - vpd_size = cfg->ops->read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); - if (unlikely(vpd_size <= 0)) { - dev_err(dev, "%s: Unable to read VPD (size = %ld)\n", - __func__, vpd_size); - rc = -ENODEV; - goto out; - } - - /* - * Find the offset of the WWPN tag within the read only - * VPD data and validate the found field (partials are - * no good to us). Convert the ASCII data to an integer - * value. Note that we must copy to a temporary buffer - * because the conversion service requires that the ASCII - * string be terminated. - * - * Allow for WWPN not being found for all devices, setting - * the returned WWPN to zero when not found. Notify with a - * log error for cards that should have had WWPN keywords - * in the VPD - cards requiring WWPN will not have their - * ports programmed and operate in an undefined state. - */ - for (k = 0; k < cfg->num_fc_ports; k++) { - i = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, - wwpn_vpd_tags[k], &kw_size); - if (i == -ENOENT) { - if (wwpn_vpd_required) - dev_err(dev, "%s: Port %d WWPN not found\n", - __func__, k); - wwpn[k] = 0ULL; - continue; - } - - if (i < 0 || kw_size != WWPN_LEN) { - dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n", - __func__, k); - rc = -ENODEV; - goto out; - } - - memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); - rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); - if (unlikely(rc)) { - dev_err(dev, "%s: WWPN conversion failed for port %d\n", - __func__, k); - rc = -ENODEV; - goto out; - } - - dev_dbg(dev, "%s: wwpn%d=%016llx\n", __func__, k, wwpn[k]); - } - -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * init_pcr() - initialize the provisioning and control registers - * @cfg: Internal structure associated with the host. - * - * Also sets up fast access to the mapped registers and initializes AFU - * command fields that never change. - */ -static void init_pcr(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct sisl_ctrl_map __iomem *ctrl_map; - struct hwq *hwq; - void *cookie; - int i; - - for (i = 0; i < MAX_CONTEXT; i++) { - ctrl_map = &afu->afu_map->ctrls[i].ctrl; - /* Disrupt any clients that could be running */ - /* e.g. clients that survived a master restart */ - writeq_be(0, &ctrl_map->rht_start); - writeq_be(0, &ctrl_map->rht_cnt_id); - writeq_be(0, &ctrl_map->ctx_cap); - } - - /* Copy frequently used fields into hwq */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - cookie = hwq->ctx_cookie; - - hwq->ctx_hndl = (u16) cfg->ops->process_element(cookie); - hwq->host_map = &afu->afu_map->hosts[hwq->ctx_hndl].host; - hwq->ctrl_map = &afu->afu_map->ctrls[hwq->ctx_hndl].ctrl; - - /* Program the Endian Control for the master context */ - writeq_be(SISL_ENDIAN_CTRL, &hwq->host_map->endian_ctrl); - } -} - -/** - * init_global() - initialize AFU global registers - * @cfg: Internal structure associated with the host. - */ -static int init_global(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq; - struct sisl_host_map __iomem *hmap; - __be64 __iomem *fc_port_regs; - u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */ - int i = 0, num_ports = 0; - int rc = 0; - int j; - void *ctx; - u64 reg; - - rc = read_vpd(cfg, &wwpn[0]); - if (rc) { - dev_err(dev, "%s: could not read vpd rc=%d\n", __func__, rc); - goto out; - } - - /* Set up RRQ and SQ in HWQ for master issued cmds */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - hmap = hwq->host_map; - - writeq_be((u64) hwq->hrrq_start, &hmap->rrq_start); - writeq_be((u64) hwq->hrrq_end, &hmap->rrq_end); - hwq->hrrq_online = true; - - if (afu_is_sq_cmd_mode(afu)) { - writeq_be((u64)hwq->hsq_start, &hmap->sq_start); - writeq_be((u64)hwq->hsq_end, &hmap->sq_end); - } - } - - /* AFU configuration */ - reg = readq_be(&afu->afu_map->global.regs.afu_config); - reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN; - /* enable all auto retry options and control endianness */ - /* leave others at default: */ - /* CTX_CAP write protected, mbox_r does not clear on read and */ - /* checker on if dual afu */ - writeq_be(reg, &afu->afu_map->global.regs.afu_config); - - /* Global port select: select either port */ - if (afu->internal_lun) { - /* Only use port 0 */ - writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); - num_ports = 0; - } else { - writeq_be(PORT_MASK(cfg->num_fc_ports), - &afu->afu_map->global.regs.afu_port_sel); - num_ports = cfg->num_fc_ports; - } - - for (i = 0; i < num_ports; i++) { - fc_port_regs = get_fc_port_regs(cfg, i); - - /* Unmask all errors (but they are still masked at AFU) */ - writeq_be(0, &fc_port_regs[FC_ERRMSK / 8]); - /* Clear CRC error cnt & set a threshold */ - (void)readq_be(&fc_port_regs[FC_CNT_CRCERR / 8]); - writeq_be(MC_CRC_THRESH, &fc_port_regs[FC_CRC_THRESH / 8]); - - /* Set WWPNs. If already programmed, wwpn[i] is 0 */ - if (wwpn[i] != 0) - afu_set_wwpn(afu, i, &fc_port_regs[0], wwpn[i]); - /* Programming WWPN back to back causes additional - * offline/online transitions and a PLOGI - */ - msleep(100); - } - - if (afu_is_ocxl_lisn(afu)) { - /* Set up the LISN effective address for each master */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - ctx = hwq->ctx_cookie; - - for (j = 0; j < hwq->num_irqs; j++) { - reg = cfg->ops->get_irq_objhndl(ctx, j); - writeq_be(reg, &hwq->ctrl_map->lisn_ea[j]); - } - - reg = hwq->ctx_hndl; - writeq_be(SISL_LISN_PASID(reg, reg), - &hwq->ctrl_map->lisn_pasid[0]); - writeq_be(SISL_LISN_PASID(0UL, reg), - &hwq->ctrl_map->lisn_pasid[1]); - } - } - - /* Set up master's own CTX_CAP to allow real mode, host translation */ - /* tables, afu cmds and read/write GSCSI cmds. */ - /* First, unlock ctx_cap write by reading mbox */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - (void)readq_be(&hwq->ctrl_map->mbox_r); /* unlock ctx_cap */ - writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | - SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | - SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), - &hwq->ctrl_map->ctx_cap); - } - - /* - * Determine write-same unmap support for host by evaluating the unmap - * sector support bit of the context control register associated with - * the primary hardware queue. Note that while this status is reflected - * in a context register, the outcome can be assumed to be host-wide. - */ - hwq = get_hwq(afu, PRIMARY_HWQ); - reg = readq_be(&hwq->host_map->ctx_ctrl); - if (reg & SISL_CTX_CTRL_UNMAP_SECTOR) - cfg->ws_unmap = true; - - /* Initialize heartbeat */ - afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); -out: - return rc; -} - -/** - * start_afu() - initializes and starts the AFU - * @cfg: Internal structure associated with the host. - */ -static int start_afu(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq; - int rc = 0; - int i; - - init_pcr(cfg); - - /* Initialize each HWQ */ - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - /* After an AFU reset, RRQ entries are stale, clear them */ - memset(&hwq->rrq_entry, 0, sizeof(hwq->rrq_entry)); - - /* Initialize RRQ pointers */ - hwq->hrrq_start = &hwq->rrq_entry[0]; - hwq->hrrq_end = &hwq->rrq_entry[NUM_RRQ_ENTRY - 1]; - hwq->hrrq_curr = hwq->hrrq_start; - hwq->toggle = 1; - - /* Initialize spin locks */ - spin_lock_init(&hwq->hrrq_slock); - spin_lock_init(&hwq->hsq_slock); - - /* Initialize SQ */ - if (afu_is_sq_cmd_mode(afu)) { - memset(&hwq->sq, 0, sizeof(hwq->sq)); - hwq->hsq_start = &hwq->sq[0]; - hwq->hsq_end = &hwq->sq[NUM_SQ_ENTRY - 1]; - hwq->hsq_curr = hwq->hsq_start; - - atomic_set(&hwq->hsq_credits, NUM_SQ_ENTRY - 1); - } - - /* Initialize IRQ poll */ - if (afu_is_irqpoll_enabled(afu)) - irq_poll_init(&hwq->irqpoll, afu->irqpoll_weight, - cxlflash_irqpoll); - - } - - rc = init_global(cfg); - - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * init_intr() - setup interrupt handlers for the master context - * @cfg: Internal structure associated with the host. - * @hwq: Hardware queue to initialize. - * - * Return: 0 on success, -errno on failure - */ -static enum undo_level init_intr(struct cxlflash_cfg *cfg, - struct hwq *hwq) -{ - struct device *dev = &cfg->dev->dev; - void *ctx = hwq->ctx_cookie; - int rc = 0; - enum undo_level level = UNDO_NOOP; - bool is_primary_hwq = (hwq->index == PRIMARY_HWQ); - int num_irqs = hwq->num_irqs; - - rc = cfg->ops->allocate_afu_irqs(ctx, num_irqs); - if (unlikely(rc)) { - dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n", - __func__, rc); - level = UNDO_NOOP; - goto out; - } - - rc = cfg->ops->map_afu_irq(ctx, 1, cxlflash_sync_err_irq, hwq, - "SISL_MSI_SYNC_ERROR"); - if (unlikely(rc <= 0)) { - dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__); - level = FREE_IRQ; - goto out; - } - - rc = cfg->ops->map_afu_irq(ctx, 2, cxlflash_rrq_irq, hwq, - "SISL_MSI_RRQ_UPDATED"); - if (unlikely(rc <= 0)) { - dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__); - level = UNMAP_ONE; - goto out; - } - - /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ - if (!is_primary_hwq) - goto out; - - rc = cfg->ops->map_afu_irq(ctx, 3, cxlflash_async_err_irq, hwq, - "SISL_MSI_ASYNC_ERROR"); - if (unlikely(rc <= 0)) { - dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__); - level = UNMAP_TWO; - goto out; - } -out: - return level; -} - -/** - * init_mc() - create and register as the master context - * @cfg: Internal structure associated with the host. - * @index: HWQ Index of the master context. - * - * Return: 0 on success, -errno on failure - */ -static int init_mc(struct cxlflash_cfg *cfg, u32 index) -{ - void *ctx; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq = get_hwq(cfg->afu, index); - int rc = 0; - int num_irqs; - enum undo_level level; - - hwq->afu = cfg->afu; - hwq->index = index; - INIT_LIST_HEAD(&hwq->pending_cmds); - - if (index == PRIMARY_HWQ) { - ctx = cfg->ops->get_context(cfg->dev, cfg->afu_cookie); - num_irqs = 3; - } else { - ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); - num_irqs = 2; - } - if (IS_ERR_OR_NULL(ctx)) { - rc = -ENOMEM; - goto err1; - } - - WARN_ON(hwq->ctx_cookie); - hwq->ctx_cookie = ctx; - hwq->num_irqs = num_irqs; - - /* Set it up as a master with the CXL */ - cfg->ops->set_master(ctx); - - /* Reset AFU when initializing primary context */ - if (index == PRIMARY_HWQ) { - rc = cfg->ops->afu_reset(ctx); - if (unlikely(rc)) { - dev_err(dev, "%s: AFU reset failed rc=%d\n", - __func__, rc); - goto err1; - } - } - - level = init_intr(cfg, hwq); - if (unlikely(level)) { - dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc); - goto err2; - } - - /* Finally, activate the context by starting it */ - rc = cfg->ops->start_context(hwq->ctx_cookie); - if (unlikely(rc)) { - dev_err(dev, "%s: start context failed rc=%d\n", __func__, rc); - level = UNMAP_THREE; - goto err2; - } - -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -err2: - term_intr(cfg, level, index); - if (index != PRIMARY_HWQ) - cfg->ops->release_context(ctx); -err1: - hwq->ctx_cookie = NULL; - goto out; -} - -/** - * get_num_afu_ports() - determines and configures the number of AFU ports - * @cfg: Internal structure associated with the host. - * - * This routine determines the number of AFU ports by converting the global - * port selection mask. The converted value is only valid following an AFU - * reset (explicit or power-on). This routine must be invoked shortly after - * mapping as other routines are dependent on the number of ports during the - * initialization sequence. - * - * To support legacy AFUs that might not have reflected an initial global - * port mask (value read is 0), default to the number of ports originally - * supported by the cxlflash driver (2) before hardware with other port - * offerings was introduced. - */ -static void get_num_afu_ports(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - u64 port_mask; - int num_fc_ports = LEGACY_FC_PORTS; - - port_mask = readq_be(&afu->afu_map->global.regs.afu_port_sel); - if (port_mask != 0ULL) - num_fc_ports = min(ilog2(port_mask) + 1, MAX_FC_PORTS); - - dev_dbg(dev, "%s: port_mask=%016llx num_fc_ports=%d\n", - __func__, port_mask, num_fc_ports); - - cfg->num_fc_ports = num_fc_ports; - cfg->host->max_channel = PORTNUM2CHAN(num_fc_ports); -} - -/** - * init_afu() - setup as master context and start AFU - * @cfg: Internal structure associated with the host. - * - * This routine is a higher level of control for configuring the - * AFU on probe and reset paths. - * - * Return: 0 on success, -errno on failure - */ -static int init_afu(struct cxlflash_cfg *cfg) -{ - u64 reg; - int rc = 0; - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct hwq *hwq; - int i; - - cfg->ops->perst_reloads_same_image(cfg->afu_cookie, true); - - mutex_init(&afu->sync_active); - afu->num_hwqs = afu->desired_hwqs; - for (i = 0; i < afu->num_hwqs; i++) { - rc = init_mc(cfg, i); - if (rc) { - dev_err(dev, "%s: init_mc failed rc=%d index=%d\n", - __func__, rc, i); - goto err1; - } - } - - /* Map the entire MMIO space of the AFU using the first context */ - hwq = get_hwq(afu, PRIMARY_HWQ); - afu->afu_map = cfg->ops->psa_map(hwq->ctx_cookie); - if (!afu->afu_map) { - dev_err(dev, "%s: psa_map failed\n", __func__); - rc = -ENOMEM; - goto err1; - } - - /* No byte reverse on reading afu_version or string will be backwards */ - reg = readq(&afu->afu_map->global.regs.afu_version); - memcpy(afu->version, ®, sizeof(reg)); - afu->interface_version = - readq_be(&afu->afu_map->global.regs.interface_version); - if ((afu->interface_version + 1) == 0) { - dev_err(dev, "Back level AFU, please upgrade. AFU version %s " - "interface version %016llx\n", afu->version, - afu->interface_version); - rc = -EINVAL; - goto err1; - } - - if (afu_is_sq_cmd_mode(afu)) { - afu->send_cmd = send_cmd_sq; - afu->context_reset = context_reset_sq; - } else { - afu->send_cmd = send_cmd_ioarrin; - afu->context_reset = context_reset_ioarrin; - } - - dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, - afu->version, afu->interface_version); - - get_num_afu_ports(cfg); - - rc = start_afu(cfg); - if (rc) { - dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); - goto err1; - } - - afu_err_intr_init(cfg->afu); - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - hwq->room = readq_be(&hwq->host_map->cmd_room); - } - - /* Restore the LUN mappings */ - cxlflash_restore_luntable(cfg); -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; - -err1: - for (i = afu->num_hwqs - 1; i >= 0; i--) { - term_intr(cfg, UNMAP_THREE, i); - term_mc(cfg, i); - } - goto out; -} - -/** - * afu_reset() - resets the AFU - * @cfg: Internal structure associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int afu_reset(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int rc = 0; - - /* Stop the context before the reset. Since the context is - * no longer available restart it after the reset is complete - */ - term_afu(cfg); - - rc = init_afu(cfg); - - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * drain_ioctls() - wait until all currently executing ioctls have completed - * @cfg: Internal structure associated with the host. - * - * Obtain write access to read/write semaphore that wraps ioctl - * handling to 'drain' ioctls currently executing. - */ -static void drain_ioctls(struct cxlflash_cfg *cfg) -{ - down_write(&cfg->ioctl_rwsem); - up_write(&cfg->ioctl_rwsem); -} - -/** - * cxlflash_async_reset_host() - asynchronous host reset handler - * @data: Private data provided while scheduling reset. - * @cookie: Cookie that can be used for checkpointing. - */ -static void cxlflash_async_reset_host(void *data, async_cookie_t cookie) -{ - struct cxlflash_cfg *cfg = data; - struct device *dev = &cfg->dev->dev; - int rc = 0; - - if (cfg->state != STATE_RESET) { - dev_dbg(dev, "%s: Not performing a reset, state=%d\n", - __func__, cfg->state); - goto out; - } - - drain_ioctls(cfg); - cxlflash_mark_contexts_error(cfg); - rc = afu_reset(cfg); - if (rc) - cfg->state = STATE_FAILTERM; - else - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->reset_waitq); - -out: - scsi_unblock_requests(cfg->host); -} - -/** - * cxlflash_schedule_async_reset() - schedule an asynchronous host reset - * @cfg: Internal structure associated with the host. - */ -static void cxlflash_schedule_async_reset(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - - if (cfg->state != STATE_NORMAL) { - dev_dbg(dev, "%s: Not performing reset state=%d\n", - __func__, cfg->state); - return; - } - - cfg->state = STATE_RESET; - scsi_block_requests(cfg->host); - cfg->async_reset_cookie = async_schedule(cxlflash_async_reset_host, - cfg); -} - -/** - * send_afu_cmd() - builds and sends an internal AFU command - * @afu: AFU associated with the host. - * @rcb: Pre-populated IOARCB describing command to send. - * - * The AFU can only take one internal AFU command at a time. This limitation is - * enforced by using a mutex to provide exclusive access to the AFU during the - * operation. This design point requires calling threads to not be on interrupt - * context due to the possibility of sleeping during concurrent AFU operations. - * - * The command status is optionally passed back to the caller when the caller - * populates the IOASA field of the IOARCB with a pointer to an IOASA structure. - * - * Return: - * 0 on success, -errno on failure - */ -static int send_afu_cmd(struct afu *afu, struct sisl_ioarcb *rcb) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct afu_cmd *cmd = NULL; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); - ulong lock_flags; - char *buf = NULL; - int rc = 0; - int nretry = 0; - - if (cfg->state != STATE_NORMAL) { - dev_dbg(dev, "%s: Sync not required state=%u\n", - __func__, cfg->state); - return 0; - } - - mutex_lock(&afu->sync_active); - atomic_inc(&afu->cmds_active); - buf = kmalloc(sizeof(*cmd) + __alignof__(*cmd) - 1, GFP_KERNEL); - if (unlikely(!buf)) { - dev_err(dev, "%s: no memory for command\n", __func__); - rc = -ENOMEM; - goto out; - } - - cmd = (struct afu_cmd *)PTR_ALIGN(buf, __alignof__(*cmd)); - -retry: - memset(cmd, 0, sizeof(*cmd)); - memcpy(&cmd->rcb, rcb, sizeof(*rcb)); - INIT_LIST_HEAD(&cmd->queue); - init_completion(&cmd->cevent); - cmd->parent = afu; - cmd->hwq_index = hwq->index; - cmd->rcb.ctx_id = hwq->ctx_hndl; - - dev_dbg(dev, "%s: afu=%p cmd=%p type=%02x nretry=%d\n", - __func__, afu, cmd, cmd->rcb.cdb[0], nretry); - - rc = afu->send_cmd(afu, cmd); - if (unlikely(rc)) { - rc = -ENOBUFS; - goto out; - } - - rc = wait_resp(afu, cmd); - switch (rc) { - case -ETIMEDOUT: - rc = afu->context_reset(hwq); - if (rc) { - /* Delete the command from pending_cmds list */ - spin_lock_irqsave(&hwq->hsq_slock, lock_flags); - list_del(&cmd->list); - spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); - - cxlflash_schedule_async_reset(cfg); - break; - } - fallthrough; /* to retry */ - case -EAGAIN: - if (++nretry < 2) - goto retry; - fallthrough; /* to exit */ - default: - break; - } - - if (rcb->ioasa) - *rcb->ioasa = cmd->sa; -out: - atomic_dec(&afu->cmds_active); - mutex_unlock(&afu->sync_active); - kfree(buf); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_afu_sync() - builds and sends an AFU sync command - * @afu: AFU associated with the host. - * @ctx: Identifies context requesting sync. - * @res: Identifies resource requesting sync. - * @mode: Type of sync to issue (lightweight, heavyweight, global). - * - * AFU sync operations are only necessary and allowed when the device is - * operating normally. When not operating normally, sync requests can occur as - * part of cleaning up resources associated with an adapter prior to removal. - * In this scenario, these requests are simply ignored (safe due to the AFU - * going away). - * - * Return: - * 0 on success, -errno on failure - */ -int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx, res_hndl_t res, u8 mode) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct sisl_ioarcb rcb = { 0 }; - - dev_dbg(dev, "%s: afu=%p ctx=%u res=%u mode=%u\n", - __func__, afu, ctx, res, mode); - - rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; - rcb.msi = SISL_MSI_RRQ_UPDATED; - rcb.timeout = MC_AFU_SYNC_TIMEOUT; - - rcb.cdb[0] = SISL_AFU_CMD_SYNC; - rcb.cdb[1] = mode; - put_unaligned_be16(ctx, &rcb.cdb[2]); - put_unaligned_be32(res, &rcb.cdb[4]); - - return send_afu_cmd(afu, &rcb); -} - -/** - * cxlflash_eh_abort_handler() - abort a SCSI command - * @scp: SCSI command to abort. - * - * CXL Flash devices do not support a single command abort. Reset the context - * as per SISLite specification. Flush any pending commands in the hardware - * queue before the reset. - * - * Return: SUCCESS/FAILED as defined in scsi/scsi.h - */ -static int cxlflash_eh_abort_handler(struct scsi_cmnd *scp) -{ - int rc = FAILED; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = shost_priv(host); - struct afu_cmd *cmd = sc_to_afuc(scp); - struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct hwq *hwq = get_hwq(afu, cmd->hwq_index); - - dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, - scp->device->channel, scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - - /* When the state is not normal, another reset/reload is in progress. - * Return failed and the mid-layer will invoke host reset handler. - */ - if (cfg->state != STATE_NORMAL) { - dev_dbg(dev, "%s: Invalid state for abort, state=%d\n", - __func__, cfg->state); - goto out; - } - - rc = afu->context_reset(hwq); - if (unlikely(rc)) - goto out; - - rc = SUCCESS; - -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_eh_device_reset_handler() - reset a single LUN - * @scp: SCSI command to send. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h - */ -static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) -{ - int rc = SUCCESS; - struct scsi_device *sdev = scp->device; - struct Scsi_Host *host = sdev->host; - struct cxlflash_cfg *cfg = shost_priv(host); - struct device *dev = &cfg->dev->dev; - int rcr = 0; - - dev_dbg(dev, "%s: %d/%d/%d/%llu\n", __func__, - host->host_no, sdev->channel, sdev->id, sdev->lun); -retry: - switch (cfg->state) { - case STATE_NORMAL: - rcr = send_tmf(cfg, sdev, TMF_LUN_RESET); - if (unlikely(rcr)) - rc = FAILED; - break; - case STATE_RESET: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - goto retry; - default: - rc = FAILED; - break; - } - - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_eh_host_reset_handler() - reset the host adapter - * @scp: SCSI command from stack identifying host. - * - * Following a reset, the state is evaluated again in case an EEH occurred - * during the reset. In such a scenario, the host reset will either yield - * until the EEH recovery is complete or return success or failure based - * upon the current device state. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h - */ -static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) -{ - int rc = SUCCESS; - int rcr = 0; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = shost_priv(host); - struct device *dev = &cfg->dev->dev; - - dev_dbg(dev, "%s: %d\n", __func__, host->host_no); - - switch (cfg->state) { - case STATE_NORMAL: - cfg->state = STATE_RESET; - drain_ioctls(cfg); - cxlflash_mark_contexts_error(cfg); - rcr = afu_reset(cfg); - if (rcr) { - rc = FAILED; - cfg->state = STATE_FAILTERM; - } else - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->reset_waitq); - ssleep(1); - fallthrough; - case STATE_RESET: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - if (cfg->state == STATE_NORMAL) - break; - fallthrough; - default: - rc = FAILED; - break; - } - - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_change_queue_depth() - change the queue depth for the device - * @sdev: SCSI device destined for queue depth change. - * @qdepth: Requested queue depth value to set. - * - * The requested queue depth is capped to the maximum supported value. - * - * Return: The actual queue depth set. - */ -static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) -{ - - if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) - qdepth = CXLFLASH_MAX_CMDS_PER_LUN; - - scsi_change_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - -/** - * cxlflash_show_port_status() - queries and presents the current port status - * @port: Desired port for status reporting. - * @cfg: Internal structure associated with the host. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf or -EINVAL. - */ -static ssize_t cxlflash_show_port_status(u32 port, - struct cxlflash_cfg *cfg, - char *buf) -{ - struct device *dev = &cfg->dev->dev; - char *disp_status; - u64 status; - __be64 __iomem *fc_port_regs; - - WARN_ON(port >= MAX_FC_PORTS); - - if (port >= cfg->num_fc_ports) { - dev_info(dev, "%s: Port %d not supported on this card.\n", - __func__, port); - return -EINVAL; - } - - fc_port_regs = get_fc_port_regs(cfg, port); - status = readq_be(&fc_port_regs[FC_MTIP_STATUS / 8]); - status &= FC_MTIP_STATUS_MASK; - - if (status == FC_MTIP_STATUS_ONLINE) - disp_status = "online"; - else if (status == FC_MTIP_STATUS_OFFLINE) - disp_status = "offline"; - else - disp_status = "unknown"; - - return scnprintf(buf, PAGE_SIZE, "%s\n", disp_status); -} - -/** - * port0_show() - queries and presents the current status of port 0 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port0_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_status(0, cfg, buf); -} - -/** - * port1_show() - queries and presents the current status of port 1 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port1_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_status(1, cfg, buf); -} - -/** - * port2_show() - queries and presents the current status of port 2 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port2_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_status(2, cfg, buf); -} - -/** - * port3_show() - queries and presents the current status of port 3 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port3_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_status(3, cfg, buf); -} - -/** - * lun_mode_show() - presents the current LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the LUN mode. - * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t lun_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - - return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); -} - -/** - * lun_mode_store() - sets the LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the LUN mode. - * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. - * @count: Length of data resizing in @buf. - * - * The CXL Flash AFU supports a dummy LUN mode where the external - * links and storage are not required. Space on the FPGA is used - * to create 1 or 2 small LUNs which are presented to the system - * as if they were a normal storage device. This feature is useful - * during development and also provides manufacturing with a way - * to test the AFU without an actual device. - * - * 0 = external LUN[s] (default) - * 1 = internal LUN (1 x 64K, 512B blocks, id 0) - * 2 = internal LUN (1 x 64K, 4K blocks, id 0) - * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) - * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t lun_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = shost_priv(shost); - struct afu *afu = cfg->afu; - int rc; - u32 lun_mode; - - rc = kstrtouint(buf, 10, &lun_mode); - if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { - afu->internal_lun = lun_mode; - - /* - * When configured for internal LUN, there is only one channel, - * channel number 0, else there will be one less than the number - * of fc ports for this card. - */ - if (afu->internal_lun) - shost->max_channel = 0; - else - shost->max_channel = PORTNUM2CHAN(cfg->num_fc_ports); - - afu_reset(cfg); - scsi_scan_host(cfg->host); - } - - return count; -} - -/** - * ioctl_version_show() - presents the current ioctl version of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the ioctl version. - * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t ioctl_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t bytes = 0; - - bytes = scnprintf(buf, PAGE_SIZE, - "disk: %u\n", DK_CXLFLASH_VERSION_0); - bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, - "host: %u\n", HT_CXLFLASH_VERSION_0); - - return bytes; -} - -/** - * cxlflash_show_port_lun_table() - queries and presents the port LUN table - * @port: Desired port for status reporting. - * @cfg: Internal structure associated with the host. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf or -EINVAL. - */ -static ssize_t cxlflash_show_port_lun_table(u32 port, - struct cxlflash_cfg *cfg, - char *buf) -{ - struct device *dev = &cfg->dev->dev; - __be64 __iomem *fc_port_luns; - int i; - ssize_t bytes = 0; - - WARN_ON(port >= MAX_FC_PORTS); - - if (port >= cfg->num_fc_ports) { - dev_info(dev, "%s: Port %d not supported on this card.\n", - __func__, port); - return -EINVAL; - } - - fc_port_luns = get_fc_port_luns(cfg, port); - - for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) - bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, - "%03d: %016llx\n", - i, readq_be(&fc_port_luns[i])); - return bytes; -} - -/** - * port0_lun_table_show() - presents the current LUN table of port 0 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port0_lun_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_lun_table(0, cfg, buf); -} - -/** - * port1_lun_table_show() - presents the current LUN table of port 1 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port1_lun_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_lun_table(1, cfg, buf); -} - -/** - * port2_lun_table_show() - presents the current LUN table of port 2 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port2_lun_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_lun_table(2, cfg, buf); -} - -/** - * port3_lun_table_show() - presents the current LUN table of port 3 - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t port3_lun_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - - return cxlflash_show_port_lun_table(3, cfg, buf); -} - -/** - * irqpoll_weight_show() - presents the current IRQ poll weight for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the IRQ poll weight. - * @buf: Buffer of length PAGE_SIZE to report back the current IRQ poll - * weight in ASCII. - * - * An IRQ poll weight of 0 indicates polling is disabled. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t irqpoll_weight_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - - return scnprintf(buf, PAGE_SIZE, "%u\n", afu->irqpoll_weight); -} - -/** - * irqpoll_weight_store() - sets the current IRQ poll weight for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the IRQ poll weight. - * @buf: Buffer of length PAGE_SIZE containing the desired IRQ poll - * weight in ASCII. - * @count: Length of data resizing in @buf. - * - * An IRQ poll weight of 0 indicates polling is disabled. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t irqpoll_weight_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct device *cfgdev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct hwq *hwq; - u32 weight; - int rc, i; - - rc = kstrtouint(buf, 10, &weight); - if (rc) - return -EINVAL; - - if (weight > 256) { - dev_info(cfgdev, - "Invalid IRQ poll weight. It must be 256 or less.\n"); - return -EINVAL; - } - - if (weight == afu->irqpoll_weight) { - dev_info(cfgdev, - "Current IRQ poll weight has the same weight.\n"); - return -EINVAL; - } - - if (afu_is_irqpoll_enabled(afu)) { - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - irq_poll_disable(&hwq->irqpoll); - } - } - - afu->irqpoll_weight = weight; - - if (weight > 0) { - for (i = 0; i < afu->num_hwqs; i++) { - hwq = get_hwq(afu, i); - - irq_poll_init(&hwq->irqpoll, weight, cxlflash_irqpoll); - } - } - - return count; -} - -/** - * num_hwqs_show() - presents the number of hardware queues for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the number of hardware queues. - * @buf: Buffer of length PAGE_SIZE to report back the number of hardware - * queues in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t num_hwqs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - - return scnprintf(buf, PAGE_SIZE, "%u\n", afu->num_hwqs); -} - -/** - * num_hwqs_store() - sets the number of hardware queues for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the number of hardware queues. - * @buf: Buffer of length PAGE_SIZE containing the number of hardware - * queues in ASCII. - * @count: Length of data resizing in @buf. - * - * n > 0: num_hwqs = n - * n = 0: num_hwqs = num_online_cpus() - * n < 0: num_online_cpus() / abs(n) - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t num_hwqs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - int rc; - int nhwqs, num_hwqs; - - rc = kstrtoint(buf, 10, &nhwqs); - if (rc) - return -EINVAL; - - if (nhwqs >= 1) - num_hwqs = nhwqs; - else if (nhwqs == 0) - num_hwqs = num_online_cpus(); - else - num_hwqs = num_online_cpus() / abs(nhwqs); - - afu->desired_hwqs = min(num_hwqs, CXLFLASH_MAX_HWQS); - WARN_ON_ONCE(afu->desired_hwqs == 0); - -retry: - switch (cfg->state) { - case STATE_NORMAL: - cfg->state = STATE_RESET; - drain_ioctls(cfg); - cxlflash_mark_contexts_error(cfg); - rc = afu_reset(cfg); - if (rc) - cfg->state = STATE_FAILTERM; - else - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->reset_waitq); - break; - case STATE_RESET: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - if (cfg->state == STATE_NORMAL) - goto retry; - fallthrough; - default: - /* Ideally should not happen */ - dev_err(dev, "%s: Device is not ready, state=%d\n", - __func__, cfg->state); - break; - } - - return count; -} - -static const char *hwq_mode_name[MAX_HWQ_MODE] = { "rr", "tag", "cpu" }; - -/** - * hwq_mode_show() - presents the HWQ steering mode for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the HWQ steering mode. - * @buf: Buffer of length PAGE_SIZE to report back the HWQ steering mode - * as a character string. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t hwq_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); - struct afu *afu = cfg->afu; - - return scnprintf(buf, PAGE_SIZE, "%s\n", hwq_mode_name[afu->hwq_mode]); -} - -/** - * hwq_mode_store() - sets the HWQ steering mode for the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the HWQ steering mode. - * @buf: Buffer of length PAGE_SIZE containing the HWQ steering mode - * as a character string. - * @count: Length of data resizing in @buf. - * - * rr = Round-Robin - * tag = Block MQ Tagging - * cpu = CPU Affinity - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t hwq_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = shost_priv(shost); - struct device *cfgdev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - int i; - u32 mode = MAX_HWQ_MODE; - - for (i = 0; i < MAX_HWQ_MODE; i++) { - if (!strncmp(hwq_mode_name[i], buf, strlen(hwq_mode_name[i]))) { - mode = i; - break; - } - } - - if (mode >= MAX_HWQ_MODE) { - dev_info(cfgdev, "Invalid HWQ steering mode.\n"); - return -EINVAL; - } - - afu->hwq_mode = mode; - - return count; -} - -/** - * mode_show() - presents the current mode of the device - * @dev: Generic device associated with the device. - * @attr: Device attribute representing the device mode. - * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - return scnprintf(buf, PAGE_SIZE, "%s\n", - sdev->hostdata ? "superpipe" : "legacy"); -} - -/* - * Host attributes - */ -static DEVICE_ATTR_RO(port0); -static DEVICE_ATTR_RO(port1); -static DEVICE_ATTR_RO(port2); -static DEVICE_ATTR_RO(port3); -static DEVICE_ATTR_RW(lun_mode); -static DEVICE_ATTR_RO(ioctl_version); -static DEVICE_ATTR_RO(port0_lun_table); -static DEVICE_ATTR_RO(port1_lun_table); -static DEVICE_ATTR_RO(port2_lun_table); -static DEVICE_ATTR_RO(port3_lun_table); -static DEVICE_ATTR_RW(irqpoll_weight); -static DEVICE_ATTR_RW(num_hwqs); -static DEVICE_ATTR_RW(hwq_mode); - -static struct attribute *cxlflash_host_attrs[] = { - &dev_attr_port0.attr, - &dev_attr_port1.attr, - &dev_attr_port2.attr, - &dev_attr_port3.attr, - &dev_attr_lun_mode.attr, - &dev_attr_ioctl_version.attr, - &dev_attr_port0_lun_table.attr, - &dev_attr_port1_lun_table.attr, - &dev_attr_port2_lun_table.attr, - &dev_attr_port3_lun_table.attr, - &dev_attr_irqpoll_weight.attr, - &dev_attr_num_hwqs.attr, - &dev_attr_hwq_mode.attr, - NULL -}; - -ATTRIBUTE_GROUPS(cxlflash_host); - -/* - * Device attributes - */ -static DEVICE_ATTR_RO(mode); - -static struct attribute *cxlflash_dev_attrs[] = { - &dev_attr_mode.attr, - NULL -}; - -ATTRIBUTE_GROUPS(cxlflash_dev); - -/* - * Host template - */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = CXLFLASH_ADAPTER_NAME, - .info = cxlflash_driver_info, - .ioctl = cxlflash_ioctl, - .proc_name = CXLFLASH_NAME, - .queuecommand = cxlflash_queuecommand, - .eh_abort_handler = cxlflash_eh_abort_handler, - .eh_device_reset_handler = cxlflash_eh_device_reset_handler, - .eh_host_reset_handler = cxlflash_eh_host_reset_handler, - .change_queue_depth = cxlflash_change_queue_depth, - .cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN, - .can_queue = CXLFLASH_MAX_CMDS, - .cmd_size = sizeof(struct afu_cmd) + __alignof__(struct afu_cmd) - 1, - .this_id = -1, - .sg_tablesize = 1, /* No scatter gather support */ - .max_sectors = CXLFLASH_MAX_SECTORS, - .shost_groups = cxlflash_host_groups, - .sdev_groups = cxlflash_dev_groups, -}; - -/* - * Device dependent values - */ -static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, - CXLFLASH_WWPN_VPD_REQUIRED }; -static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, - CXLFLASH_NOTIFY_SHUTDOWN }; -static struct dev_dependent_vals dev_briard_vals = { CXLFLASH_MAX_SECTORS, - (CXLFLASH_NOTIFY_SHUTDOWN | - CXLFLASH_OCXL_DEV) }; - -/* - * PCI device binding table - */ -static const struct pci_device_id cxlflash_pci_table[] = { - {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, - {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals}, - {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_BRIARD, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_briard_vals}, - {} -}; - -MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); - -/** - * cxlflash_worker_thread() - work thread handler for the AFU - * @work: Work structure contained within cxlflash associated with host. - * - * Handles the following events: - * - Link reset which cannot be performed on interrupt context due to - * blocking up to a few seconds - * - Rescan the host - */ -static void cxlflash_worker_thread(struct work_struct *work) -{ - struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, - work_q); - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - __be64 __iomem *fc_port_regs; - int port; - ulong lock_flags; - - /* Avoid MMIO if the device has failed */ - - if (cfg->state != STATE_NORMAL) - return; - - spin_lock_irqsave(cfg->host->host_lock, lock_flags); - - if (cfg->lr_state == LINK_RESET_REQUIRED) { - port = cfg->lr_port; - if (port < 0) - dev_err(dev, "%s: invalid port index %d\n", - __func__, port); - else { - spin_unlock_irqrestore(cfg->host->host_lock, - lock_flags); - - /* The reset can block... */ - fc_port_regs = get_fc_port_regs(cfg, port); - afu_link_reset(afu, port, fc_port_regs); - spin_lock_irqsave(cfg->host->host_lock, lock_flags); - } - - cfg->lr_state = LINK_RESET_COMPLETE; - } - - spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); - - if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) - scsi_scan_host(cfg->host); -} - -/** - * cxlflash_chr_open() - character device open handler - * @inode: Device inode associated with this character device. - * @file: File pointer for this device. - * - * Only users with admin privileges are allowed to open the character device. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_chr_open(struct inode *inode, struct file *file) -{ - struct cxlflash_cfg *cfg; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - cfg = container_of(inode->i_cdev, struct cxlflash_cfg, cdev); - file->private_data = cfg; - - return 0; -} - -/** - * decode_hioctl() - translates encoded host ioctl to easily identifiable string - * @cmd: The host ioctl command to decode. - * - * Return: A string identifying the decoded host ioctl. - */ -static char *decode_hioctl(unsigned int cmd) -{ - switch (cmd) { - case HT_CXLFLASH_LUN_PROVISION: - return __stringify_1(HT_CXLFLASH_LUN_PROVISION); - } - - return "UNKNOWN"; -} - -/** - * cxlflash_lun_provision() - host LUN provisioning handler - * @cfg: Internal structure associated with the host. - * @arg: Kernel copy of userspace ioctl data structure. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_lun_provision(struct cxlflash_cfg *cfg, void *arg) -{ - struct ht_cxlflash_lun_provision *lunprov = arg; - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct sisl_ioarcb rcb; - struct sisl_ioasa asa; - __be64 __iomem *fc_port_regs; - u16 port = lunprov->port; - u16 scmd = lunprov->hdr.subcmd; - u16 type; - u64 reg; - u64 size; - u64 lun_id; - int rc = 0; - - if (!afu_is_lun_provision(afu)) { - rc = -ENOTSUPP; - goto out; - } - - if (port >= cfg->num_fc_ports) { - rc = -EINVAL; - goto out; - } - - switch (scmd) { - case HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN: - type = SISL_AFU_LUN_PROVISION_CREATE; - size = lunprov->size; - lun_id = 0; - break; - case HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN: - type = SISL_AFU_LUN_PROVISION_DELETE; - size = 0; - lun_id = lunprov->lun_id; - break; - case HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT: - fc_port_regs = get_fc_port_regs(cfg, port); - - reg = readq_be(&fc_port_regs[FC_MAX_NUM_LUNS / 8]); - lunprov->max_num_luns = reg; - reg = readq_be(&fc_port_regs[FC_CUR_NUM_LUNS / 8]); - lunprov->cur_num_luns = reg; - reg = readq_be(&fc_port_regs[FC_MAX_CAP_PORT / 8]); - lunprov->max_cap_port = reg; - reg = readq_be(&fc_port_regs[FC_CUR_CAP_PORT / 8]); - lunprov->cur_cap_port = reg; - - goto out; - default: - rc = -EINVAL; - goto out; - } - - memset(&rcb, 0, sizeof(rcb)); - memset(&asa, 0, sizeof(asa)); - rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; - rcb.lun_id = lun_id; - rcb.msi = SISL_MSI_RRQ_UPDATED; - rcb.timeout = MC_LUN_PROV_TIMEOUT; - rcb.ioasa = &asa; - - rcb.cdb[0] = SISL_AFU_CMD_LUN_PROVISION; - rcb.cdb[1] = type; - rcb.cdb[2] = port; - put_unaligned_be64(size, &rcb.cdb[8]); - - rc = send_afu_cmd(afu, &rcb); - if (rc) { - dev_err(dev, "%s: send_afu_cmd failed rc=%d asc=%08x afux=%x\n", - __func__, rc, asa.ioasc, asa.afu_extra); - goto out; - } - - if (scmd == HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN) { - lunprov->lun_id = (u64)asa.lunid_hi << 32 | asa.lunid_lo; - memcpy(lunprov->wwid, asa.wwid, sizeof(lunprov->wwid)); - } -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_afu_debug() - host AFU debug handler - * @cfg: Internal structure associated with the host. - * @arg: Kernel copy of userspace ioctl data structure. - * - * For debug requests requiring a data buffer, always provide an aligned - * (cache line) buffer to the AFU to appease any alignment requirements. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_afu_debug(struct cxlflash_cfg *cfg, void *arg) -{ - struct ht_cxlflash_afu_debug *afu_dbg = arg; - struct afu *afu = cfg->afu; - struct device *dev = &cfg->dev->dev; - struct sisl_ioarcb rcb; - struct sisl_ioasa asa; - char *buf = NULL; - char *kbuf = NULL; - void __user *ubuf = (__force void __user *)afu_dbg->data_ea; - u16 req_flags = SISL_REQ_FLAGS_AFU_CMD; - u32 ulen = afu_dbg->data_len; - bool is_write = afu_dbg->hdr.flags & HT_CXLFLASH_HOST_WRITE; - int rc = 0; - - if (!afu_is_afu_debug(afu)) { - rc = -ENOTSUPP; - goto out; - } - - if (ulen) { - req_flags |= SISL_REQ_FLAGS_SUP_UNDERRUN; - - if (ulen > HT_CXLFLASH_AFU_DEBUG_MAX_DATA_LEN) { - rc = -EINVAL; - goto out; - } - - buf = kmalloc(ulen + cache_line_size() - 1, GFP_KERNEL); - if (unlikely(!buf)) { - rc = -ENOMEM; - goto out; - } - - kbuf = PTR_ALIGN(buf, cache_line_size()); - - if (is_write) { - req_flags |= SISL_REQ_FLAGS_HOST_WRITE; - - if (copy_from_user(kbuf, ubuf, ulen)) { - rc = -EFAULT; - goto out; - } - } - } - - memset(&rcb, 0, sizeof(rcb)); - memset(&asa, 0, sizeof(asa)); - - rcb.req_flags = req_flags; - rcb.msi = SISL_MSI_RRQ_UPDATED; - rcb.timeout = MC_AFU_DEBUG_TIMEOUT; - rcb.ioasa = &asa; - - if (ulen) { - rcb.data_len = ulen; - rcb.data_ea = (uintptr_t)kbuf; - } - - rcb.cdb[0] = SISL_AFU_CMD_DEBUG; - memcpy(&rcb.cdb[4], afu_dbg->afu_subcmd, - HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN); - - rc = send_afu_cmd(afu, &rcb); - if (rc) { - dev_err(dev, "%s: send_afu_cmd failed rc=%d asc=%08x afux=%x\n", - __func__, rc, asa.ioasc, asa.afu_extra); - goto out; - } - - if (ulen && !is_write) { - if (copy_to_user(ubuf, kbuf, ulen)) - rc = -EFAULT; - } -out: - kfree(buf); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_chr_ioctl() - character device IOCTL handler - * @file: File pointer for this device. - * @cmd: IOCTL command. - * @arg: Userspace ioctl data structure. - * - * A read/write semaphore is used to implement a 'drain' of currently - * running ioctls. The read semaphore is taken at the beginning of each - * ioctl thread and released upon concluding execution. Additionally the - * semaphore should be released and then reacquired in any ioctl execution - * path which will wait for an event to occur that is outside the scope of - * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, - * a thread simply needs to acquire the write semaphore. - * - * Return: 0 on success, -errno on failure - */ -static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - typedef int (*hioctl) (struct cxlflash_cfg *, void *); - - struct cxlflash_cfg *cfg = file->private_data; - struct device *dev = &cfg->dev->dev; - char buf[sizeof(union cxlflash_ht_ioctls)]; - void __user *uarg = (void __user *)arg; - struct ht_cxlflash_hdr *hdr; - size_t size = 0; - bool known_ioctl = false; - int idx = 0; - int rc = 0; - hioctl do_ioctl = NULL; - - static const struct { - size_t size; - hioctl ioctl; - } ioctl_tbl[] = { /* NOTE: order matters here */ - { sizeof(struct ht_cxlflash_lun_provision), cxlflash_lun_provision }, - { sizeof(struct ht_cxlflash_afu_debug), cxlflash_afu_debug }, - }; - - /* Hold read semaphore so we can drain if needed */ - down_read(&cfg->ioctl_rwsem); - - dev_dbg(dev, "%s: cmd=%u idx=%d tbl_size=%lu\n", - __func__, cmd, idx, sizeof(ioctl_tbl)); - - switch (cmd) { - case HT_CXLFLASH_LUN_PROVISION: - case HT_CXLFLASH_AFU_DEBUG: - known_ioctl = true; - idx = _IOC_NR(HT_CXLFLASH_LUN_PROVISION) - _IOC_NR(cmd); - size = ioctl_tbl[idx].size; - do_ioctl = ioctl_tbl[idx].ioctl; - - if (likely(do_ioctl)) - break; - - fallthrough; - default: - rc = -EINVAL; - goto out; - } - - if (unlikely(copy_from_user(&buf, uarg, size))) { - dev_err(dev, "%s: copy_from_user() fail " - "size=%lu cmd=%d (%s) uarg=%p\n", - __func__, size, cmd, decode_hioctl(cmd), uarg); - rc = -EFAULT; - goto out; - } - - hdr = (struct ht_cxlflash_hdr *)&buf; - if (hdr->version != HT_CXLFLASH_VERSION_0) { - dev_dbg(dev, "%s: Version %u not supported for %s\n", - __func__, hdr->version, decode_hioctl(cmd)); - rc = -EINVAL; - goto out; - } - - if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->return_flags) { - dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); - rc = -EINVAL; - goto out; - } - - rc = do_ioctl(cfg, (void *)&buf); - if (likely(!rc)) - if (unlikely(copy_to_user(uarg, &buf, size))) { - dev_err(dev, "%s: copy_to_user() fail " - "size=%lu cmd=%d (%s) uarg=%p\n", - __func__, size, cmd, decode_hioctl(cmd), uarg); - rc = -EFAULT; - } - - /* fall through to exit */ - -out: - up_read(&cfg->ioctl_rwsem); - if (unlikely(rc && known_ioctl)) - dev_err(dev, "%s: ioctl %s (%08X) returned rc=%d\n", - __func__, decode_hioctl(cmd), cmd, rc); - else - dev_dbg(dev, "%s: ioctl %s (%08X) returned rc=%d\n", - __func__, decode_hioctl(cmd), cmd, rc); - return rc; -} - -/* - * Character device file operations - */ -static const struct file_operations cxlflash_chr_fops = { - .owner = THIS_MODULE, - .open = cxlflash_chr_open, - .unlocked_ioctl = cxlflash_chr_ioctl, - .compat_ioctl = compat_ptr_ioctl, -}; - -/** - * init_chrdev() - initialize the character device for the host - * @cfg: Internal structure associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int init_chrdev(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - struct device *char_dev; - dev_t devno; - int minor; - int rc = 0; - - minor = cxlflash_get_minor(); - if (unlikely(minor < 0)) { - dev_err(dev, "%s: Exhausted allowed adapters\n", __func__); - rc = -ENOSPC; - goto out; - } - - devno = MKDEV(cxlflash_major, minor); - cdev_init(&cfg->cdev, &cxlflash_chr_fops); - - rc = cdev_add(&cfg->cdev, devno, 1); - if (rc) { - dev_err(dev, "%s: cdev_add failed rc=%d\n", __func__, rc); - goto err1; - } - - char_dev = device_create(&cxlflash_class, NULL, devno, - NULL, "cxlflash%d", minor); - if (IS_ERR(char_dev)) { - rc = PTR_ERR(char_dev); - dev_err(dev, "%s: device_create failed rc=%d\n", - __func__, rc); - goto err2; - } - - cfg->chardev = char_dev; -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -err2: - cdev_del(&cfg->cdev); -err1: - cxlflash_put_minor(minor); - goto out; -} - -/** - * cxlflash_probe() - PCI entry point to add host - * @pdev: PCI device associated with the host. - * @dev_id: PCI device id associated with device. - * - * The device will initially start out in a 'probing' state and - * transition to the 'normal' state at the end of a successful - * probe. Should an EEH event occur during probe, the notification - * thread (error_detected()) will wait until the probe handler - * is nearly complete. At that time, the device will be moved to - * a 'probed' state and the EEH thread woken up to drive the slot - * reset and recovery (device moves to 'normal' state). Meanwhile, - * the probe will be allowed to exit successfully. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_probe(struct pci_dev *pdev, - const struct pci_device_id *dev_id) -{ - struct Scsi_Host *host; - struct cxlflash_cfg *cfg = NULL; - struct device *dev = &pdev->dev; - struct dev_dependent_vals *ddv; - int rc = 0; - int k; - - dev_err_once(&pdev->dev, "DEPRECATION: cxlflash is deprecated and will be removed in a future kernel release\n"); - - dev_dbg(&pdev->dev, "%s: Found CXLFLASH with IRQ: %d\n", - __func__, pdev->irq); - - ddv = (struct dev_dependent_vals *)dev_id->driver_data; - driver_template.max_sectors = ddv->max_sectors; - - host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg)); - if (!host) { - dev_err(dev, "%s: scsi_host_alloc failed\n", __func__); - rc = -ENOMEM; - goto out; - } - - host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; - host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; - host->unique_id = host->host_no; - host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; - - cfg = shost_priv(host); - cfg->state = STATE_PROBING; - cfg->host = host; - rc = alloc_mem(cfg); - if (rc) { - dev_err(dev, "%s: alloc_mem failed\n", __func__); - rc = -ENOMEM; - scsi_host_put(cfg->host); - goto out; - } - - cfg->init_state = INIT_STATE_NONE; - cfg->dev = pdev; - cfg->cxl_fops = cxlflash_cxl_fops; - cfg->ops = cxlflash_assign_ops(ddv); - WARN_ON_ONCE(!cfg->ops); - - /* - * Promoted LUNs move to the top of the LUN table. The rest stay on - * the bottom half. The bottom half grows from the end (index = 255), - * whereas the top half grows from the beginning (index = 0). - * - * Initialize the last LUN index for all possible ports. - */ - cfg->promote_lun_index = 0; - - for (k = 0; k < MAX_FC_PORTS; k++) - cfg->last_lun_index[k] = CXLFLASH_NUM_VLUNS/2 - 1; - - cfg->dev_id = (struct pci_device_id *)dev_id; - - init_waitqueue_head(&cfg->tmf_waitq); - init_waitqueue_head(&cfg->reset_waitq); - - INIT_WORK(&cfg->work_q, cxlflash_worker_thread); - cfg->lr_state = LINK_RESET_INVALID; - cfg->lr_port = -1; - spin_lock_init(&cfg->tmf_slock); - mutex_init(&cfg->ctx_tbl_list_mutex); - mutex_init(&cfg->ctx_recovery_mutex); - init_rwsem(&cfg->ioctl_rwsem); - INIT_LIST_HEAD(&cfg->ctx_err_recovery); - INIT_LIST_HEAD(&cfg->lluns); - - pci_set_drvdata(pdev, cfg); - - rc = init_pci(cfg); - if (rc) { - dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc); - goto out_remove; - } - cfg->init_state = INIT_STATE_PCI; - - cfg->afu_cookie = cfg->ops->create_afu(pdev); - if (unlikely(!cfg->afu_cookie)) { - dev_err(dev, "%s: create_afu failed\n", __func__); - rc = -ENOMEM; - goto out_remove; - } - - rc = init_afu(cfg); - if (rc && !wq_has_sleeper(&cfg->reset_waitq)) { - dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc); - goto out_remove; - } - cfg->init_state = INIT_STATE_AFU; - - rc = init_scsi(cfg); - if (rc) { - dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc); - goto out_remove; - } - cfg->init_state = INIT_STATE_SCSI; - - rc = init_chrdev(cfg); - if (rc) { - dev_err(dev, "%s: init_chrdev failed rc=%d\n", __func__, rc); - goto out_remove; - } - cfg->init_state = INIT_STATE_CDEV; - - if (wq_has_sleeper(&cfg->reset_waitq)) { - cfg->state = STATE_PROBED; - wake_up_all(&cfg->reset_waitq); - } else - cfg->state = STATE_NORMAL; -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; - -out_remove: - cfg->state = STATE_PROBED; - cxlflash_remove(pdev); - goto out; -} - -/** - * cxlflash_pci_error_detected() - called when a PCI error is detected - * @pdev: PCI device struct. - * @state: PCI channel state. - * - * When an EEH occurs during an active reset, wait until the reset is - * complete and then take action based upon the device state. - * - * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - int rc = 0; - struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); - struct device *dev = &cfg->dev->dev; - - dev_dbg(dev, "%s: pdev=%p state=%u\n", __func__, pdev, state); - - switch (state) { - case pci_channel_io_frozen: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && - cfg->state != STATE_PROBING); - if (cfg->state == STATE_FAILTERM) - return PCI_ERS_RESULT_DISCONNECT; - - cfg->state = STATE_RESET; - scsi_block_requests(cfg->host); - drain_ioctls(cfg); - rc = cxlflash_mark_contexts_error(cfg); - if (unlikely(rc)) - dev_err(dev, "%s: Failed to mark user contexts rc=%d\n", - __func__, rc); - term_afu(cfg); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - cfg->state = STATE_FAILTERM; - wake_up_all(&cfg->reset_waitq); - scsi_unblock_requests(cfg->host); - return PCI_ERS_RESULT_DISCONNECT; - default: - break; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * cxlflash_pci_slot_reset() - called when PCI slot has been reset - * @pdev: PCI device struct. - * - * This routine is called by the pci error recovery code after the PCI - * slot has been reset, just before we should resume normal operations. - * - * Return: PCI_ERS_RESULT_RECOVERED or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) -{ - int rc = 0; - struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); - struct device *dev = &cfg->dev->dev; - - dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); - - rc = init_afu(cfg); - if (unlikely(rc)) { - dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc); - return PCI_ERS_RESULT_DISCONNECT; - } - - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * cxlflash_pci_resume() - called when normal operation can resume - * @pdev: PCI device struct - */ -static void cxlflash_pci_resume(struct pci_dev *pdev) -{ - struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); - struct device *dev = &cfg->dev->dev; - - dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); - - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->reset_waitq); - scsi_unblock_requests(cfg->host); -} - -/** - * cxlflash_devnode() - provides devtmpfs for devices in the cxlflash class - * @dev: Character device. - * @mode: Mode that can be used to verify access. - * - * Return: Allocated string describing the devtmpfs structure. - */ -static char *cxlflash_devnode(const struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "cxlflash/%s", dev_name(dev)); -} - -/** - * cxlflash_class_init() - create character device class - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_class_init(void) -{ - dev_t devno; - int rc = 0; - - rc = alloc_chrdev_region(&devno, 0, CXLFLASH_MAX_ADAPTERS, "cxlflash"); - if (unlikely(rc)) { - pr_err("%s: alloc_chrdev_region failed rc=%d\n", __func__, rc); - goto out; - } - - cxlflash_major = MAJOR(devno); - - rc = class_register(&cxlflash_class); - if (rc) { - pr_err("%s: class_create failed rc=%d\n", __func__, rc); - goto err; - } - -out: - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; -err: - unregister_chrdev_region(devno, CXLFLASH_MAX_ADAPTERS); - goto out; -} - -/** - * cxlflash_class_exit() - destroy character device class - */ -static void cxlflash_class_exit(void) -{ - dev_t devno = MKDEV(cxlflash_major, 0); - - class_unregister(&cxlflash_class); - unregister_chrdev_region(devno, CXLFLASH_MAX_ADAPTERS); -} - -static const struct pci_error_handlers cxlflash_err_handler = { - .error_detected = cxlflash_pci_error_detected, - .slot_reset = cxlflash_pci_slot_reset, - .resume = cxlflash_pci_resume, -}; - -/* - * PCI device structure - */ -static struct pci_driver cxlflash_driver = { - .name = CXLFLASH_NAME, - .id_table = cxlflash_pci_table, - .probe = cxlflash_probe, - .remove = cxlflash_remove, - .shutdown = cxlflash_remove, - .err_handler = &cxlflash_err_handler, -}; - -/** - * init_cxlflash() - module entry point - * - * Return: 0 on success, -errno on failure - */ -static int __init init_cxlflash(void) -{ - int rc; - - check_sizes(); - cxlflash_list_init(); - rc = cxlflash_class_init(); - if (unlikely(rc)) - goto out; - - rc = pci_register_driver(&cxlflash_driver); - if (unlikely(rc)) - goto err; -out: - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; -err: - cxlflash_class_exit(); - goto out; -} - -/** - * exit_cxlflash() - module exit point - */ -static void __exit exit_cxlflash(void) -{ - cxlflash_term_global_luns(); - cxlflash_free_errpage(); - - pci_unregister_driver(&cxlflash_driver); - cxlflash_class_exit(); -} - -module_init(init_cxlflash); -module_exit(exit_cxlflash); diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h deleted file mode 100644 index 0bfb98effce0..000000000000 --- a/drivers/scsi/cxlflash/main.h +++ /dev/null @@ -1,129 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#ifndef _CXLFLASH_MAIN_H -#define _CXLFLASH_MAIN_H - -#include <linux/list.h> -#include <linux/types.h> -#include <scsi/scsi.h> -#include <scsi/scsi_device.h> - -#include "backend.h" - -#define CXLFLASH_NAME "cxlflash" -#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" -#define CXLFLASH_MAX_ADAPTERS 32 - -#define PCI_DEVICE_ID_IBM_CORSA 0x04F0 -#define PCI_DEVICE_ID_IBM_FLASH_GT 0x0600 -#define PCI_DEVICE_ID_IBM_BRIARD 0x0624 - -/* Since there is only one target, make it 0 */ -#define CXLFLASH_TARGET 0 -#define CXLFLASH_MAX_CDB_LEN 16 - -/* Really only one target per bus since the Texan is directly attached */ -#define CXLFLASH_MAX_NUM_TARGETS_PER_BUS 1 -#define CXLFLASH_MAX_NUM_LUNS_PER_TARGET 65536 - -#define CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ) - -/* FC defines */ -#define FC_MTIP_CMDCONFIG 0x010 -#define FC_MTIP_STATUS 0x018 -#define FC_MAX_NUM_LUNS 0x080 /* Max LUNs host can provision for port */ -#define FC_CUR_NUM_LUNS 0x088 /* Cur number LUNs provisioned for port */ -#define FC_MAX_CAP_PORT 0x090 /* Max capacity all LUNs for port (4K blocks) */ -#define FC_CUR_CAP_PORT 0x098 /* Cur capacity all LUNs for port (4K blocks) */ - -#define FC_PNAME 0x300 -#define FC_CONFIG 0x320 -#define FC_CONFIG2 0x328 -#define FC_STATUS 0x330 -#define FC_ERROR 0x380 -#define FC_ERRCAP 0x388 -#define FC_ERRMSK 0x390 -#define FC_CNT_CRCERR 0x538 -#define FC_CRC_THRESH 0x580 - -#define FC_MTIP_CMDCONFIG_ONLINE 0x20ULL -#define FC_MTIP_CMDCONFIG_OFFLINE 0x40ULL - -#define FC_MTIP_STATUS_MASK 0x30ULL -#define FC_MTIP_STATUS_ONLINE 0x20ULL -#define FC_MTIP_STATUS_OFFLINE 0x10ULL - -/* TIMEOUT and RETRY definitions */ - -/* AFU command timeout values */ -#define MC_AFU_SYNC_TIMEOUT 5 /* 5 secs */ -#define MC_LUN_PROV_TIMEOUT 5 /* 5 secs */ -#define MC_AFU_DEBUG_TIMEOUT 5 /* 5 secs */ - -/* AFU command room retry limit */ -#define MC_ROOM_RETRY_CNT 10 - -/* FC CRC clear periodic timer */ -#define MC_CRC_THRESH 100 /* threshold in 5 mins */ - -#define FC_PORT_STATUS_RETRY_CNT 100 /* 100 100ms retries = 10 seconds */ -#define FC_PORT_STATUS_RETRY_INTERVAL_US 100000 /* microseconds */ - -/* VPD defines */ -#define CXLFLASH_VPD_LEN 256 -#define WWPN_LEN 16 -#define WWPN_BUF_LEN (WWPN_LEN + 1) - -enum undo_level { - UNDO_NOOP = 0, - FREE_IRQ, - UNMAP_ONE, - UNMAP_TWO, - UNMAP_THREE -}; - -struct dev_dependent_vals { - u64 max_sectors; - u64 flags; -#define CXLFLASH_NOTIFY_SHUTDOWN 0x0000000000000001ULL -#define CXLFLASH_WWPN_VPD_REQUIRED 0x0000000000000002ULL -#define CXLFLASH_OCXL_DEV 0x0000000000000004ULL -}; - -static inline const struct cxlflash_backend_ops * -cxlflash_assign_ops(struct dev_dependent_vals *ddv) -{ - const struct cxlflash_backend_ops *ops = NULL; - -#ifdef CONFIG_OCXL_BASE - if (ddv->flags & CXLFLASH_OCXL_DEV) - ops = &cxlflash_ocxl_ops; -#endif - -#ifdef CONFIG_CXL_BASE - if (!(ddv->flags & CXLFLASH_OCXL_DEV)) - ops = &cxlflash_cxl_ops; -#endif - - return ops; -} - -struct asyc_intr_info { - u64 status; - char *desc; - u8 port; - u8 action; -#define CLR_FC_ERROR 0x01 -#define LINK_RESET 0x02 -#define SCAN_HOST 0x04 -}; - -#endif /* _CXLFLASH_MAIN_H */ diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c deleted file mode 100644 index 6542818e595a..000000000000 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ /dev/null @@ -1,1399 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2018 IBM Corporation - */ - -#include <linux/file.h> -#include <linux/idr.h> -#include <linux/module.h> -#include <linux/mount.h> -#include <linux/pseudo_fs.h> -#include <linux/poll.h> -#include <linux/sched/signal.h> -#include <linux/interrupt.h> -#include <linux/irqdomain.h> -#include <asm/xive.h> -#include <misc/ocxl.h> - -#include <uapi/misc/cxl.h> - -#include "backend.h" -#include "ocxl_hw.h" - -/* - * Pseudo-filesystem to allocate inodes. - */ - -#define OCXLFLASH_FS_MAGIC 0x1697698f - -static int ocxlflash_fs_cnt; -static struct vfsmount *ocxlflash_vfs_mount; - -static int ocxlflash_fs_init_fs_context(struct fs_context *fc) -{ - return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM; -} - -static struct file_system_type ocxlflash_fs_type = { - .name = "ocxlflash", - .owner = THIS_MODULE, - .init_fs_context = ocxlflash_fs_init_fs_context, - .kill_sb = kill_anon_super, -}; - -/* - * ocxlflash_release_mapping() - release the memory mapping - * @ctx: Context whose mapping is to be released. - */ -static void ocxlflash_release_mapping(struct ocxlflash_context *ctx) -{ - if (ctx->mapping) - simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); - ctx->mapping = NULL; -} - -/* - * ocxlflash_getfile() - allocate pseudo filesystem, inode, and the file - * @dev: Generic device of the host. - * @name: Name of the pseudo filesystem. - * @fops: File operations. - * @priv: Private data. - * @flags: Flags for the file. - * - * Return: pointer to the file on success, ERR_PTR on failure - */ -static struct file *ocxlflash_getfile(struct device *dev, const char *name, - const struct file_operations *fops, - void *priv, int flags) -{ - struct file *file; - struct inode *inode; - int rc; - - if (fops->owner && !try_module_get(fops->owner)) { - dev_err(dev, "%s: Owner does not exist\n", __func__); - rc = -ENOENT; - goto err1; - } - - rc = simple_pin_fs(&ocxlflash_fs_type, &ocxlflash_vfs_mount, - &ocxlflash_fs_cnt); - if (unlikely(rc < 0)) { - dev_err(dev, "%s: Cannot mount ocxlflash pseudofs rc=%d\n", - __func__, rc); - goto err2; - } - - inode = alloc_anon_inode(ocxlflash_vfs_mount->mnt_sb); - if (IS_ERR(inode)) { - rc = PTR_ERR(inode); - dev_err(dev, "%s: alloc_anon_inode failed rc=%d\n", - __func__, rc); - goto err3; - } - - file = alloc_file_pseudo(inode, ocxlflash_vfs_mount, name, - flags & (O_ACCMODE | O_NONBLOCK), fops); - if (IS_ERR(file)) { - rc = PTR_ERR(file); - dev_err(dev, "%s: alloc_file failed rc=%d\n", - __func__, rc); - goto err4; - } - - file->private_data = priv; -out: - return file; -err4: - iput(inode); -err3: - simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); -err2: - module_put(fops->owner); -err1: - file = ERR_PTR(rc); - goto out; -} - -/** - * ocxlflash_psa_map() - map the process specific MMIO space - * @ctx_cookie: Adapter context for which the mapping needs to be done. - * - * Return: MMIO pointer of the mapped region - */ -static void __iomem *ocxlflash_psa_map(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct device *dev = ctx->hw_afu->dev; - - mutex_lock(&ctx->state_mutex); - if (ctx->state != STARTED) { - dev_err(dev, "%s: Context not started, state=%d\n", __func__, - ctx->state); - mutex_unlock(&ctx->state_mutex); - return NULL; - } - mutex_unlock(&ctx->state_mutex); - - return ioremap(ctx->psn_phys, ctx->psn_size); -} - -/** - * ocxlflash_psa_unmap() - unmap the process specific MMIO space - * @addr: MMIO pointer to unmap. - */ -static void ocxlflash_psa_unmap(void __iomem *addr) -{ - iounmap(addr); -} - -/** - * ocxlflash_process_element() - get process element of the adapter context - * @ctx_cookie: Adapter context associated with the process element. - * - * Return: process element of the adapter context - */ -static int ocxlflash_process_element(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - - return ctx->pe; -} - -/** - * afu_map_irq() - map the interrupt of the adapter context - * @flags: Flags. - * @ctx: Adapter context. - * @num: Per-context AFU interrupt number. - * @handler: Interrupt handler to register. - * @cookie: Interrupt handler private data. - * @name: Name of the interrupt. - * - * Return: 0 on success, -errno on failure - */ -static int afu_map_irq(u64 flags, struct ocxlflash_context *ctx, int num, - irq_handler_t handler, void *cookie, char *name) -{ - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct device *dev = afu->dev; - struct ocxlflash_irqs *irq; - struct xive_irq_data *xd; - u32 virq; - int rc = 0; - - if (num < 0 || num >= ctx->num_irqs) { - dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num); - rc = -ENOENT; - goto out; - } - - irq = &ctx->irqs[num]; - virq = irq_create_mapping(NULL, irq->hwirq); - if (unlikely(!virq)) { - dev_err(dev, "%s: irq_create_mapping failed\n", __func__); - rc = -ENOMEM; - goto out; - } - - rc = request_irq(virq, handler, 0, name, cookie); - if (unlikely(rc)) { - dev_err(dev, "%s: request_irq failed rc=%d\n", __func__, rc); - goto err1; - } - - xd = irq_get_handler_data(virq); - if (unlikely(!xd)) { - dev_err(dev, "%s: Can't get interrupt data\n", __func__); - rc = -ENXIO; - goto err2; - } - - irq->virq = virq; - irq->vtrig = xd->trig_mmio; -out: - return rc; -err2: - free_irq(virq, cookie); -err1: - irq_dispose_mapping(virq); - goto out; -} - -/** - * ocxlflash_map_afu_irq() - map the interrupt of the adapter context - * @ctx_cookie: Adapter context. - * @num: Per-context AFU interrupt number. - * @handler: Interrupt handler to register. - * @cookie: Interrupt handler private data. - * @name: Name of the interrupt. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_map_afu_irq(void *ctx_cookie, int num, - irq_handler_t handler, void *cookie, - char *name) -{ - return afu_map_irq(0, ctx_cookie, num, handler, cookie, name); -} - -/** - * afu_unmap_irq() - unmap the interrupt - * @flags: Flags. - * @ctx: Adapter context. - * @num: Per-context AFU interrupt number. - * @cookie: Interrupt handler private data. - */ -static void afu_unmap_irq(u64 flags, struct ocxlflash_context *ctx, int num, - void *cookie) -{ - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct device *dev = afu->dev; - struct ocxlflash_irqs *irq; - - if (num < 0 || num >= ctx->num_irqs) { - dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num); - return; - } - - irq = &ctx->irqs[num]; - - if (irq_find_mapping(NULL, irq->hwirq)) { - free_irq(irq->virq, cookie); - irq_dispose_mapping(irq->virq); - } - - memset(irq, 0, sizeof(*irq)); -} - -/** - * ocxlflash_unmap_afu_irq() - unmap the interrupt - * @ctx_cookie: Adapter context. - * @num: Per-context AFU interrupt number. - * @cookie: Interrupt handler private data. - */ -static void ocxlflash_unmap_afu_irq(void *ctx_cookie, int num, void *cookie) -{ - return afu_unmap_irq(0, ctx_cookie, num, cookie); -} - -/** - * ocxlflash_get_irq_objhndl() - get the object handle for an interrupt - * @ctx_cookie: Context associated with the interrupt. - * @irq: Interrupt number. - * - * Return: effective address of the mapped region - */ -static u64 ocxlflash_get_irq_objhndl(void *ctx_cookie, int irq) -{ - struct ocxlflash_context *ctx = ctx_cookie; - - if (irq < 0 || irq >= ctx->num_irqs) - return 0; - - return (__force u64)ctx->irqs[irq].vtrig; -} - -/** - * ocxlflash_xsl_fault() - callback when translation error is triggered - * @data: Private data provided at callback registration, the context. - * @addr: Address that triggered the error. - * @dsisr: Value of dsisr register. - */ -static void ocxlflash_xsl_fault(void *data, u64 addr, u64 dsisr) -{ - struct ocxlflash_context *ctx = data; - - spin_lock(&ctx->slock); - ctx->fault_addr = addr; - ctx->fault_dsisr = dsisr; - ctx->pending_fault = true; - spin_unlock(&ctx->slock); - - wake_up_all(&ctx->wq); -} - -/** - * start_context() - local routine to start a context - * @ctx: Adapter context to be started. - * - * Assign the context specific MMIO space, add and enable the PE. - * - * Return: 0 on success, -errno on failure - */ -static int start_context(struct ocxlflash_context *ctx) -{ - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct ocxl_afu_config *acfg = &afu->acfg; - void *link_token = afu->link_token; - struct pci_dev *pdev = afu->pdev; - struct device *dev = afu->dev; - bool master = ctx->master; - struct mm_struct *mm; - int rc = 0; - u32 pid; - - mutex_lock(&ctx->state_mutex); - if (ctx->state != OPENED) { - dev_err(dev, "%s: Context state invalid, state=%d\n", - __func__, ctx->state); - rc = -EINVAL; - goto out; - } - - if (master) { - ctx->psn_size = acfg->global_mmio_size; - ctx->psn_phys = afu->gmmio_phys; - } else { - ctx->psn_size = acfg->pp_mmio_stride; - ctx->psn_phys = afu->ppmmio_phys + (ctx->pe * ctx->psn_size); - } - - /* pid and mm not set for master contexts */ - if (master) { - pid = 0; - mm = NULL; - } else { - pid = current->mm->context.id; - mm = current->mm; - } - - rc = ocxl_link_add_pe(link_token, ctx->pe, pid, 0, 0, - pci_dev_id(pdev), mm, ocxlflash_xsl_fault, - ctx); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_link_add_pe failed rc=%d\n", - __func__, rc); - goto out; - } - - ctx->state = STARTED; -out: - mutex_unlock(&ctx->state_mutex); - return rc; -} - -/** - * ocxlflash_start_context() - start a kernel context - * @ctx_cookie: Adapter context to be started. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_start_context(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - - return start_context(ctx); -} - -/** - * ocxlflash_stop_context() - stop a context - * @ctx_cookie: Adapter context to be stopped. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_stop_context(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct ocxl_afu_config *acfg = &afu->acfg; - struct pci_dev *pdev = afu->pdev; - struct device *dev = afu->dev; - enum ocxlflash_ctx_state state; - int rc = 0; - - mutex_lock(&ctx->state_mutex); - state = ctx->state; - ctx->state = CLOSED; - mutex_unlock(&ctx->state_mutex); - if (state != STARTED) - goto out; - - rc = ocxl_config_terminate_pasid(pdev, acfg->dvsec_afu_control_pos, - ctx->pe); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_config_terminate_pasid failed rc=%d\n", - __func__, rc); - /* If EBUSY, PE could be referenced in future by the AFU */ - if (rc == -EBUSY) - goto out; - } - - rc = ocxl_link_remove_pe(afu->link_token, ctx->pe); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_link_remove_pe failed rc=%d\n", - __func__, rc); - goto out; - } -out: - return rc; -} - -/** - * ocxlflash_afu_reset() - reset the AFU - * @ctx_cookie: Adapter context. - */ -static int ocxlflash_afu_reset(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct device *dev = ctx->hw_afu->dev; - - /* Pending implementation from OCXL transport services */ - dev_err_once(dev, "%s: afu_reset() fop not supported\n", __func__); - - /* Silently return success until it is implemented */ - return 0; -} - -/** - * ocxlflash_set_master() - sets the context as master - * @ctx_cookie: Adapter context to set as master. - */ -static void ocxlflash_set_master(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - - ctx->master = true; -} - -/** - * ocxlflash_get_context() - obtains the context associated with the host - * @pdev: PCI device associated with the host. - * @afu_cookie: Hardware AFU associated with the host. - * - * Return: returns the pointer to host adapter context - */ -static void *ocxlflash_get_context(struct pci_dev *pdev, void *afu_cookie) -{ - struct ocxl_hw_afu *afu = afu_cookie; - - return afu->ocxl_ctx; -} - -/** - * ocxlflash_dev_context_init() - allocate and initialize an adapter context - * @pdev: PCI device associated with the host. - * @afu_cookie: Hardware AFU associated with the host. - * - * Return: returns the adapter context on success, ERR_PTR on failure - */ -static void *ocxlflash_dev_context_init(struct pci_dev *pdev, void *afu_cookie) -{ - struct ocxl_hw_afu *afu = afu_cookie; - struct device *dev = afu->dev; - struct ocxlflash_context *ctx; - int rc; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (unlikely(!ctx)) { - dev_err(dev, "%s: Context allocation failed\n", __func__); - rc = -ENOMEM; - goto err1; - } - - idr_preload(GFP_KERNEL); - rc = idr_alloc(&afu->idr, ctx, 0, afu->max_pasid, GFP_NOWAIT); - idr_preload_end(); - if (unlikely(rc < 0)) { - dev_err(dev, "%s: idr_alloc failed rc=%d\n", __func__, rc); - goto err2; - } - - spin_lock_init(&ctx->slock); - init_waitqueue_head(&ctx->wq); - mutex_init(&ctx->state_mutex); - - ctx->state = OPENED; - ctx->pe = rc; - ctx->master = false; - ctx->mapping = NULL; - ctx->hw_afu = afu; - ctx->irq_bitmap = 0; - ctx->pending_irq = false; - ctx->pending_fault = false; -out: - return ctx; -err2: - kfree(ctx); -err1: - ctx = ERR_PTR(rc); - goto out; -} - -/** - * ocxlflash_release_context() - releases an adapter context - * @ctx_cookie: Adapter context to be released. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_release_context(void *ctx_cookie) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct device *dev; - int rc = 0; - - if (!ctx) - goto out; - - dev = ctx->hw_afu->dev; - mutex_lock(&ctx->state_mutex); - if (ctx->state >= STARTED) { - dev_err(dev, "%s: Context in use, state=%d\n", __func__, - ctx->state); - mutex_unlock(&ctx->state_mutex); - rc = -EBUSY; - goto out; - } - mutex_unlock(&ctx->state_mutex); - - idr_remove(&ctx->hw_afu->idr, ctx->pe); - ocxlflash_release_mapping(ctx); - kfree(ctx); -out: - return rc; -} - -/** - * ocxlflash_perst_reloads_same_image() - sets the image reload policy - * @afu_cookie: Hardware AFU associated with the host. - * @image: Whether to load the same image on PERST. - */ -static void ocxlflash_perst_reloads_same_image(void *afu_cookie, bool image) -{ - struct ocxl_hw_afu *afu = afu_cookie; - - afu->perst_same_image = image; -} - -/** - * ocxlflash_read_adapter_vpd() - reads the adapter VPD - * @pdev: PCI device associated with the host. - * @buf: Buffer to get the VPD data. - * @count: Size of buffer (maximum bytes that can be read). - * - * Return: size of VPD on success, -errno on failure - */ -static ssize_t ocxlflash_read_adapter_vpd(struct pci_dev *pdev, void *buf, - size_t count) -{ - return pci_read_vpd(pdev, 0, count, buf); -} - -/** - * free_afu_irqs() - internal service to free interrupts - * @ctx: Adapter context. - */ -static void free_afu_irqs(struct ocxlflash_context *ctx) -{ - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct device *dev = afu->dev; - int i; - - if (!ctx->irqs) { - dev_err(dev, "%s: Interrupts not allocated\n", __func__); - return; - } - - for (i = ctx->num_irqs; i >= 0; i--) - ocxl_link_free_irq(afu->link_token, ctx->irqs[i].hwirq); - - kfree(ctx->irqs); - ctx->irqs = NULL; -} - -/** - * alloc_afu_irqs() - internal service to allocate interrupts - * @ctx: Context associated with the request. - * @num: Number of interrupts requested. - * - * Return: 0 on success, -errno on failure - */ -static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num) -{ - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct device *dev = afu->dev; - struct ocxlflash_irqs *irqs; - int rc = 0; - int hwirq; - int i; - - if (ctx->irqs) { - dev_err(dev, "%s: Interrupts already allocated\n", __func__); - rc = -EEXIST; - goto out; - } - - if (num > OCXL_MAX_IRQS) { - dev_err(dev, "%s: Too many interrupts num=%d\n", __func__, num); - rc = -EINVAL; - goto out; - } - - irqs = kcalloc(num, sizeof(*irqs), GFP_KERNEL); - if (unlikely(!irqs)) { - dev_err(dev, "%s: Context irqs allocation failed\n", __func__); - rc = -ENOMEM; - goto out; - } - - for (i = 0; i < num; i++) { - rc = ocxl_link_irq_alloc(afu->link_token, &hwirq); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n", - __func__, rc); - goto err; - } - - irqs[i].hwirq = hwirq; - } - - ctx->irqs = irqs; - ctx->num_irqs = num; -out: - return rc; -err: - for (i = i-1; i >= 0; i--) - ocxl_link_free_irq(afu->link_token, irqs[i].hwirq); - kfree(irqs); - goto out; -} - -/** - * ocxlflash_allocate_afu_irqs() - allocates the requested number of interrupts - * @ctx_cookie: Context associated with the request. - * @num: Number of interrupts requested. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_allocate_afu_irqs(void *ctx_cookie, int num) -{ - return alloc_afu_irqs(ctx_cookie, num); -} - -/** - * ocxlflash_free_afu_irqs() - frees the interrupts of an adapter context - * @ctx_cookie: Adapter context. - */ -static void ocxlflash_free_afu_irqs(void *ctx_cookie) -{ - free_afu_irqs(ctx_cookie); -} - -/** - * ocxlflash_unconfig_afu() - unconfigure the AFU - * @afu: AFU associated with the host. - */ -static void ocxlflash_unconfig_afu(struct ocxl_hw_afu *afu) -{ - if (afu->gmmio_virt) { - iounmap(afu->gmmio_virt); - afu->gmmio_virt = NULL; - } -} - -/** - * ocxlflash_destroy_afu() - destroy the AFU structure - * @afu_cookie: AFU to be freed. - */ -static void ocxlflash_destroy_afu(void *afu_cookie) -{ - struct ocxl_hw_afu *afu = afu_cookie; - int pos; - - if (!afu) - return; - - ocxlflash_release_context(afu->ocxl_ctx); - idr_destroy(&afu->idr); - - /* Disable the AFU */ - pos = afu->acfg.dvsec_afu_control_pos; - ocxl_config_set_afu_state(afu->pdev, pos, 0); - - ocxlflash_unconfig_afu(afu); - kfree(afu); -} - -/** - * ocxlflash_config_fn() - configure the host function - * @pdev: PCI device associated with the host. - * @afu: AFU associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_config_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu) -{ - struct ocxl_fn_config *fcfg = &afu->fcfg; - struct device *dev = &pdev->dev; - u16 base, enabled, supported; - int rc = 0; - - /* Read DVSEC config of the function */ - rc = ocxl_config_read_function(pdev, fcfg); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_config_read_function failed rc=%d\n", - __func__, rc); - goto out; - } - - /* Check if function has AFUs defined, only 1 per function supported */ - if (fcfg->max_afu_index >= 0) { - afu->is_present = true; - if (fcfg->max_afu_index != 0) - dev_warn(dev, "%s: Unexpected AFU index value %d\n", - __func__, fcfg->max_afu_index); - } - - rc = ocxl_config_get_actag_info(pdev, &base, &enabled, &supported); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_config_get_actag_info failed rc=%d\n", - __func__, rc); - goto out; - } - - afu->fn_actag_base = base; - afu->fn_actag_enabled = enabled; - - ocxl_config_set_actag(pdev, fcfg->dvsec_function_pos, base, enabled); - dev_dbg(dev, "%s: Function acTag range base=%u enabled=%u\n", - __func__, base, enabled); - - rc = ocxl_link_setup(pdev, 0, &afu->link_token); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_link_setup failed rc=%d\n", - __func__, rc); - goto out; - } - - rc = ocxl_config_set_TL(pdev, fcfg->dvsec_tl_pos); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_config_set_TL failed rc=%d\n", - __func__, rc); - goto err; - } -out: - return rc; -err: - ocxl_link_release(pdev, afu->link_token); - goto out; -} - -/** - * ocxlflash_unconfig_fn() - unconfigure the host function - * @pdev: PCI device associated with the host. - * @afu: AFU associated with the host. - */ -static void ocxlflash_unconfig_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu) -{ - ocxl_link_release(pdev, afu->link_token); -} - -/** - * ocxlflash_map_mmio() - map the AFU MMIO space - * @afu: AFU associated with the host. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_map_mmio(struct ocxl_hw_afu *afu) -{ - struct ocxl_afu_config *acfg = &afu->acfg; - struct pci_dev *pdev = afu->pdev; - struct device *dev = afu->dev; - phys_addr_t gmmio, ppmmio; - int rc = 0; - - rc = pci_request_region(pdev, acfg->global_mmio_bar, "ocxlflash"); - if (unlikely(rc)) { - dev_err(dev, "%s: pci_request_region for global failed rc=%d\n", - __func__, rc); - goto out; - } - gmmio = pci_resource_start(pdev, acfg->global_mmio_bar); - gmmio += acfg->global_mmio_offset; - - rc = pci_request_region(pdev, acfg->pp_mmio_bar, "ocxlflash"); - if (unlikely(rc)) { - dev_err(dev, "%s: pci_request_region for pp bar failed rc=%d\n", - __func__, rc); - goto err1; - } - ppmmio = pci_resource_start(pdev, acfg->pp_mmio_bar); - ppmmio += acfg->pp_mmio_offset; - - afu->gmmio_virt = ioremap(gmmio, acfg->global_mmio_size); - if (unlikely(!afu->gmmio_virt)) { - dev_err(dev, "%s: MMIO mapping failed\n", __func__); - rc = -ENOMEM; - goto err2; - } - - afu->gmmio_phys = gmmio; - afu->ppmmio_phys = ppmmio; -out: - return rc; -err2: - pci_release_region(pdev, acfg->pp_mmio_bar); -err1: - pci_release_region(pdev, acfg->global_mmio_bar); - goto out; -} - -/** - * ocxlflash_config_afu() - configure the host AFU - * @pdev: PCI device associated with the host. - * @afu: AFU associated with the host. - * - * Must be called _after_ host function configuration. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_config_afu(struct pci_dev *pdev, struct ocxl_hw_afu *afu) -{ - struct ocxl_afu_config *acfg = &afu->acfg; - struct ocxl_fn_config *fcfg = &afu->fcfg; - struct device *dev = &pdev->dev; - int count; - int base; - int pos; - int rc = 0; - - /* This HW AFU function does not have any AFUs defined */ - if (!afu->is_present) - goto out; - - /* Read AFU config at index 0 */ - rc = ocxl_config_read_afu(pdev, fcfg, acfg, 0); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxl_config_read_afu failed rc=%d\n", - __func__, rc); - goto out; - } - - /* Only one AFU per function is supported, so actag_base is same */ - base = afu->fn_actag_base; - count = min_t(int, acfg->actag_supported, afu->fn_actag_enabled); - pos = acfg->dvsec_afu_control_pos; - - ocxl_config_set_afu_actag(pdev, pos, base, count); - dev_dbg(dev, "%s: acTag base=%d enabled=%d\n", __func__, base, count); - afu->afu_actag_base = base; - afu->afu_actag_enabled = count; - afu->max_pasid = 1 << acfg->pasid_supported_log; - - ocxl_config_set_afu_pasid(pdev, pos, 0, acfg->pasid_supported_log); - - rc = ocxlflash_map_mmio(afu); - if (unlikely(rc)) { - dev_err(dev, "%s: ocxlflash_map_mmio failed rc=%d\n", - __func__, rc); - goto out; - } - - /* Enable the AFU */ - ocxl_config_set_afu_state(pdev, acfg->dvsec_afu_control_pos, 1); -out: - return rc; -} - -/** - * ocxlflash_create_afu() - create the AFU for OCXL - * @pdev: PCI device associated with the host. - * - * Return: AFU on success, NULL on failure - */ -static void *ocxlflash_create_afu(struct pci_dev *pdev) -{ - struct device *dev = &pdev->dev; - struct ocxlflash_context *ctx; - struct ocxl_hw_afu *afu; - int rc; - - afu = kzalloc(sizeof(*afu), GFP_KERNEL); - if (unlikely(!afu)) { - dev_err(dev, "%s: HW AFU allocation failed\n", __func__); - goto out; - } - - afu->pdev = pdev; - afu->dev = dev; - idr_init(&afu->idr); - - rc = ocxlflash_config_fn(pdev, afu); - if (unlikely(rc)) { - dev_err(dev, "%s: Function configuration failed rc=%d\n", - __func__, rc); - goto err1; - } - - rc = ocxlflash_config_afu(pdev, afu); - if (unlikely(rc)) { - dev_err(dev, "%s: AFU configuration failed rc=%d\n", - __func__, rc); - goto err2; - } - - ctx = ocxlflash_dev_context_init(pdev, afu); - if (IS_ERR(ctx)) { - rc = PTR_ERR(ctx); - dev_err(dev, "%s: ocxlflash_dev_context_init failed rc=%d\n", - __func__, rc); - goto err3; - } - - afu->ocxl_ctx = ctx; -out: - return afu; -err3: - ocxlflash_unconfig_afu(afu); -err2: - ocxlflash_unconfig_fn(pdev, afu); -err1: - idr_destroy(&afu->idr); - kfree(afu); - afu = NULL; - goto out; -} - -/** - * ctx_event_pending() - check for any event pending on the context - * @ctx: Context to be checked. - * - * Return: true if there is an event pending, false if none pending - */ -static inline bool ctx_event_pending(struct ocxlflash_context *ctx) -{ - if (ctx->pending_irq || ctx->pending_fault) - return true; - - return false; -} - -/** - * afu_poll() - poll the AFU for events on the context - * @file: File associated with the adapter context. - * @poll: Poll structure from the user. - * - * Return: poll mask - */ -static unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) -{ - struct ocxlflash_context *ctx = file->private_data; - struct device *dev = ctx->hw_afu->dev; - ulong lock_flags; - int mask = 0; - - poll_wait(file, &ctx->wq, poll); - - spin_lock_irqsave(&ctx->slock, lock_flags); - if (ctx_event_pending(ctx)) - mask |= POLLIN | POLLRDNORM; - else if (ctx->state == CLOSED) - mask |= POLLERR; - spin_unlock_irqrestore(&ctx->slock, lock_flags); - - dev_dbg(dev, "%s: Poll wait completed for pe %i mask %i\n", - __func__, ctx->pe, mask); - - return mask; -} - -/** - * afu_read() - perform a read on the context for any event - * @file: File associated with the adapter context. - * @buf: Buffer to receive the data. - * @count: Size of buffer (maximum bytes that can be read). - * @off: Offset. - * - * Return: size of the data read on success, -errno on failure - */ -static ssize_t afu_read(struct file *file, char __user *buf, size_t count, - loff_t *off) -{ - struct ocxlflash_context *ctx = file->private_data; - struct device *dev = ctx->hw_afu->dev; - struct cxl_event event; - ulong lock_flags; - ssize_t esize; - ssize_t rc; - int bit; - DEFINE_WAIT(event_wait); - - if (*off != 0) { - dev_err(dev, "%s: Non-zero offset not supported, off=%lld\n", - __func__, *off); - rc = -EINVAL; - goto out; - } - - spin_lock_irqsave(&ctx->slock, lock_flags); - - for (;;) { - prepare_to_wait(&ctx->wq, &event_wait, TASK_INTERRUPTIBLE); - - if (ctx_event_pending(ctx) || (ctx->state == CLOSED)) - break; - - if (file->f_flags & O_NONBLOCK) { - dev_err(dev, "%s: File cannot be blocked on I/O\n", - __func__); - rc = -EAGAIN; - goto err; - } - - if (signal_pending(current)) { - dev_err(dev, "%s: Signal pending on the process\n", - __func__); - rc = -ERESTARTSYS; - goto err; - } - - spin_unlock_irqrestore(&ctx->slock, lock_flags); - schedule(); - spin_lock_irqsave(&ctx->slock, lock_flags); - } - - finish_wait(&ctx->wq, &event_wait); - - memset(&event, 0, sizeof(event)); - event.header.process_element = ctx->pe; - event.header.size = sizeof(struct cxl_event_header); - if (ctx->pending_irq) { - esize = sizeof(struct cxl_event_afu_interrupt); - event.header.size += esize; - event.header.type = CXL_EVENT_AFU_INTERRUPT; - - bit = find_first_bit(&ctx->irq_bitmap, ctx->num_irqs); - clear_bit(bit, &ctx->irq_bitmap); - event.irq.irq = bit + 1; - if (bitmap_empty(&ctx->irq_bitmap, ctx->num_irqs)) - ctx->pending_irq = false; - } else if (ctx->pending_fault) { - event.header.size += sizeof(struct cxl_event_data_storage); - event.header.type = CXL_EVENT_DATA_STORAGE; - event.fault.addr = ctx->fault_addr; - event.fault.dsisr = ctx->fault_dsisr; - ctx->pending_fault = false; - } - - spin_unlock_irqrestore(&ctx->slock, lock_flags); - - if (copy_to_user(buf, &event, event.header.size)) { - dev_err(dev, "%s: copy_to_user failed\n", __func__); - rc = -EFAULT; - goto out; - } - - rc = event.header.size; -out: - return rc; -err: - finish_wait(&ctx->wq, &event_wait); - spin_unlock_irqrestore(&ctx->slock, lock_flags); - goto out; -} - -/** - * afu_release() - release and free the context - * @inode: File inode pointer. - * @file: File associated with the context. - * - * Return: 0 on success, -errno on failure - */ -static int afu_release(struct inode *inode, struct file *file) -{ - struct ocxlflash_context *ctx = file->private_data; - int i; - - /* Unmap and free the interrupts associated with the context */ - for (i = ctx->num_irqs; i >= 0; i--) - afu_unmap_irq(0, ctx, i, ctx); - free_afu_irqs(ctx); - - return ocxlflash_release_context(ctx); -} - -/** - * ocxlflash_mmap_fault() - mmap fault handler - * @vmf: VM fault associated with current fault. - * - * Return: 0 on success, -errno on failure - */ -static vm_fault_t ocxlflash_mmap_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct ocxlflash_context *ctx = vma->vm_file->private_data; - struct device *dev = ctx->hw_afu->dev; - u64 mmio_area, offset; - - offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= ctx->psn_size) - return VM_FAULT_SIGBUS; - - mutex_lock(&ctx->state_mutex); - if (ctx->state != STARTED) { - dev_err(dev, "%s: Context not started, state=%d\n", - __func__, ctx->state); - mutex_unlock(&ctx->state_mutex); - return VM_FAULT_SIGBUS; - } - mutex_unlock(&ctx->state_mutex); - - mmio_area = ctx->psn_phys; - mmio_area += offset; - - return vmf_insert_pfn(vma, vmf->address, mmio_area >> PAGE_SHIFT); -} - -static const struct vm_operations_struct ocxlflash_vmops = { - .fault = ocxlflash_mmap_fault, -}; - -/** - * afu_mmap() - map the fault handler operations - * @file: File associated with the context. - * @vma: VM area associated with mapping. - * - * Return: 0 on success, -errno on failure - */ -static int afu_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct ocxlflash_context *ctx = file->private_data; - - if ((vma_pages(vma) + vma->vm_pgoff) > - (ctx->psn_size >> PAGE_SHIFT)) - return -EINVAL; - - vm_flags_set(vma, VM_IO | VM_PFNMAP); - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_ops = &ocxlflash_vmops; - return 0; -} - -static const struct file_operations ocxl_afu_fops = { - .owner = THIS_MODULE, - .poll = afu_poll, - .read = afu_read, - .release = afu_release, - .mmap = afu_mmap, -}; - -#define PATCH_FOPS(NAME) \ - do { if (!fops->NAME) fops->NAME = ocxl_afu_fops.NAME; } while (0) - -/** - * ocxlflash_get_fd() - get file descriptor for an adapter context - * @ctx_cookie: Adapter context. - * @fops: File operations to be associated. - * @fd: File descriptor to be returned back. - * - * Return: pointer to the file on success, ERR_PTR on failure - */ -static struct file *ocxlflash_get_fd(void *ctx_cookie, - struct file_operations *fops, int *fd) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct device *dev = ctx->hw_afu->dev; - struct file *file; - int flags, fdtmp; - int rc = 0; - char *name = NULL; - - /* Only allow one fd per context */ - if (ctx->mapping) { - dev_err(dev, "%s: Context is already mapped to an fd\n", - __func__); - rc = -EEXIST; - goto err1; - } - - flags = O_RDWR | O_CLOEXEC; - - /* This code is similar to anon_inode_getfd() */ - rc = get_unused_fd_flags(flags); - if (unlikely(rc < 0)) { - dev_err(dev, "%s: get_unused_fd_flags failed rc=%d\n", - __func__, rc); - goto err1; - } - fdtmp = rc; - - /* Patch the file ops that are not defined */ - if (fops) { - PATCH_FOPS(poll); - PATCH_FOPS(read); - PATCH_FOPS(release); - PATCH_FOPS(mmap); - } else /* Use default ops */ - fops = (struct file_operations *)&ocxl_afu_fops; - - name = kasprintf(GFP_KERNEL, "ocxlflash:%d", ctx->pe); - file = ocxlflash_getfile(dev, name, fops, ctx, flags); - kfree(name); - if (IS_ERR(file)) { - rc = PTR_ERR(file); - dev_err(dev, "%s: ocxlflash_getfile failed rc=%d\n", - __func__, rc); - goto err2; - } - - ctx->mapping = file->f_mapping; - *fd = fdtmp; -out: - return file; -err2: - put_unused_fd(fdtmp); -err1: - file = ERR_PTR(rc); - goto out; -} - -/** - * ocxlflash_fops_get_context() - get the context associated with the file - * @file: File associated with the adapter context. - * - * Return: pointer to the context - */ -static void *ocxlflash_fops_get_context(struct file *file) -{ - return file->private_data; -} - -/** - * ocxlflash_afu_irq() - interrupt handler for user contexts - * @irq: Interrupt number. - * @data: Private data provided at interrupt registration, the context. - * - * Return: Always return IRQ_HANDLED. - */ -static irqreturn_t ocxlflash_afu_irq(int irq, void *data) -{ - struct ocxlflash_context *ctx = data; - struct device *dev = ctx->hw_afu->dev; - int i; - - dev_dbg(dev, "%s: Interrupt raised for pe %i virq %i\n", - __func__, ctx->pe, irq); - - for (i = 0; i < ctx->num_irqs; i++) { - if (ctx->irqs[i].virq == irq) - break; - } - if (unlikely(i >= ctx->num_irqs)) { - dev_err(dev, "%s: Received AFU IRQ out of range\n", __func__); - goto out; - } - - spin_lock(&ctx->slock); - set_bit(i - 1, &ctx->irq_bitmap); - ctx->pending_irq = true; - spin_unlock(&ctx->slock); - - wake_up_all(&ctx->wq); -out: - return IRQ_HANDLED; -} - -/** - * ocxlflash_start_work() - start a user context - * @ctx_cookie: Context to be started. - * @num_irqs: Number of interrupts requested. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_start_work(void *ctx_cookie, u64 num_irqs) -{ - struct ocxlflash_context *ctx = ctx_cookie; - struct ocxl_hw_afu *afu = ctx->hw_afu; - struct device *dev = afu->dev; - char *name; - int rc = 0; - int i; - - rc = alloc_afu_irqs(ctx, num_irqs); - if (unlikely(rc < 0)) { - dev_err(dev, "%s: alloc_afu_irqs failed rc=%d\n", __func__, rc); - goto out; - } - - for (i = 0; i < num_irqs; i++) { - name = kasprintf(GFP_KERNEL, "ocxlflash-%s-pe%i-%i", - dev_name(dev), ctx->pe, i); - rc = afu_map_irq(0, ctx, i, ocxlflash_afu_irq, ctx, name); - kfree(name); - if (unlikely(rc < 0)) { - dev_err(dev, "%s: afu_map_irq failed rc=%d\n", - __func__, rc); - goto err; - } - } - - rc = start_context(ctx); - if (unlikely(rc)) { - dev_err(dev, "%s: start_context failed rc=%d\n", __func__, rc); - goto err; - } -out: - return rc; -err: - for (i = i-1; i >= 0; i--) - afu_unmap_irq(0, ctx, i, ctx); - free_afu_irqs(ctx); - goto out; -}; - -/** - * ocxlflash_fd_mmap() - mmap handler for adapter file descriptor - * @file: File installed with adapter file descriptor. - * @vma: VM area associated with mapping. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_fd_mmap(struct file *file, struct vm_area_struct *vma) -{ - return afu_mmap(file, vma); -} - -/** - * ocxlflash_fd_release() - release the context associated with the file - * @inode: File inode pointer. - * @file: File associated with the adapter context. - * - * Return: 0 on success, -errno on failure - */ -static int ocxlflash_fd_release(struct inode *inode, struct file *file) -{ - return afu_release(inode, file); -} - -/* Backend ops to ocxlflash services */ -const struct cxlflash_backend_ops cxlflash_ocxl_ops = { - .module = THIS_MODULE, - .psa_map = ocxlflash_psa_map, - .psa_unmap = ocxlflash_psa_unmap, - .process_element = ocxlflash_process_element, - .map_afu_irq = ocxlflash_map_afu_irq, - .unmap_afu_irq = ocxlflash_unmap_afu_irq, - .get_irq_objhndl = ocxlflash_get_irq_objhndl, - .start_context = ocxlflash_start_context, - .stop_context = ocxlflash_stop_context, - .afu_reset = ocxlflash_afu_reset, - .set_master = ocxlflash_set_master, - .get_context = ocxlflash_get_context, - .dev_context_init = ocxlflash_dev_context_init, - .release_context = ocxlflash_release_context, - .perst_reloads_same_image = ocxlflash_perst_reloads_same_image, - .read_adapter_vpd = ocxlflash_read_adapter_vpd, - .allocate_afu_irqs = ocxlflash_allocate_afu_irqs, - .free_afu_irqs = ocxlflash_free_afu_irqs, - .create_afu = ocxlflash_create_afu, - .destroy_afu = ocxlflash_destroy_afu, - .get_fd = ocxlflash_get_fd, - .fops_get_context = ocxlflash_fops_get_context, - .start_work = ocxlflash_start_work, - .fd_mmap = ocxlflash_fd_mmap, - .fd_release = ocxlflash_fd_release, -}; diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h deleted file mode 100644 index f2fe88816bea..000000000000 --- a/drivers/scsi/cxlflash/ocxl_hw.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2018 IBM Corporation - */ - -#define OCXL_MAX_IRQS 4 /* Max interrupts per process */ - -struct ocxlflash_irqs { - int hwirq; - u32 virq; - void __iomem *vtrig; -}; - -/* OCXL hardware AFU associated with the host */ -struct ocxl_hw_afu { - struct ocxlflash_context *ocxl_ctx; /* Host context */ - struct pci_dev *pdev; /* PCI device */ - struct device *dev; /* Generic device */ - bool perst_same_image; /* Same image loaded on perst */ - - struct ocxl_fn_config fcfg; /* DVSEC config of the function */ - struct ocxl_afu_config acfg; /* AFU configuration data */ - - int fn_actag_base; /* Function acTag base */ - int fn_actag_enabled; /* Function acTag number enabled */ - int afu_actag_base; /* AFU acTag base */ - int afu_actag_enabled; /* AFU acTag number enabled */ - - phys_addr_t ppmmio_phys; /* Per process MMIO space */ - phys_addr_t gmmio_phys; /* Global AFU MMIO space */ - void __iomem *gmmio_virt; /* Global MMIO map */ - - void *link_token; /* Link token for the SPA */ - struct idr idr; /* IDR to manage contexts */ - int max_pasid; /* Maximum number of contexts */ - bool is_present; /* Function has AFUs defined */ -}; - -enum ocxlflash_ctx_state { - CLOSED, - OPENED, - STARTED -}; - -struct ocxlflash_context { - struct ocxl_hw_afu *hw_afu; /* HW AFU back pointer */ - struct address_space *mapping; /* Mapping for pseudo filesystem */ - bool master; /* Whether this is a master context */ - int pe; /* Process element */ - - phys_addr_t psn_phys; /* Process mapping */ - u64 psn_size; /* Process mapping size */ - - spinlock_t slock; /* Protects irq/fault/event updates */ - wait_queue_head_t wq; /* Wait queue for poll and interrupts */ - struct mutex state_mutex; /* Mutex to update context state */ - enum ocxlflash_ctx_state state; /* Context state */ - - struct ocxlflash_irqs *irqs; /* Pointer to array of structures */ - int num_irqs; /* Number of interrupts */ - bool pending_irq; /* Pending interrupt on the context */ - ulong irq_bitmap; /* Bits indicating pending irq num */ - - u64 fault_addr; /* Address that triggered the fault */ - u64 fault_dsisr; /* Value of dsisr register at fault */ - bool pending_fault; /* Pending translation fault */ -}; diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h deleted file mode 100644 index ab315c59505b..000000000000 --- a/drivers/scsi/cxlflash/sislite.h +++ /dev/null @@ -1,560 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#ifndef _SISLITE_H -#define _SISLITE_H - -#include <linux/types.h> - -typedef u16 ctx_hndl_t; -typedef u32 res_hndl_t; - -#define SIZE_4K 4096 -#define SIZE_64K 65536 - -/* - * IOARCB: 64 bytes, min 16 byte alignment required, host native endianness - * except for SCSI CDB which remains big endian per SCSI standards. - */ -struct sisl_ioarcb { - u16 ctx_id; /* ctx_hndl_t */ - u16 req_flags; -#define SISL_REQ_FLAGS_RES_HNDL 0x8000U /* bit 0 (MSB) */ -#define SISL_REQ_FLAGS_PORT_LUN_ID 0x0000U - -#define SISL_REQ_FLAGS_SUP_UNDERRUN 0x4000U /* bit 1 */ - -#define SISL_REQ_FLAGS_TIMEOUT_SECS 0x0000U /* bits 8,9 */ -#define SISL_REQ_FLAGS_TIMEOUT_MSECS 0x0040U -#define SISL_REQ_FLAGS_TIMEOUT_USECS 0x0080U -#define SISL_REQ_FLAGS_TIMEOUT_CYCLES 0x00C0U - -#define SISL_REQ_FLAGS_TMF_CMD 0x0004u /* bit 13 */ - -#define SISL_REQ_FLAGS_AFU_CMD 0x0002U /* bit 14 */ - -#define SISL_REQ_FLAGS_HOST_WRITE 0x0001U /* bit 15 (LSB) */ -#define SISL_REQ_FLAGS_HOST_READ 0x0000U - - union { - u32 res_hndl; /* res_hndl_t */ - u32 port_sel; /* this is a selection mask: - * 0x1 -> port#0 can be selected, - * 0x2 -> port#1 can be selected. - * Can be bitwise ORed. - */ - }; - u64 lun_id; - u32 data_len; /* 4K for read/write */ - u32 ioadl_len; - union { - u64 data_ea; /* min 16 byte aligned */ - u64 ioadl_ea; - }; - u8 msi; /* LISN to send on RRQ write */ -#define SISL_MSI_CXL_PFAULT 0 /* reserved for CXL page faults */ -#define SISL_MSI_SYNC_ERROR 1 /* recommended for AFU sync error */ -#define SISL_MSI_RRQ_UPDATED 2 /* recommended for IO completion */ -#define SISL_MSI_ASYNC_ERROR 3 /* master only - for AFU async error */ - - u8 rrq; /* 0 for a single RRQ */ - u16 timeout; /* in units specified by req_flags */ - u32 rsvd1; - u8 cdb[16]; /* must be in big endian */ -#define SISL_AFU_CMD_SYNC 0xC0 /* AFU sync command */ -#define SISL_AFU_CMD_LUN_PROVISION 0xD0 /* AFU LUN provision command */ -#define SISL_AFU_CMD_DEBUG 0xE0 /* AFU debug command */ - -#define SISL_AFU_LUN_PROVISION_CREATE 0x00 /* LUN provision create type */ -#define SISL_AFU_LUN_PROVISION_DELETE 0x01 /* LUN provision delete type */ - - union { - u64 reserved; /* Reserved for IOARRIN mode */ - struct sisl_ioasa *ioasa; /* IOASA EA for SQ Mode */ - }; -} __packed; - -struct sisl_rc { - u8 flags; -#define SISL_RC_FLAGS_SENSE_VALID 0x80U -#define SISL_RC_FLAGS_FCP_RSP_CODE_VALID 0x40U -#define SISL_RC_FLAGS_OVERRUN 0x20U -#define SISL_RC_FLAGS_UNDERRUN 0x10U - - u8 afu_rc; -#define SISL_AFU_RC_RHT_INVALID 0x01U /* user error */ -#define SISL_AFU_RC_RHT_UNALIGNED 0x02U /* should never happen */ -#define SISL_AFU_RC_RHT_OUT_OF_BOUNDS 0x03u /* user error */ -#define SISL_AFU_RC_RHT_DMA_ERR 0x04u /* see afu_extra - * may retry if afu_retry is off - * possible on master exit - */ -#define SISL_AFU_RC_RHT_RW_PERM 0x05u /* no RW perms, user error */ -#define SISL_AFU_RC_LXT_UNALIGNED 0x12U /* should never happen */ -#define SISL_AFU_RC_LXT_OUT_OF_BOUNDS 0x13u /* user error */ -#define SISL_AFU_RC_LXT_DMA_ERR 0x14u /* see afu_extra - * may retry if afu_retry is off - * possible on master exit - */ -#define SISL_AFU_RC_LXT_RW_PERM 0x15u /* no RW perms, user error */ - -#define SISL_AFU_RC_NOT_XLATE_HOST 0x1au /* possible if master exited */ - - /* NO_CHANNELS means the FC ports selected by dest_port in - * IOARCB or in the LXT entry are down when the AFU tried to select - * a FC port. If the port went down on an active IO, it will set - * fc_rc to =0x54(NOLOGI) or 0x57(LINKDOWN) instead. - */ -#define SISL_AFU_RC_NO_CHANNELS 0x20U /* see afu_extra, may retry */ -#define SISL_AFU_RC_CAP_VIOLATION 0x21U /* either user error or - * afu reset/master restart - */ -#define SISL_AFU_RC_OUT_OF_DATA_BUFS 0x30U /* always retry */ -#define SISL_AFU_RC_DATA_DMA_ERR 0x31U /* see afu_extra - * may retry if afu_retry is off - */ - - u8 scsi_rc; /* SCSI status byte, retry as appropriate */ -#define SISL_SCSI_RC_CHECK 0x02U -#define SISL_SCSI_RC_BUSY 0x08u - - u8 fc_rc; /* retry */ - /* - * We should only see fc_rc=0x57 (LINKDOWN) or 0x54(NOLOGI) for - * commands that are in flight when a link goes down or is logged out. - * If the link is down or logged out before AFU selects the port, either - * it will choose the other port or we will get afu_rc=0x20 (no_channel) - * if there is no valid port to use. - * - * ABORTPEND/ABORTOK/ABORTFAIL/TGTABORT can be retried, typically these - * would happen if a frame is dropped and something times out. - * NOLOGI or LINKDOWN can be retried if the other port is up. - * RESIDERR can be retried as well. - * - * ABORTFAIL might indicate that lots of frames are getting CRC errors. - * So it maybe retried once and reset the link if it happens again. - * The link can also be reset on the CRC error threshold interrupt. - */ -#define SISL_FC_RC_ABORTPEND 0x52 /* exchange timeout or abort request */ -#define SISL_FC_RC_WRABORTPEND 0x53 /* due to write XFER_RDY invalid */ -#define SISL_FC_RC_NOLOGI 0x54 /* port not logged in, in-flight cmds */ -#define SISL_FC_RC_NOEXP 0x55 /* FC protocol error or HW bug */ -#define SISL_FC_RC_INUSE 0x56 /* tag already in use, HW bug */ -#define SISL_FC_RC_LINKDOWN 0x57 /* link down, in-flight cmds */ -#define SISL_FC_RC_ABORTOK 0x58 /* pending abort completed w/success */ -#define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ -#define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ -#define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI - * reported len, possibly due to dropped - * frames - */ -#define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ -}; - -#define SISL_SENSE_DATA_LEN 20 /* Sense data length */ -#define SISL_WWID_DATA_LEN 16 /* WWID data length */ - -/* - * IOASA: 64 bytes & must follow IOARCB, min 16 byte alignment required, - * host native endianness - */ -struct sisl_ioasa { - union { - struct sisl_rc rc; - u32 ioasc; -#define SISL_IOASC_GOOD_COMPLETION 0x00000000U - }; - - union { - u32 resid; - u32 lunid_hi; - }; - - u8 port; - u8 afu_extra; - /* when afu_rc=0x04, 0x14, 0x31 (_xxx_DMA_ERR): - * afu_exta contains PSL response code. Useful codes are: - */ -#define SISL_AFU_DMA_ERR_PAGE_IN 0x0A /* AFU_retry_on_pagein Action - * Enabled N/A - * Disabled retry - */ -#define SISL_AFU_DMA_ERR_INVALID_EA 0x0B /* this is a hard error - * afu_rc Implies - * 0x04, 0x14 master exit. - * 0x31 user error. - */ - /* when afu rc=0x20 (no channels): - * afu_extra bits [4:5]: available portmask, [6:7]: requested portmask. - */ -#define SISL_AFU_NO_CLANNELS_AMASK(afu_extra) (((afu_extra) & 0x0C) >> 2) -#define SISL_AFU_NO_CLANNELS_RMASK(afu_extra) ((afu_extra) & 0x03) - - u8 scsi_extra; - u8 fc_extra; - - union { - u8 sense_data[SISL_SENSE_DATA_LEN]; - struct { - u32 lunid_lo; - u8 wwid[SISL_WWID_DATA_LEN]; - }; - }; - - /* These fields are defined by the SISlite architecture for the - * host to use as they see fit for their implementation. - */ - union { - u64 host_use[4]; - u8 host_use_b[32]; - }; -} __packed; - -#define SISL_RESP_HANDLE_T_BIT 0x1ULL /* Toggle bit */ - -/* MMIO space is required to support only 64-bit access */ - -/* - * This AFU has two mechanisms to deal with endian-ness. - * One is a global configuration (in the afu_config) register - * below that specifies the endian-ness of the host. - * The other is a per context (i.e. application) specification - * controlled by the endian_ctrl field here. Since the master - * context is one such application the master context's - * endian-ness is set to be the same as the host. - * - * As per the SISlite spec, the MMIO registers are always - * big endian. - */ -#define SISL_ENDIAN_CTRL_BE 0x8000000000000080ULL -#define SISL_ENDIAN_CTRL_LE 0x0000000000000000ULL - -#ifdef __BIG_ENDIAN -#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_BE -#else -#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_LE -#endif - -/* per context host transport MMIO */ -struct sisl_host_map { - __be64 endian_ctrl; /* Per context Endian Control. The AFU will - * operate on whatever the context is of the - * host application. - */ - - __be64 intr_status; /* this sends LISN# programmed in ctx_ctrl. - * Only recovery in a PERM_ERR is a context - * exit since there is no way to tell which - * command caused the error. - */ -#define SISL_ISTATUS_PERM_ERR_LISN_3_EA 0x0400ULL /* b53, user error */ -#define SISL_ISTATUS_PERM_ERR_LISN_2_EA 0x0200ULL /* b54, user error */ -#define SISL_ISTATUS_PERM_ERR_LISN_1_EA 0x0100ULL /* b55, user error */ -#define SISL_ISTATUS_PERM_ERR_LISN_3_PASID 0x0080ULL /* b56, user error */ -#define SISL_ISTATUS_PERM_ERR_LISN_2_PASID 0x0040ULL /* b57, user error */ -#define SISL_ISTATUS_PERM_ERR_LISN_1_PASID 0x0020ULL /* b58, user error */ -#define SISL_ISTATUS_PERM_ERR_CMDROOM 0x0010ULL /* b59, user error */ -#define SISL_ISTATUS_PERM_ERR_RCB_READ 0x0008ULL /* b60, user error */ -#define SISL_ISTATUS_PERM_ERR_SA_WRITE 0x0004ULL /* b61, user error */ -#define SISL_ISTATUS_PERM_ERR_RRQ_WRITE 0x0002ULL /* b62, user error */ - /* Page in wait accessing RCB/IOASA/RRQ is reported in b63. - * Same error in data/LXT/RHT access is reported via IOASA. - */ -#define SISL_ISTATUS_TEMP_ERR_PAGEIN 0x0001ULL /* b63, can only be - * generated when AFU - * auto retry is - * disabled. If user - * can determine the - * command that caused - * the error, it can - * be retried. - */ -#define SISL_ISTATUS_UNMASK (0x07FFULL) /* 1 means unmasked */ -#define SISL_ISTATUS_MASK ~(SISL_ISTATUS_UNMASK) /* 1 means masked */ - - __be64 intr_clear; - __be64 intr_mask; - __be64 ioarrin; /* only write what cmd_room permits */ - __be64 rrq_start; /* start & end are both inclusive */ - __be64 rrq_end; /* write sequence: start followed by end */ - __be64 cmd_room; - __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ -#define SISL_CTX_CTRL_UNMAP_SECTOR 0x8000000000000000ULL /* b0 */ -#define SISL_CTX_CTRL_LISN_MASK (0xFFULL) - __be64 mbox_w; /* restricted use */ - __be64 sq_start; /* Submission Queue (R/W): write sequence and */ - __be64 sq_end; /* inclusion semantics are the same as RRQ */ - __be64 sq_head; /* Submission Queue Head (R): for debugging */ - __be64 sq_tail; /* Submission Queue TAIL (R/W): next IOARCB */ - __be64 sq_ctx_reset; /* Submission Queue Context Reset (R/W) */ -}; - -/* per context provisioning & control MMIO */ -struct sisl_ctrl_map { - __be64 rht_start; - __be64 rht_cnt_id; - /* both cnt & ctx_id args must be ULL */ -#define SISL_RHT_CNT_ID(cnt, ctx_id) (((cnt) << 48) | ((ctx_id) << 32)) - - __be64 ctx_cap; /* afu_rc below is when the capability is violated */ -#define SISL_CTX_CAP_PROXY_ISSUE 0x8000000000000000ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_REAL_MODE 0x4000000000000000ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_HOST_XLATE 0x2000000000000000ULL /* afu_rc 0x1a */ -#define SISL_CTX_CAP_PROXY_TARGET 0x1000000000000000ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_AFU_CMD 0x0000000000000008ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_GSCSI_CMD 0x0000000000000004ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_WRITE_CMD 0x0000000000000002ULL /* afu_rc 0x21 */ -#define SISL_CTX_CAP_READ_CMD 0x0000000000000001ULL /* afu_rc 0x21 */ - __be64 mbox_r; - __be64 lisn_pasid[2]; - /* pasid _a arg must be ULL */ -#define SISL_LISN_PASID(_a, _b) (((_a) << 32) | (_b)) - __be64 lisn_ea[3]; -}; - -/* single copy global regs */ -struct sisl_global_regs { - __be64 aintr_status; - /* - * In cxlflash, FC port/link are arranged in port pairs, each - * gets a byte of status: - * - * *_OTHER: other err, FC_ERRCAP[31:20] - * *_LOGO: target sent FLOGI/PLOGI/LOGO while logged in - * *_CRC_T: CRC threshold exceeded - * *_LOGI_R: login state machine timed out and retrying - * *_LOGI_F: login failed, FC_ERROR[19:0] - * *_LOGI_S: login succeeded - * *_LINK_DN: link online to offline - * *_LINK_UP: link offline to online - */ -#define SISL_ASTATUS_FC2_OTHER 0x80000000ULL /* b32 */ -#define SISL_ASTATUS_FC2_LOGO 0x40000000ULL /* b33 */ -#define SISL_ASTATUS_FC2_CRC_T 0x20000000ULL /* b34 */ -#define SISL_ASTATUS_FC2_LOGI_R 0x10000000ULL /* b35 */ -#define SISL_ASTATUS_FC2_LOGI_F 0x08000000ULL /* b36 */ -#define SISL_ASTATUS_FC2_LOGI_S 0x04000000ULL /* b37 */ -#define SISL_ASTATUS_FC2_LINK_DN 0x02000000ULL /* b38 */ -#define SISL_ASTATUS_FC2_LINK_UP 0x01000000ULL /* b39 */ - -#define SISL_ASTATUS_FC3_OTHER 0x00800000ULL /* b40 */ -#define SISL_ASTATUS_FC3_LOGO 0x00400000ULL /* b41 */ -#define SISL_ASTATUS_FC3_CRC_T 0x00200000ULL /* b42 */ -#define SISL_ASTATUS_FC3_LOGI_R 0x00100000ULL /* b43 */ -#define SISL_ASTATUS_FC3_LOGI_F 0x00080000ULL /* b44 */ -#define SISL_ASTATUS_FC3_LOGI_S 0x00040000ULL /* b45 */ -#define SISL_ASTATUS_FC3_LINK_DN 0x00020000ULL /* b46 */ -#define SISL_ASTATUS_FC3_LINK_UP 0x00010000ULL /* b47 */ - -#define SISL_ASTATUS_FC0_OTHER 0x00008000ULL /* b48 */ -#define SISL_ASTATUS_FC0_LOGO 0x00004000ULL /* b49 */ -#define SISL_ASTATUS_FC0_CRC_T 0x00002000ULL /* b50 */ -#define SISL_ASTATUS_FC0_LOGI_R 0x00001000ULL /* b51 */ -#define SISL_ASTATUS_FC0_LOGI_F 0x00000800ULL /* b52 */ -#define SISL_ASTATUS_FC0_LOGI_S 0x00000400ULL /* b53 */ -#define SISL_ASTATUS_FC0_LINK_DN 0x00000200ULL /* b54 */ -#define SISL_ASTATUS_FC0_LINK_UP 0x00000100ULL /* b55 */ - -#define SISL_ASTATUS_FC1_OTHER 0x00000080ULL /* b56 */ -#define SISL_ASTATUS_FC1_LOGO 0x00000040ULL /* b57 */ -#define SISL_ASTATUS_FC1_CRC_T 0x00000020ULL /* b58 */ -#define SISL_ASTATUS_FC1_LOGI_R 0x00000010ULL /* b59 */ -#define SISL_ASTATUS_FC1_LOGI_F 0x00000008ULL /* b60 */ -#define SISL_ASTATUS_FC1_LOGI_S 0x00000004ULL /* b61 */ -#define SISL_ASTATUS_FC1_LINK_DN 0x00000002ULL /* b62 */ -#define SISL_ASTATUS_FC1_LINK_UP 0x00000001ULL /* b63 */ - -#define SISL_FC_INTERNAL_UNMASK 0x0000000300000000ULL /* 1 means unmasked */ -#define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) -#define SISL_FC_INTERNAL_SHIFT 32 - -#define SISL_FC_SHUTDOWN_NORMAL 0x0000000000000010ULL -#define SISL_FC_SHUTDOWN_ABRUPT 0x0000000000000020ULL - -#define SISL_STATUS_SHUTDOWN_ACTIVE 0x0000000000000010ULL -#define SISL_STATUS_SHUTDOWN_COMPLETE 0x0000000000000020ULL - -#define SISL_ASTATUS_UNMASK 0xFFFFFFFFULL /* 1 means unmasked */ -#define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ - - __be64 aintr_clear; - __be64 aintr_mask; - __be64 afu_ctrl; - __be64 afu_hb; - __be64 afu_scratch_pad; - __be64 afu_port_sel; -#define SISL_AFUCONF_AR_IOARCB 0x4000ULL -#define SISL_AFUCONF_AR_LXT 0x2000ULL -#define SISL_AFUCONF_AR_RHT 0x1000ULL -#define SISL_AFUCONF_AR_DATA 0x0800ULL -#define SISL_AFUCONF_AR_RSRC 0x0400ULL -#define SISL_AFUCONF_AR_IOASA 0x0200ULL -#define SISL_AFUCONF_AR_RRQ 0x0100ULL -/* Aggregate all Auto Retry Bits */ -#define SISL_AFUCONF_AR_ALL (SISL_AFUCONF_AR_IOARCB|SISL_AFUCONF_AR_LXT| \ - SISL_AFUCONF_AR_RHT|SISL_AFUCONF_AR_DATA| \ - SISL_AFUCONF_AR_RSRC|SISL_AFUCONF_AR_IOASA| \ - SISL_AFUCONF_AR_RRQ) -#ifdef __BIG_ENDIAN -#define SISL_AFUCONF_ENDIAN 0x0000ULL -#else -#define SISL_AFUCONF_ENDIAN 0x0020ULL -#endif -#define SISL_AFUCONF_MBOX_CLR_READ 0x0010ULL - __be64 afu_config; - __be64 rsvd[0xf8]; - __le64 afu_version; - __be64 interface_version; -#define SISL_INTVER_CAP_SHIFT 16 -#define SISL_INTVER_MAJ_SHIFT 8 -#define SISL_INTVER_CAP_MASK 0xFFFFFFFF00000000ULL -#define SISL_INTVER_MAJ_MASK 0x00000000FFFF0000ULL -#define SISL_INTVER_MIN_MASK 0x000000000000FFFFULL -#define SISL_INTVER_CAP_IOARRIN_CMD_MODE 0x800000000000ULL -#define SISL_INTVER_CAP_SQ_CMD_MODE 0x400000000000ULL -#define SISL_INTVER_CAP_RESERVED_CMD_MODE_A 0x200000000000ULL -#define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL -#define SISL_INTVER_CAP_LUN_PROVISION 0x080000000000ULL -#define SISL_INTVER_CAP_AFU_DEBUG 0x040000000000ULL -#define SISL_INTVER_CAP_OCXL_LISN 0x020000000000ULL -}; - -#define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ -#define CXLFLASH_MAX_FC_BANKS 2 /* max # of banks supported */ -#define CXLFLASH_MAX_FC_PORTS (CXLFLASH_NUM_FC_PORTS_PER_BANK * \ - CXLFLASH_MAX_FC_BANKS) -#define CXLFLASH_MAX_CONTEXT 512 /* number of contexts per AFU */ -#define CXLFLASH_NUM_VLUNS 512 /* number of vluns per AFU/port */ -#define CXLFLASH_NUM_REGS 512 /* number of registers per port */ - -struct fc_port_bank { - __be64 fc_port_regs[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_REGS]; - __be64 fc_port_luns[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_VLUNS]; -}; - -struct sisl_global_map { - union { - struct sisl_global_regs regs; - char page0[SIZE_4K]; /* page 0 */ - }; - - char page1[SIZE_4K]; /* page 1 */ - - struct fc_port_bank bank[CXLFLASH_MAX_FC_BANKS]; /* pages 2 - 9 */ - - /* pages 10 - 15 are reserved */ - -}; - -/* - * CXL Flash Memory Map - * - * +-------------------------------+ - * | 512 * 64 KB User MMIO | - * | (per context) | - * | User Accessible | - * +-------------------------------+ - * | 512 * 128 B per context | - * | Provisioning and Control | - * | Trusted Process accessible | - * +-------------------------------+ - * | 64 KB Global | - * | Trusted Process accessible | - * +-------------------------------+ - */ -struct cxlflash_afu_map { - union { - struct sisl_host_map host; - char harea[SIZE_64K]; /* 64KB each */ - } hosts[CXLFLASH_MAX_CONTEXT]; - - union { - struct sisl_ctrl_map ctrl; - char carea[cache_line_size()]; /* 128B each */ - } ctrls[CXLFLASH_MAX_CONTEXT]; - - union { - struct sisl_global_map global; - char garea[SIZE_64K]; /* 64KB single block */ - }; -}; - -/* - * LXT - LBA Translation Table - * LXT control blocks - */ -struct sisl_lxt_entry { - u64 rlba_base; /* bits 0:47 is base - * b48:55 is lun index - * b58:59 is write & read perms - * (if no perm, afu_rc=0x15) - * b60:63 is port_sel mask - */ -}; - -/* - * RHT - Resource Handle Table - * Per the SISlite spec, RHT entries are to be 16-byte aligned - */ -struct sisl_rht_entry { - struct sisl_lxt_entry *lxt_start; - u32 lxt_cnt; - u16 rsvd; - u8 fp; /* format & perm nibbles. - * (if no perm, afu_rc=0x05) - */ - u8 nmask; -} __packed __aligned(16); - -struct sisl_rht_entry_f1 { - u64 lun_id; - union { - struct { - u8 valid; - u8 rsvd[5]; - u8 fp; - u8 port_sel; - }; - - u64 dw; - }; -} __packed __aligned(16); - -/* make the fp byte */ -#define SISL_RHT_FP(fmt, perm) (((fmt) << 4) | (perm)) - -/* make the fp byte for a clone from a source fp and clone flags - * flags must be only 2 LSB bits. - */ -#define SISL_RHT_FP_CLONE(src_fp, cln_flags) ((src_fp) & (0xFC | (cln_flags))) - -#define RHT_PERM_READ 0x01U -#define RHT_PERM_WRITE 0x02U -#define RHT_PERM_RW (RHT_PERM_READ | RHT_PERM_WRITE) - -/* extract the perm bits from a fp */ -#define SISL_RHT_PERM(fp) ((fp) & RHT_PERM_RW) - -#define PORT0 0x01U -#define PORT1 0x02U -#define PORT2 0x04U -#define PORT3 0x08U -#define PORT_MASK(_n) ((1 << (_n)) - 1) - -/* AFU Sync Mode byte */ -#define AFU_LW_SYNC 0x0U -#define AFU_HW_SYNC 0x1U -#define AFU_GSYNC 0x2U - -/* Special Task Management Function CDB */ -#define TMF_LUN_RESET 0x1U -#define TMF_CLEAR_ACA 0x2U - -#endif /* _SISLITE_H */ diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c deleted file mode 100644 index 97631f48e19d..000000000000 --- a/drivers/scsi/cxlflash/superpipe.c +++ /dev/null @@ -1,2218 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#include <linux/delay.h> -#include <linux/file.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/syscalls.h> -#include <linux/unaligned.h> - -#include <scsi/scsi.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_eh.h> -#include <uapi/scsi/cxlflash_ioctl.h> - -#include "sislite.h" -#include "common.h" -#include "vlun.h" -#include "superpipe.h" - -struct cxlflash_global global; - -/** - * marshal_rele_to_resize() - translate release to resize structure - * @release: Source structure from which to translate/copy. - * @resize: Destination structure for the translate/copy. - */ -static void marshal_rele_to_resize(struct dk_cxlflash_release *release, - struct dk_cxlflash_resize *resize) -{ - resize->hdr = release->hdr; - resize->context_id = release->context_id; - resize->rsrc_handle = release->rsrc_handle; -} - -/** - * marshal_det_to_rele() - translate detach to release structure - * @detach: Destination structure for the translate/copy. - * @release: Source structure from which to translate/copy. - */ -static void marshal_det_to_rele(struct dk_cxlflash_detach *detach, - struct dk_cxlflash_release *release) -{ - release->hdr = detach->hdr; - release->context_id = detach->context_id; -} - -/** - * marshal_udir_to_rele() - translate udirect to release structure - * @udirect: Source structure from which to translate/copy. - * @release: Destination structure for the translate/copy. - */ -static void marshal_udir_to_rele(struct dk_cxlflash_udirect *udirect, - struct dk_cxlflash_release *release) -{ - release->hdr = udirect->hdr; - release->context_id = udirect->context_id; - release->rsrc_handle = udirect->rsrc_handle; -} - -/** - * cxlflash_free_errpage() - frees resources associated with global error page - */ -void cxlflash_free_errpage(void) -{ - - mutex_lock(&global.mutex); - if (global.err_page) { - __free_page(global.err_page); - global.err_page = NULL; - } - mutex_unlock(&global.mutex); -} - -/** - * cxlflash_stop_term_user_contexts() - stops/terminates known user contexts - * @cfg: Internal structure associated with the host. - * - * When the host needs to go down, all users must be quiesced and their - * memory freed. This is accomplished by putting the contexts in error - * state which will notify the user and let them 'drive' the tear down. - * Meanwhile, this routine camps until all user contexts have been removed. - * - * Note that the main loop in this routine will always execute at least once - * to flush the reset_waitq. - */ -void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int i, found = true; - - cxlflash_mark_contexts_error(cfg); - - while (true) { - for (i = 0; i < MAX_CONTEXT; i++) - if (cfg->ctx_tbl[i]) { - found = true; - break; - } - - if (!found && list_empty(&cfg->ctx_err_recovery)) - return; - - dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", - __func__); - wake_up_all(&cfg->reset_waitq); - ssleep(1); - found = false; - } -} - -/** - * find_error_context() - locates a context by cookie on the error recovery list - * @cfg: Internal structure associated with the host. - * @rctxid: Desired context by id. - * @file: Desired context by file. - * - * Return: Found context on success, NULL on failure - */ -static struct ctx_info *find_error_context(struct cxlflash_cfg *cfg, u64 rctxid, - struct file *file) -{ - struct ctx_info *ctxi; - - list_for_each_entry(ctxi, &cfg->ctx_err_recovery, list) - if ((ctxi->ctxid == rctxid) || (ctxi->file == file)) - return ctxi; - - return NULL; -} - -/** - * get_context() - obtains a validated and locked context reference - * @cfg: Internal structure associated with the host. - * @rctxid: Desired context (raw, un-decoded format). - * @arg: LUN information or file associated with request. - * @ctx_ctrl: Control information to 'steer' desired lookup. - * - * NOTE: despite the name pid, in linux, current->pid actually refers - * to the lightweight process id (tid) and can change if the process is - * multi threaded. The tgid remains constant for the process and only changes - * when the process of fork. For all intents and purposes, think of tgid - * as a pid in the traditional sense. - * - * Return: Validated context on success, NULL on failure - */ -struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, - void *arg, enum ctx_ctrl ctx_ctrl) -{ - struct device *dev = &cfg->dev->dev; - struct ctx_info *ctxi = NULL; - struct lun_access *lun_access = NULL; - struct file *file = NULL; - struct llun_info *lli = arg; - u64 ctxid = DECODE_CTXID(rctxid); - int rc; - pid_t pid = task_tgid_nr(current), ctxpid = 0; - - if (ctx_ctrl & CTX_CTRL_FILE) { - lli = NULL; - file = (struct file *)arg; - } - - if (ctx_ctrl & CTX_CTRL_CLONE) - pid = task_ppid_nr(current); - - if (likely(ctxid < MAX_CONTEXT)) { - while (true) { - mutex_lock(&cfg->ctx_tbl_list_mutex); - ctxi = cfg->ctx_tbl[ctxid]; - if (ctxi) - if ((file && (ctxi->file != file)) || - (!file && (ctxi->ctxid != rctxid))) - ctxi = NULL; - - if ((ctx_ctrl & CTX_CTRL_ERR) || - (!ctxi && (ctx_ctrl & CTX_CTRL_ERR_FALLBACK))) - ctxi = find_error_context(cfg, rctxid, file); - if (!ctxi) { - mutex_unlock(&cfg->ctx_tbl_list_mutex); - goto out; - } - - /* - * Need to acquire ownership of the context while still - * under the table/list lock to serialize with a remove - * thread. Use the 'try' to avoid stalling the - * table/list lock for a single context. - * - * Note that the lock order is: - * - * cfg->ctx_tbl_list_mutex -> ctxi->mutex - * - * Therefore release ctx_tbl_list_mutex before retrying. - */ - rc = mutex_trylock(&ctxi->mutex); - mutex_unlock(&cfg->ctx_tbl_list_mutex); - if (rc) - break; /* got the context's lock! */ - } - - if (ctxi->unavail) - goto denied; - - ctxpid = ctxi->pid; - if (likely(!(ctx_ctrl & CTX_CTRL_NOPID))) - if (pid != ctxpid) - goto denied; - - if (lli) { - list_for_each_entry(lun_access, &ctxi->luns, list) - if (lun_access->lli == lli) - goto out; - goto denied; - } - } - -out: - dev_dbg(dev, "%s: rctxid=%016llx ctxinfo=%p ctxpid=%u pid=%u " - "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, - ctx_ctrl); - - return ctxi; - -denied: - mutex_unlock(&ctxi->mutex); - ctxi = NULL; - goto out; -} - -/** - * put_context() - release a context that was retrieved from get_context() - * @ctxi: Context to release. - * - * For now, releasing the context equates to unlocking it's mutex. - */ -void put_context(struct ctx_info *ctxi) -{ - mutex_unlock(&ctxi->mutex); -} - -/** - * afu_attach() - attach a context to the AFU - * @cfg: Internal structure associated with the host. - * @ctxi: Context to attach. - * - * Upon setting the context capabilities, they must be confirmed with - * a read back operation as the context might have been closed since - * the mailbox was unlocked. When this occurs, registration is failed. - * - * Return: 0 on success, -errno on failure - */ -static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) -{ - struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct sisl_ctrl_map __iomem *ctrl_map = ctxi->ctrl_map; - int rc = 0; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); - u64 val; - int i; - - /* Unlock cap and restrict user to read/write cmds in translated mode */ - readq_be(&ctrl_map->mbox_r); - val = (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD); - writeq_be(val, &ctrl_map->ctx_cap); - val = readq_be(&ctrl_map->ctx_cap); - if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { - dev_err(dev, "%s: ctx may be closed val=%016llx\n", - __func__, val); - rc = -EAGAIN; - goto out; - } - - if (afu_is_ocxl_lisn(afu)) { - /* Set up the LISN effective address for each interrupt */ - for (i = 0; i < ctxi->irqs; i++) { - val = cfg->ops->get_irq_objhndl(ctxi->ctx, i); - writeq_be(val, &ctrl_map->lisn_ea[i]); - } - - /* Use primary HWQ PASID as identifier for all interrupts */ - val = hwq->ctx_hndl; - writeq_be(SISL_LISN_PASID(val, val), &ctrl_map->lisn_pasid[0]); - writeq_be(SISL_LISN_PASID(0UL, val), &ctrl_map->lisn_pasid[1]); - } - - /* Set up MMIO registers pointing to the RHT */ - writeq_be((u64)ctxi->rht_start, &ctrl_map->rht_start); - val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(hwq->ctx_hndl)); - writeq_be(val, &ctrl_map->rht_cnt_id); -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * read_cap16() - issues a SCSI READ_CAP16 command - * @sdev: SCSI device associated with LUN. - * @lli: LUN destined for capacity request. - * - * The READ_CAP16 can take quite a while to complete. Should an EEH occur while - * in scsi_execute_cmd(), the EEH handler will attempt to recover. As part of - * the recovery, the handler drains all currently running ioctls, waiting until - * they have completed before proceeding with a reset. As this routine is used - * on the ioctl path, this can create a condition where the EEH handler becomes - * stuck, infinitely waiting for this ioctl thread. To avoid this behavior, - * temporarily unmark this thread as an ioctl thread by releasing the ioctl - * read semaphore. This will allow the EEH handler to proceed with a recovery - * while this thread is still running. Once the scsi_execute_cmd() returns, - * reacquire the ioctl read semaphore and check the adapter state in case it - * changed while inside of scsi_execute_cmd(). The state check will wait if the - * adapter is still being recovered or return a failure if the recovery failed. - * In the event that the adapter reset failed, simply return the failure as the - * ioctl would be unable to continue. - * - * Note that the above puts a requirement on this routine to only be called on - * an ioctl thread. - * - * Return: 0 on success, -errno on failure - */ -static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct glun_info *gli = lli->parent; - struct scsi_sense_hdr sshdr; - const struct scsi_exec_args exec_args = { - .sshdr = &sshdr, - }; - u8 *cmd_buf = NULL; - u8 *scsi_cmd = NULL; - int rc = 0; - int result = 0; - int retry_cnt = 0; - u32 to = CMD_TIMEOUT * HZ; - -retry: - cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); - scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); - if (unlikely(!cmd_buf || !scsi_cmd)) { - rc = -ENOMEM; - goto out; - } - - scsi_cmd[0] = SERVICE_ACTION_IN_16; /* read cap(16) */ - scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ - put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); - - dev_dbg(dev, "%s: %ssending cmd(%02x)\n", __func__, - retry_cnt ? "re" : "", scsi_cmd[0]); - - /* Drop the ioctl read semaphore across lengthy call */ - up_read(&cfg->ioctl_rwsem); - result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, cmd_buf, - CMD_BUFSIZE, to, CMD_RETRIES, &exec_args); - down_read(&cfg->ioctl_rwsem); - rc = check_state(cfg); - if (rc) { - dev_err(dev, "%s: Failed state result=%08x\n", - __func__, result); - rc = -ENODEV; - goto out; - } - - if (result > 0 && scsi_sense_valid(&sshdr)) { - if (result & SAM_STAT_CHECK_CONDITION) { - switch (sshdr.sense_key) { - case NO_SENSE: - case RECOVERED_ERROR: - case NOT_READY: - result &= ~SAM_STAT_CHECK_CONDITION; - break; - case UNIT_ATTENTION: - switch (sshdr.asc) { - case 0x29: /* Power on Reset or Device Reset */ - fallthrough; - case 0x2A: /* Device capacity changed */ - case 0x3F: /* Report LUNs changed */ - /* Retry the command once more */ - if (retry_cnt++ < 1) { - kfree(cmd_buf); - kfree(scsi_cmd); - goto retry; - } - } - break; - default: - break; - } - } - } - - if (result) { - dev_err(dev, "%s: command failed, result=%08x\n", - __func__, result); - rc = -EIO; - goto out; - } - - /* - * Read cap was successful, grab values from the buffer; - * note that we don't need to worry about unaligned access - * as the buffer is allocated on an aligned boundary. - */ - mutex_lock(&gli->mutex); - gli->max_lba = be64_to_cpu(*((__be64 *)&cmd_buf[0])); - gli->blk_len = be32_to_cpu(*((__be32 *)&cmd_buf[8])); - mutex_unlock(&gli->mutex); - -out: - kfree(cmd_buf); - kfree(scsi_cmd); - - dev_dbg(dev, "%s: maxlba=%lld blklen=%d rc=%d\n", - __func__, gli->max_lba, gli->blk_len, rc); - return rc; -} - -/** - * get_rhte() - obtains validated resource handle table entry reference - * @ctxi: Context owning the resource handle. - * @rhndl: Resource handle associated with entry. - * @lli: LUN associated with request. - * - * Return: Validated RHTE on success, NULL on failure - */ -struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, - struct llun_info *lli) -{ - struct cxlflash_cfg *cfg = ctxi->cfg; - struct device *dev = &cfg->dev->dev; - struct sisl_rht_entry *rhte = NULL; - - if (unlikely(!ctxi->rht_start)) { - dev_dbg(dev, "%s: Context does not have allocated RHT\n", - __func__); - goto out; - } - - if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { - dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", - __func__, rhndl); - goto out; - } - - if (unlikely(ctxi->rht_lun[rhndl] != lli)) { - dev_dbg(dev, "%s: Bad resource handle LUN rhndl=%d\n", - __func__, rhndl); - goto out; - } - - rhte = &ctxi->rht_start[rhndl]; - if (unlikely(rhte->nmask == 0)) { - dev_dbg(dev, "%s: Unopened resource handle rhndl=%d\n", - __func__, rhndl); - rhte = NULL; - goto out; - } - -out: - return rhte; -} - -/** - * rhte_checkout() - obtains free/empty resource handle table entry - * @ctxi: Context owning the resource handle. - * @lli: LUN associated with request. - * - * Return: Free RHTE on success, NULL on failure - */ -struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, - struct llun_info *lli) -{ - struct cxlflash_cfg *cfg = ctxi->cfg; - struct device *dev = &cfg->dev->dev; - struct sisl_rht_entry *rhte = NULL; - int i; - - /* Find a free RHT entry */ - for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) - if (ctxi->rht_start[i].nmask == 0) { - rhte = &ctxi->rht_start[i]; - ctxi->rht_out++; - break; - } - - if (likely(rhte)) - ctxi->rht_lun[i] = lli; - - dev_dbg(dev, "%s: returning rhte=%p index=%d\n", __func__, rhte, i); - return rhte; -} - -/** - * rhte_checkin() - releases a resource handle table entry - * @ctxi: Context owning the resource handle. - * @rhte: RHTE to release. - */ -void rhte_checkin(struct ctx_info *ctxi, - struct sisl_rht_entry *rhte) -{ - u32 rsrc_handle = rhte - ctxi->rht_start; - - rhte->nmask = 0; - rhte->fp = 0; - ctxi->rht_out--; - ctxi->rht_lun[rsrc_handle] = NULL; - ctxi->rht_needs_ws[rsrc_handle] = false; -} - -/** - * rht_format1() - populates a RHTE for format 1 - * @rhte: RHTE to populate. - * @lun_id: LUN ID of LUN associated with RHTE. - * @perm: Desired permissions for RHTE. - * @port_sel: Port selection mask - */ -static void rht_format1(struct sisl_rht_entry *rhte, u64 lun_id, u32 perm, - u32 port_sel) -{ - /* - * Populate the Format 1 RHT entry for direct access (physical - * LUN) using the synchronization sequence defined in the - * SISLite specification. - */ - struct sisl_rht_entry_f1 dummy = { 0 }; - struct sisl_rht_entry_f1 *rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; - - memset(rhte_f1, 0, sizeof(*rhte_f1)); - rhte_f1->fp = SISL_RHT_FP(1U, 0); - dma_wmb(); /* Make setting of format bit visible */ - - rhte_f1->lun_id = lun_id; - dma_wmb(); /* Make setting of LUN id visible */ - - /* - * Use a dummy RHT Format 1 entry to build the second dword - * of the entry that must be populated in a single write when - * enabled (valid bit set to TRUE). - */ - dummy.valid = 0x80; - dummy.fp = SISL_RHT_FP(1U, perm); - dummy.port_sel = port_sel; - rhte_f1->dw = dummy.dw; - - dma_wmb(); /* Make remaining RHT entry fields visible */ -} - -/** - * cxlflash_lun_attach() - attaches a user to a LUN and manages the LUN's mode - * @gli: LUN to attach. - * @mode: Desired mode of the LUN. - * @locked: Mutex status on current thread. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) -{ - int rc = 0; - - if (!locked) - mutex_lock(&gli->mutex); - - if (gli->mode == MODE_NONE) - gli->mode = mode; - else if (gli->mode != mode) { - pr_debug("%s: gli_mode=%d requested_mode=%d\n", - __func__, gli->mode, mode); - rc = -EINVAL; - goto out; - } - - gli->users++; - WARN_ON(gli->users <= 0); -out: - pr_debug("%s: Returning rc=%d gli->mode=%u gli->users=%u\n", - __func__, rc, gli->mode, gli->users); - if (!locked) - mutex_unlock(&gli->mutex); - return rc; -} - -/** - * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode - * @gli: LUN to detach. - * - * When resetting the mode, terminate block allocation resources as they - * are no longer required (service is safe to call even when block allocation - * resources were not present - such as when transitioning from physical mode). - * These resources will be reallocated when needed (subsequent transition to - * virtual mode). - */ -void cxlflash_lun_detach(struct glun_info *gli) -{ - mutex_lock(&gli->mutex); - WARN_ON(gli->mode == MODE_NONE); - if (--gli->users == 0) { - gli->mode = MODE_NONE; - cxlflash_ba_terminate(&gli->blka.ba_lun); - } - pr_debug("%s: gli->users=%u\n", __func__, gli->users); - WARN_ON(gli->users < 0); - mutex_unlock(&gli->mutex); -} - -/** - * _cxlflash_disk_release() - releases the specified resource entry - * @sdev: SCSI device associated with LUN. - * @ctxi: Context owning resources. - * @release: Release ioctl data structure. - * - * For LUNs in virtual mode, the virtual LUN associated with the specified - * resource handle is resized to 0 prior to releasing the RHTE. Note that the - * AFU sync should _not_ be performed when the context is sitting on the error - * recovery list. A context on the error recovery list is not known to the AFU - * due to reset. When the context is recovered, it will be reattached and made - * known again to the AFU. - * - * Return: 0 on success, -errno on failure - */ -int _cxlflash_disk_release(struct scsi_device *sdev, - struct ctx_info *ctxi, - struct dk_cxlflash_release *release) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct afu *afu = cfg->afu; - bool put_ctx = false; - - struct dk_cxlflash_resize size; - res_hndl_t rhndl = release->rsrc_handle; - - int rc = 0; - int rcr = 0; - u64 ctxid = DECODE_CTXID(release->context_id), - rctxid = release->context_id; - - struct sisl_rht_entry *rhte; - struct sisl_rht_entry_f1 *rhte_f1; - - dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu gli->mode=%u gli->users=%u\n", - __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); - - if (!ctxi) { - ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", - __func__, ctxid); - rc = -EINVAL; - goto out; - } - - put_ctx = true; - } - - rhte = get_rhte(ctxi, rhndl, lli); - if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", - __func__, rhndl); - rc = -EINVAL; - goto out; - } - - /* - * Resize to 0 for virtual LUNS by setting the size - * to 0. This will clear LXT_START and LXT_CNT fields - * in the RHT entry and properly sync with the AFU. - * - * Afterwards we clear the remaining fields. - */ - switch (gli->mode) { - case MODE_VIRTUAL: - marshal_rele_to_resize(release, &size); - size.req_size = 0; - rc = _cxlflash_vlun_resize(sdev, ctxi, &size); - if (rc) { - dev_dbg(dev, "%s: resize failed rc %d\n", __func__, rc); - goto out; - } - - break; - case MODE_PHYSICAL: - /* - * Clear the Format 1 RHT entry for direct access - * (physical LUN) using the synchronization sequence - * defined in the SISLite specification. - */ - rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; - - rhte_f1->valid = 0; - dma_wmb(); /* Make revocation of RHT entry visible */ - - rhte_f1->lun_id = 0; - dma_wmb(); /* Make clearing of LUN id visible */ - - rhte_f1->dw = 0; - dma_wmb(); /* Make RHT entry bottom-half clearing visible */ - - if (!ctxi->err_recovery_active) { - rcr = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); - if (unlikely(rcr)) - dev_dbg(dev, "%s: AFU sync failed rc=%d\n", - __func__, rcr); - } - break; - default: - WARN(1, "Unsupported LUN mode!"); - goto out; - } - - rhte_checkin(ctxi, rhte); - cxlflash_lun_detach(gli); - -out: - if (put_ctx) - put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -int cxlflash_disk_release(struct scsi_device *sdev, void *release) -{ - return _cxlflash_disk_release(sdev, NULL, release); -} - -/** - * destroy_context() - releases a context - * @cfg: Internal structure associated with the host. - * @ctxi: Context to release. - * - * This routine is safe to be called with a a non-initialized context. - * Also note that the routine conditionally checks for the existence - * of the context control map before clearing the RHT registers and - * context capabilities because it is possible to destroy a context - * while the context is in the error state (previous mapping was - * removed [so there is no need to worry about clearing] and context - * is waiting for a new mapping). - */ -static void destroy_context(struct cxlflash_cfg *cfg, - struct ctx_info *ctxi) -{ - struct afu *afu = cfg->afu; - - if (ctxi->initialized) { - WARN_ON(!list_empty(&ctxi->luns)); - - /* Clear RHT registers and drop all capabilities for context */ - if (afu->afu_map && ctxi->ctrl_map) { - writeq_be(0, &ctxi->ctrl_map->rht_start); - writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); - writeq_be(0, &ctxi->ctrl_map->ctx_cap); - } - } - - /* Free memory associated with context */ - free_page((ulong)ctxi->rht_start); - kfree(ctxi->rht_needs_ws); - kfree(ctxi->rht_lun); - kfree(ctxi); -} - -/** - * create_context() - allocates and initializes a context - * @cfg: Internal structure associated with the host. - * - * Return: Allocated context on success, NULL on failure - */ -static struct ctx_info *create_context(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - struct ctx_info *ctxi = NULL; - struct llun_info **lli = NULL; - u8 *ws = NULL; - struct sisl_rht_entry *rhte; - - ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); - lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); - ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); - if (unlikely(!ctxi || !lli || !ws)) { - dev_err(dev, "%s: Unable to allocate context\n", __func__); - goto err; - } - - rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); - if (unlikely(!rhte)) { - dev_err(dev, "%s: Unable to allocate RHT\n", __func__); - goto err; - } - - ctxi->rht_lun = lli; - ctxi->rht_needs_ws = ws; - ctxi->rht_start = rhte; -out: - return ctxi; - -err: - kfree(ws); - kfree(lli); - kfree(ctxi); - ctxi = NULL; - goto out; -} - -/** - * init_context() - initializes a previously allocated context - * @ctxi: Previously allocated context - * @cfg: Internal structure associated with the host. - * @ctx: Previously obtained context cookie. - * @ctxid: Previously obtained process element associated with CXL context. - * @file: Previously obtained file associated with CXL context. - * @perms: User-specified permissions. - * @irqs: User-specified number of interrupts. - */ -static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg, - void *ctx, int ctxid, struct file *file, u32 perms, - u64 irqs) -{ - struct afu *afu = cfg->afu; - - ctxi->rht_perms = perms; - ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; - ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); - ctxi->irqs = irqs; - ctxi->pid = task_tgid_nr(current); /* tgid = pid */ - ctxi->ctx = ctx; - ctxi->cfg = cfg; - ctxi->file = file; - ctxi->initialized = true; - mutex_init(&ctxi->mutex); - kref_init(&ctxi->kref); - INIT_LIST_HEAD(&ctxi->luns); - INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ -} - -/** - * remove_context() - context kref release handler - * @kref: Kernel reference associated with context to be removed. - * - * When a context no longer has any references it can safely be removed - * from global access and destroyed. Note that it is assumed the thread - * relinquishing access to the context holds its mutex. - */ -static void remove_context(struct kref *kref) -{ - struct ctx_info *ctxi = container_of(kref, struct ctx_info, kref); - struct cxlflash_cfg *cfg = ctxi->cfg; - u64 ctxid = DECODE_CTXID(ctxi->ctxid); - - /* Remove context from table/error list */ - WARN_ON(!mutex_is_locked(&ctxi->mutex)); - ctxi->unavail = true; - mutex_unlock(&ctxi->mutex); - mutex_lock(&cfg->ctx_tbl_list_mutex); - mutex_lock(&ctxi->mutex); - - if (!list_empty(&ctxi->list)) - list_del(&ctxi->list); - cfg->ctx_tbl[ctxid] = NULL; - mutex_unlock(&cfg->ctx_tbl_list_mutex); - mutex_unlock(&ctxi->mutex); - - /* Context now completely uncoupled/unreachable */ - destroy_context(cfg, ctxi); -} - -/** - * _cxlflash_disk_detach() - detaches a LUN from a context - * @sdev: SCSI device associated with LUN. - * @ctxi: Context owning resources. - * @detach: Detach ioctl data structure. - * - * As part of the detach, all per-context resources associated with the LUN - * are cleaned up. When detaching the last LUN for a context, the context - * itself is cleaned up and released. - * - * Return: 0 on success, -errno on failure - */ -static int _cxlflash_disk_detach(struct scsi_device *sdev, - struct ctx_info *ctxi, - struct dk_cxlflash_detach *detach) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct lun_access *lun_access, *t; - struct dk_cxlflash_release rel; - bool put_ctx = false; - - int i; - int rc = 0; - u64 ctxid = DECODE_CTXID(detach->context_id), - rctxid = detach->context_id; - - dev_dbg(dev, "%s: ctxid=%llu\n", __func__, ctxid); - - if (!ctxi) { - ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", - __func__, ctxid); - rc = -EINVAL; - goto out; - } - - put_ctx = true; - } - - /* Cleanup outstanding resources tied to this LUN */ - if (ctxi->rht_out) { - marshal_det_to_rele(detach, &rel); - for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { - if (ctxi->rht_lun[i] == lli) { - rel.rsrc_handle = i; - _cxlflash_disk_release(sdev, ctxi, &rel); - } - - /* No need to loop further if we're done */ - if (ctxi->rht_out == 0) - break; - } - } - - /* Take our LUN out of context, free the node */ - list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) - if (lun_access->lli == lli) { - list_del(&lun_access->list); - kfree(lun_access); - lun_access = NULL; - break; - } - - /* - * Release the context reference and the sdev reference that - * bound this LUN to the context. - */ - if (kref_put(&ctxi->kref, remove_context)) - put_ctx = false; - scsi_device_put(sdev); -out: - if (put_ctx) - put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -static int cxlflash_disk_detach(struct scsi_device *sdev, void *detach) -{ - return _cxlflash_disk_detach(sdev, NULL, detach); -} - -/** - * cxlflash_cxl_release() - release handler for adapter file descriptor - * @inode: File-system inode associated with fd. - * @file: File installed with adapter file descriptor. - * - * This routine is the release handler for the fops registered with - * the CXL services on an initial attach for a context. It is called - * when a close (explicitly by the user or as part of a process tear - * down) is performed on the adapter file descriptor returned to the - * user. The user should be aware that explicitly performing a close - * considered catastrophic and subsequent usage of the superpipe API - * with previously saved off tokens will fail. - * - * This routine derives the context reference and calls detach for - * each LUN associated with the context.The final detach operation - * causes the context itself to be freed. With exception to when the - * CXL process element (context id) lookup fails (a case that should - * theoretically never occur), every call into this routine results - * in a complete freeing of a context. - * - * Detaching the LUN is typically an ioctl() operation and the underlying - * code assumes that ioctl_rwsem has been acquired as a reader. To support - * that design point, the semaphore is acquired and released around detach. - * - * Return: 0 on success - */ -static int cxlflash_cxl_release(struct inode *inode, struct file *file) -{ - struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, - cxl_fops); - void *ctx = cfg->ops->fops_get_context(file); - struct device *dev = &cfg->dev->dev; - struct ctx_info *ctxi = NULL; - struct dk_cxlflash_detach detach = { { 0 }, 0 }; - struct lun_access *lun_access, *t; - enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; - int ctxid; - - ctxid = cfg->ops->process_element(ctx); - if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed ctxid=%d\n", - __func__, ctx, ctxid); - goto out; - } - - ctxi = get_context(cfg, ctxid, file, ctrl); - if (unlikely(!ctxi)) { - ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); - if (!ctxi) { - dev_dbg(dev, "%s: ctxid=%d already free\n", - __func__, ctxid); - goto out_release; - } - - dev_dbg(dev, "%s: Another process owns ctxid=%d\n", - __func__, ctxid); - put_context(ctxi); - goto out; - } - - dev_dbg(dev, "%s: close for ctxid=%d\n", __func__, ctxid); - - down_read(&cfg->ioctl_rwsem); - detach.context_id = ctxi->ctxid; - list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) - _cxlflash_disk_detach(lun_access->sdev, ctxi, &detach); - up_read(&cfg->ioctl_rwsem); -out_release: - cfg->ops->fd_release(inode, file); -out: - dev_dbg(dev, "%s: returning\n", __func__); - return 0; -} - -/** - * unmap_context() - clears a previously established mapping - * @ctxi: Context owning the mapping. - * - * This routine is used to switch between the error notification page - * (dummy page of all 1's) and the real mapping (established by the CXL - * fault handler). - */ -static void unmap_context(struct ctx_info *ctxi) -{ - unmap_mapping_range(ctxi->file->f_mapping, 0, 0, 1); -} - -/** - * get_err_page() - obtains and allocates the error notification page - * @cfg: Internal structure associated with the host. - * - * Return: error notification page on success, NULL on failure - */ -static struct page *get_err_page(struct cxlflash_cfg *cfg) -{ - struct page *err_page = global.err_page; - struct device *dev = &cfg->dev->dev; - - if (unlikely(!err_page)) { - err_page = alloc_page(GFP_KERNEL); - if (unlikely(!err_page)) { - dev_err(dev, "%s: Unable to allocate err_page\n", - __func__); - goto out; - } - - memset(page_address(err_page), -1, PAGE_SIZE); - - /* Serialize update w/ other threads to avoid a leak */ - mutex_lock(&global.mutex); - if (likely(!global.err_page)) - global.err_page = err_page; - else { - __free_page(err_page); - err_page = global.err_page; - } - mutex_unlock(&global.mutex); - } - -out: - dev_dbg(dev, "%s: returning err_page=%p\n", __func__, err_page); - return err_page; -} - -/** - * cxlflash_mmap_fault() - mmap fault handler for adapter file descriptor - * @vmf: VM fault associated with current fault. - * - * To support error notification via MMIO, faults are 'caught' by this routine - * that was inserted before passing back the adapter file descriptor on attach. - * When a fault occurs, this routine evaluates if error recovery is active and - * if so, installs the error page to 'notify' the user about the error state. - * During normal operation, the fault is simply handled by the original fault - * handler that was installed by CXL services as part of initializing the - * adapter file descriptor. The VMA's page protection bits are toggled to - * indicate cached/not-cached depending on the memory backing the fault. - * - * Return: 0 on success, VM_FAULT_SIGBUS on failure - */ -static vm_fault_t cxlflash_mmap_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct file *file = vma->vm_file; - struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, - cxl_fops); - void *ctx = cfg->ops->fops_get_context(file); - struct device *dev = &cfg->dev->dev; - struct ctx_info *ctxi = NULL; - struct page *err_page = NULL; - enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; - vm_fault_t rc = 0; - int ctxid; - - ctxid = cfg->ops->process_element(ctx); - if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed ctxid=%d\n", - __func__, ctx, ctxid); - goto err; - } - - ctxi = get_context(cfg, ctxid, file, ctrl); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); - goto err; - } - - dev_dbg(dev, "%s: fault for context %d\n", __func__, ctxid); - - if (likely(!ctxi->err_recovery_active)) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - rc = ctxi->cxl_mmap_vmops->fault(vmf); - } else { - dev_dbg(dev, "%s: err recovery active, use err_page\n", - __func__); - - err_page = get_err_page(cfg); - if (unlikely(!err_page)) { - dev_err(dev, "%s: Could not get err_page\n", __func__); - rc = VM_FAULT_RETRY; - goto out; - } - - get_page(err_page); - vmf->page = err_page; - vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); - } - -out: - if (likely(ctxi)) - put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%x\n", __func__, rc); - return rc; - -err: - rc = VM_FAULT_SIGBUS; - goto out; -} - -/* - * Local MMAP vmops to 'catch' faults - */ -static const struct vm_operations_struct cxlflash_mmap_vmops = { - .fault = cxlflash_mmap_fault, -}; - -/** - * cxlflash_cxl_mmap() - mmap handler for adapter file descriptor - * @file: File installed with adapter file descriptor. - * @vma: VM area associated with mapping. - * - * Installs local mmap vmops to 'catch' faults for error notification support. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, - cxl_fops); - void *ctx = cfg->ops->fops_get_context(file); - struct device *dev = &cfg->dev->dev; - struct ctx_info *ctxi = NULL; - enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; - int ctxid; - int rc = 0; - - ctxid = cfg->ops->process_element(ctx); - if (unlikely(ctxid < 0)) { - dev_err(dev, "%s: Context %p was closed ctxid=%d\n", - __func__, ctx, ctxid); - rc = -EIO; - goto out; - } - - ctxi = get_context(cfg, ctxid, file, ctrl); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); - rc = -EIO; - goto out; - } - - dev_dbg(dev, "%s: mmap for context %d\n", __func__, ctxid); - - rc = cfg->ops->fd_mmap(file, vma); - if (likely(!rc)) { - /* Insert ourself in the mmap fault handler path */ - ctxi->cxl_mmap_vmops = vma->vm_ops; - vma->vm_ops = &cxlflash_mmap_vmops; - } - -out: - if (likely(ctxi)) - put_context(ctxi); - return rc; -} - -const struct file_operations cxlflash_cxl_fops = { - .owner = THIS_MODULE, - .mmap = cxlflash_cxl_mmap, - .release = cxlflash_cxl_release, -}; - -/** - * cxlflash_mark_contexts_error() - move contexts to error state and list - * @cfg: Internal structure associated with the host. - * - * A context is only moved over to the error list when there are no outstanding - * references to it. This ensures that a running operation has completed. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg) -{ - int i, rc = 0; - struct ctx_info *ctxi = NULL; - - mutex_lock(&cfg->ctx_tbl_list_mutex); - - for (i = 0; i < MAX_CONTEXT; i++) { - ctxi = cfg->ctx_tbl[i]; - if (ctxi) { - mutex_lock(&ctxi->mutex); - cfg->ctx_tbl[i] = NULL; - list_add(&ctxi->list, &cfg->ctx_err_recovery); - ctxi->err_recovery_active = true; - ctxi->ctrl_map = NULL; - unmap_context(ctxi); - mutex_unlock(&ctxi->mutex); - } - } - - mutex_unlock(&cfg->ctx_tbl_list_mutex); - return rc; -} - -/* - * Dummy NULL fops - */ -static const struct file_operations null_fops = { - .owner = THIS_MODULE, -}; - -/** - * check_state() - checks and responds to the current adapter state - * @cfg: Internal structure associated with the host. - * - * This routine can block and should only be used on process context. - * It assumes that the caller is an ioctl thread and holding the ioctl - * read semaphore. This is temporarily let up across the wait to allow - * for draining actively running ioctls. Also note that when waking up - * from waiting in reset, the state is unknown and must be checked again - * before proceeding. - * - * Return: 0 on success, -errno on failure - */ -int check_state(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int rc = 0; - -retry: - switch (cfg->state) { - case STATE_RESET: - dev_dbg(dev, "%s: Reset state, going to wait...\n", __func__); - up_read(&cfg->ioctl_rwsem); - rc = wait_event_interruptible(cfg->reset_waitq, - cfg->state != STATE_RESET); - down_read(&cfg->ioctl_rwsem); - if (unlikely(rc)) - break; - goto retry; - case STATE_FAILTERM: - dev_dbg(dev, "%s: Failed/Terminating\n", __func__); - rc = -ENODEV; - break; - default: - break; - } - - return rc; -} - -/** - * cxlflash_disk_attach() - attach a LUN to a context - * @sdev: SCSI device associated with LUN. - * @arg: Attach ioctl data structure. - * - * Creates a context and attaches LUN to it. A LUN can only be attached - * one time to a context (subsequent attaches for the same context/LUN pair - * are not supported). Additional LUNs can be attached to a context by - * specifying the 'reuse' flag defined in the cxlflash_ioctl.h header. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_disk_attach(struct scsi_device *sdev, void *arg) -{ - struct dk_cxlflash_attach *attach = arg; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct ctx_info *ctxi = NULL; - struct lun_access *lun_access = NULL; - int rc = 0; - u32 perms; - int ctxid = -1; - u64 irqs = attach->num_interrupts; - u64 flags = 0UL; - u64 rctxid = 0UL; - struct file *file = NULL; - - void *ctx = NULL; - - int fd = -1; - - if (irqs > 4) { - dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", - __func__, irqs); - rc = -EINVAL; - goto out; - } - - if (gli->max_lba == 0) { - dev_dbg(dev, "%s: No capacity info for LUN=%016llx\n", - __func__, lli->lun_id[sdev->channel]); - rc = read_cap16(sdev, lli); - if (rc) { - dev_err(dev, "%s: Invalid device rc=%d\n", - __func__, rc); - rc = -ENODEV; - goto out; - } - dev_dbg(dev, "%s: LBA = %016llx\n", __func__, gli->max_lba); - dev_dbg(dev, "%s: BLK_LEN = %08x\n", __func__, gli->blk_len); - } - - if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { - rctxid = attach->context_id; - ctxi = get_context(cfg, rctxid, NULL, 0); - if (!ctxi) { - dev_dbg(dev, "%s: Bad context rctxid=%016llx\n", - __func__, rctxid); - rc = -EINVAL; - goto out; - } - - list_for_each_entry(lun_access, &ctxi->luns, list) - if (lun_access->lli == lli) { - dev_dbg(dev, "%s: Already attached\n", - __func__); - rc = -EINVAL; - goto out; - } - } - - rc = scsi_device_get(sdev); - if (unlikely(rc)) { - dev_err(dev, "%s: Unable to get sdev reference\n", __func__); - goto out; - } - - lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); - if (unlikely(!lun_access)) { - dev_err(dev, "%s: Unable to allocate lun_access\n", __func__); - rc = -ENOMEM; - goto err; - } - - lun_access->lli = lli; - lun_access->sdev = sdev; - - /* Non-NULL context indicates reuse (another context reference) */ - if (ctxi) { - dev_dbg(dev, "%s: Reusing context for LUN rctxid=%016llx\n", - __func__, rctxid); - kref_get(&ctxi->kref); - list_add(&lun_access->list, &ctxi->luns); - goto out_attach; - } - - ctxi = create_context(cfg); - if (unlikely(!ctxi)) { - dev_err(dev, "%s: Failed to create context ctxid=%d\n", - __func__, ctxid); - rc = -ENOMEM; - goto err; - } - - ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); - if (IS_ERR_OR_NULL(ctx)) { - dev_err(dev, "%s: Could not initialize context %p\n", - __func__, ctx); - rc = -ENODEV; - goto err; - } - - rc = cfg->ops->start_work(ctx, irqs); - if (unlikely(rc)) { - dev_dbg(dev, "%s: Could not start context rc=%d\n", - __func__, rc); - goto err; - } - - ctxid = cfg->ops->process_element(ctx); - if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); - rc = -EPERM; - goto err; - } - - file = cfg->ops->get_fd(ctx, &cfg->cxl_fops, &fd); - if (unlikely(fd < 0)) { - rc = -ENODEV; - dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err; - } - - /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ - perms = SISL_RHT_PERM(attach->hdr.flags + 1); - - /* Context mutex is locked upon return */ - init_context(ctxi, cfg, ctx, ctxid, file, perms, irqs); - - rc = afu_attach(cfg, ctxi); - if (unlikely(rc)) { - dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); - goto err; - } - - /* - * No error paths after this point. Once the fd is installed it's - * visible to user space and can't be undone safely on this thread. - * There is no need to worry about a deadlock here because no one - * knows about us yet; we can be the only one holding our mutex. - */ - list_add(&lun_access->list, &ctxi->luns); - mutex_lock(&cfg->ctx_tbl_list_mutex); - mutex_lock(&ctxi->mutex); - cfg->ctx_tbl[ctxid] = ctxi; - mutex_unlock(&cfg->ctx_tbl_list_mutex); - fd_install(fd, file); - -out_attach: - if (fd != -1) - flags |= DK_CXLFLASH_APP_CLOSE_ADAP_FD; - if (afu_is_sq_cmd_mode(afu)) - flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; - - attach->hdr.return_flags = flags; - attach->context_id = ctxi->ctxid; - attach->block_size = gli->blk_len; - attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); - attach->last_lba = gli->max_lba; - attach->max_xfer = sdev->host->max_sectors * MAX_SECTOR_UNIT; - attach->max_xfer /= gli->blk_len; - -out: - attach->adap_fd = fd; - - if (ctxi) - put_context(ctxi); - - dev_dbg(dev, "%s: returning ctxid=%d fd=%d bs=%lld rc=%d llba=%lld\n", - __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); - return rc; - -err: - /* Cleanup CXL context; okay to 'stop' even if it was not started */ - if (!IS_ERR_OR_NULL(ctx)) { - cfg->ops->stop_context(ctx); - cfg->ops->release_context(ctx); - ctx = NULL; - } - - /* - * Here, we're overriding the fops with a dummy all-NULL fops because - * fput() calls the release fop, which will cause us to mistakenly - * call into the CXL code. Rather than try to add yet more complexity - * to that routine (cxlflash_cxl_release) we should try to fix the - * issue here. - */ - if (fd > 0) { - file->f_op = &null_fops; - fput(file); - put_unused_fd(fd); - fd = -1; - file = NULL; - } - - /* Cleanup our context */ - if (ctxi) { - destroy_context(cfg, ctxi); - ctxi = NULL; - } - - kfree(lun_access); - scsi_device_put(sdev); - goto out; -} - -/** - * recover_context() - recovers a context in error - * @cfg: Internal structure associated with the host. - * @ctxi: Context to release. - * @adap_fd: Adapter file descriptor associated with new/recovered context. - * - * Restablishes the state for a context-in-error. - * - * Return: 0 on success, -errno on failure - */ -static int recover_context(struct cxlflash_cfg *cfg, - struct ctx_info *ctxi, - int *adap_fd) -{ - struct device *dev = &cfg->dev->dev; - int rc = 0; - int fd = -1; - int ctxid = -1; - struct file *file; - void *ctx; - struct afu *afu = cfg->afu; - - ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); - if (IS_ERR_OR_NULL(ctx)) { - dev_err(dev, "%s: Could not initialize context %p\n", - __func__, ctx); - rc = -ENODEV; - goto out; - } - - rc = cfg->ops->start_work(ctx, ctxi->irqs); - if (unlikely(rc)) { - dev_dbg(dev, "%s: Could not start context rc=%d\n", - __func__, rc); - goto err1; - } - - ctxid = cfg->ops->process_element(ctx); - if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { - dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); - rc = -EPERM; - goto err2; - } - - file = cfg->ops->get_fd(ctx, &cfg->cxl_fops, &fd); - if (unlikely(fd < 0)) { - rc = -ENODEV; - dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err2; - } - - /* Update with new MMIO area based on updated context id */ - ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; - - rc = afu_attach(cfg, ctxi); - if (rc) { - dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); - goto err3; - } - - /* - * No error paths after this point. Once the fd is installed it's - * visible to user space and can't be undone safely on this thread. - */ - ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); - ctxi->ctx = ctx; - ctxi->file = file; - - /* - * Put context back in table (note the reinit of the context list); - * we must first drop the context's mutex and then acquire it in - * order with the table/list mutex to avoid a deadlock - safe to do - * here because no one can find us at this moment in time. - */ - mutex_unlock(&ctxi->mutex); - mutex_lock(&cfg->ctx_tbl_list_mutex); - mutex_lock(&ctxi->mutex); - list_del_init(&ctxi->list); - cfg->ctx_tbl[ctxid] = ctxi; - mutex_unlock(&cfg->ctx_tbl_list_mutex); - fd_install(fd, file); - *adap_fd = fd; -out: - dev_dbg(dev, "%s: returning ctxid=%d fd=%d rc=%d\n", - __func__, ctxid, fd, rc); - return rc; - -err3: - fput(file); - put_unused_fd(fd); -err2: - cfg->ops->stop_context(ctx); -err1: - cfg->ops->release_context(ctx); - goto out; -} - -/** - * cxlflash_afu_recover() - initiates AFU recovery - * @sdev: SCSI device associated with LUN. - * @arg: Recover ioctl data structure. - * - * Only a single recovery is allowed at a time to avoid exhausting CXL - * resources (leading to recovery failure) in the event that we're up - * against the maximum number of contexts limit. For similar reasons, - * a context recovery is retried if there are multiple recoveries taking - * place at the same time and the failure was due to CXL services being - * unable to keep up. - * - * As this routine is called on ioctl context, it holds the ioctl r/w - * semaphore that is used to drain ioctls in recovery scenarios. The - * implementation to achieve the pacing described above (a local mutex) - * requires that the ioctl r/w semaphore be dropped and reacquired to - * avoid a 3-way deadlock when multiple process recoveries operate in - * parallel. - * - * Because a user can detect an error condition before the kernel, it is - * quite possible for this routine to act as the kernel's EEH detection - * source (MMIO read of mbox_r). Because of this, there is a window of - * time where an EEH might have been detected but not yet 'serviced' - * (callback invoked, causing the device to enter reset state). To avoid - * looping in this routine during that window, a 1 second sleep is in place - * between the time the MMIO failure is detected and the time a wait on the - * reset wait queue is attempted via check_state(). - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_afu_recover(struct scsi_device *sdev, void *arg) -{ - struct dk_cxlflash_recover_afu *recover = arg; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct afu *afu = cfg->afu; - struct ctx_info *ctxi = NULL; - struct mutex *mutex = &cfg->ctx_recovery_mutex; - struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); - u64 flags; - u64 ctxid = DECODE_CTXID(recover->context_id), - rctxid = recover->context_id; - long reg; - bool locked = true; - int lretry = 20; /* up to 2 seconds */ - int new_adap_fd = -1; - int rc = 0; - - atomic_inc(&cfg->recovery_threads); - up_read(&cfg->ioctl_rwsem); - rc = mutex_lock_interruptible(mutex); - down_read(&cfg->ioctl_rwsem); - if (rc) { - locked = false; - goto out; - } - - rc = check_state(cfg); - if (rc) { - dev_err(dev, "%s: Failed state rc=%d\n", __func__, rc); - rc = -ENODEV; - goto out; - } - - dev_dbg(dev, "%s: reason=%016llx rctxid=%016llx\n", - __func__, recover->reason, rctxid); - -retry: - /* Ensure that this process is attached to the context */ - ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); - rc = -EINVAL; - goto out; - } - - if (ctxi->err_recovery_active) { -retry_recover: - rc = recover_context(cfg, ctxi, &new_adap_fd); - if (unlikely(rc)) { - dev_err(dev, "%s: Recovery failed ctxid=%llu rc=%d\n", - __func__, ctxid, rc); - if ((rc == -ENODEV) && - ((atomic_read(&cfg->recovery_threads) > 1) || - (lretry--))) { - dev_dbg(dev, "%s: Going to try again\n", - __func__); - mutex_unlock(mutex); - msleep(100); - rc = mutex_lock_interruptible(mutex); - if (rc) { - locked = false; - goto out; - } - goto retry_recover; - } - - goto out; - } - - ctxi->err_recovery_active = false; - - flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | - DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; - if (afu_is_sq_cmd_mode(afu)) - flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; - - recover->hdr.return_flags = flags; - recover->context_id = ctxi->ctxid; - recover->adap_fd = new_adap_fd; - recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); - goto out; - } - - /* Test if in error state */ - reg = readq_be(&hwq->ctrl_map->mbox_r); - if (reg == -1) { - dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__); - - /* - * Before checking the state, put back the context obtained with - * get_context() as it is no longer needed and sleep for a short - * period of time (see prolog notes). - */ - put_context(ctxi); - ctxi = NULL; - ssleep(1); - rc = check_state(cfg); - if (unlikely(rc)) - goto out; - goto retry; - } - - dev_dbg(dev, "%s: MMIO working, no recovery required\n", __func__); -out: - if (likely(ctxi)) - put_context(ctxi); - if (locked) - mutex_unlock(mutex); - atomic_dec_if_positive(&cfg->recovery_threads); - return rc; -} - -/** - * process_sense() - evaluates and processes sense data - * @sdev: SCSI device associated with LUN. - * @verify: Verify ioctl data structure. - * - * Return: 0 on success, -errno on failure - */ -static int process_sense(struct scsi_device *sdev, - struct dk_cxlflash_verify *verify) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - u64 prev_lba = gli->max_lba; - struct scsi_sense_hdr sshdr = { 0 }; - int rc = 0; - - rc = scsi_normalize_sense((const u8 *)&verify->sense_data, - DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); - if (!rc) { - dev_err(dev, "%s: Failed to normalize sense data\n", __func__); - rc = -EINVAL; - goto out; - } - - switch (sshdr.sense_key) { - case NO_SENSE: - case RECOVERED_ERROR: - case NOT_READY: - break; - case UNIT_ATTENTION: - switch (sshdr.asc) { - case 0x29: /* Power on Reset or Device Reset */ - fallthrough; - case 0x2A: /* Device settings/capacity changed */ - rc = read_cap16(sdev, lli); - if (rc) { - rc = -ENODEV; - break; - } - if (prev_lba != gli->max_lba) - dev_dbg(dev, "%s: Capacity changed old=%lld " - "new=%lld\n", __func__, prev_lba, - gli->max_lba); - break; - case 0x3F: /* Report LUNs changed, Rescan. */ - scsi_scan_host(cfg->host); - break; - default: - rc = -EIO; - break; - } - break; - default: - rc = -EIO; - break; - } -out: - dev_dbg(dev, "%s: sense_key %x asc %x ascq %x rc %d\n", __func__, - sshdr.sense_key, sshdr.asc, sshdr.ascq, rc); - return rc; -} - -/** - * cxlflash_disk_verify() - verifies a LUN is the same and handle size changes - * @sdev: SCSI device associated with LUN. - * @arg: Verify ioctl data structure. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_disk_verify(struct scsi_device *sdev, void *arg) -{ - struct dk_cxlflash_verify *verify = arg; - int rc = 0; - struct ctx_info *ctxi = NULL; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct sisl_rht_entry *rhte = NULL; - res_hndl_t rhndl = verify->rsrc_handle; - u64 ctxid = DECODE_CTXID(verify->context_id), - rctxid = verify->context_id; - u64 last_lba = 0; - - dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llx, hint=%016llx, " - "flags=%016llx\n", __func__, ctxid, verify->rsrc_handle, - verify->hint, verify->hdr.flags); - - ctxi = get_context(cfg, rctxid, lli, 0); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); - rc = -EINVAL; - goto out; - } - - rhte = get_rhte(ctxi, rhndl, lli); - if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", - __func__, rhndl); - rc = -EINVAL; - goto out; - } - - /* - * Look at the hint/sense to see if it requires us to redrive - * inquiry (i.e. the Unit attention is due to the WWN changing). - */ - if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { - /* Can't hold mutex across process_sense/read_cap16, - * since we could have an intervening EEH event. - */ - ctxi->unavail = true; - mutex_unlock(&ctxi->mutex); - rc = process_sense(sdev, verify); - if (unlikely(rc)) { - dev_err(dev, "%s: Failed to validate sense data (%d)\n", - __func__, rc); - mutex_lock(&ctxi->mutex); - ctxi->unavail = false; - goto out; - } - mutex_lock(&ctxi->mutex); - ctxi->unavail = false; - } - - switch (gli->mode) { - case MODE_PHYSICAL: - last_lba = gli->max_lba; - break; - case MODE_VIRTUAL: - /* Cast lxt_cnt to u64 for multiply to be treated as 64bit op */ - last_lba = ((u64)rhte->lxt_cnt * MC_CHUNK_SIZE * gli->blk_len); - last_lba /= CXLFLASH_BLOCK_SIZE; - last_lba--; - break; - default: - WARN(1, "Unsupported LUN mode!"); - } - - verify->last_lba = last_lba; - -out: - if (likely(ctxi)) - put_context(ctxi); - dev_dbg(dev, "%s: returning rc=%d llba=%llx\n", - __func__, rc, verify->last_lba); - return rc; -} - -/** - * decode_ioctl() - translates an encoded ioctl to an easily identifiable string - * @cmd: The ioctl command to decode. - * - * Return: A string identifying the decoded ioctl. - */ -static char *decode_ioctl(unsigned int cmd) -{ - switch (cmd) { - case DK_CXLFLASH_ATTACH: - return __stringify_1(DK_CXLFLASH_ATTACH); - case DK_CXLFLASH_USER_DIRECT: - return __stringify_1(DK_CXLFLASH_USER_DIRECT); - case DK_CXLFLASH_USER_VIRTUAL: - return __stringify_1(DK_CXLFLASH_USER_VIRTUAL); - case DK_CXLFLASH_VLUN_RESIZE: - return __stringify_1(DK_CXLFLASH_VLUN_RESIZE); - case DK_CXLFLASH_RELEASE: - return __stringify_1(DK_CXLFLASH_RELEASE); - case DK_CXLFLASH_DETACH: - return __stringify_1(DK_CXLFLASH_DETACH); - case DK_CXLFLASH_VERIFY: - return __stringify_1(DK_CXLFLASH_VERIFY); - case DK_CXLFLASH_VLUN_CLONE: - return __stringify_1(DK_CXLFLASH_VLUN_CLONE); - case DK_CXLFLASH_RECOVER_AFU: - return __stringify_1(DK_CXLFLASH_RECOVER_AFU); - case DK_CXLFLASH_MANAGE_LUN: - return __stringify_1(DK_CXLFLASH_MANAGE_LUN); - } - - return "UNKNOWN"; -} - -/** - * cxlflash_disk_direct_open() - opens a direct (physical) disk - * @sdev: SCSI device associated with LUN. - * @arg: UDirect ioctl data structure. - * - * On successful return, the user is informed of the resource handle - * to be used to identify the direct lun and the size (in blocks) of - * the direct lun in last LBA format. - * - * Return: 0 on success, -errno on failure - */ -static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct dk_cxlflash_release rel = { { 0 }, 0 }; - - struct dk_cxlflash_udirect *pphys = (struct dk_cxlflash_udirect *)arg; - - u64 ctxid = DECODE_CTXID(pphys->context_id), - rctxid = pphys->context_id; - u64 lun_size = 0; - u64 last_lba = 0; - u64 rsrc_handle = -1; - u32 port = CHAN2PORTMASK(sdev->channel); - - int rc = 0; - - struct ctx_info *ctxi = NULL; - struct sisl_rht_entry *rhte = NULL; - - dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); - - rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); - if (unlikely(rc)) { - dev_dbg(dev, "%s: Failed attach to LUN (PHYSICAL)\n", __func__); - goto out; - } - - ctxi = get_context(cfg, rctxid, lli, 0); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); - rc = -EINVAL; - goto err1; - } - - rhte = rhte_checkout(ctxi, lli); - if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Too many opens ctxid=%lld\n", - __func__, ctxid); - rc = -EMFILE; /* too many opens */ - goto err1; - } - - rsrc_handle = (rhte - ctxi->rht_start); - - rht_format1(rhte, lli->lun_id[sdev->channel], ctxi->rht_perms, port); - - last_lba = gli->max_lba; - pphys->hdr.return_flags = 0; - pphys->last_lba = last_lba; - pphys->rsrc_handle = rsrc_handle; - - rc = cxlflash_afu_sync(afu, ctxid, rsrc_handle, AFU_LW_SYNC); - if (unlikely(rc)) { - dev_dbg(dev, "%s: AFU sync failed rc=%d\n", __func__, rc); - goto err2; - } - -out: - if (likely(ctxi)) - put_context(ctxi); - dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", - __func__, rsrc_handle, rc, last_lba); - return rc; - -err2: - marshal_udir_to_rele(pphys, &rel); - _cxlflash_disk_release(sdev, ctxi, &rel); - goto out; -err1: - cxlflash_lun_detach(gli); - goto out; -} - -/** - * ioctl_common() - common IOCTL handler for driver - * @sdev: SCSI device associated with LUN. - * @cmd: IOCTL command. - * - * Handles common fencing operations that are valid for multiple ioctls. Always - * allow through ioctls that are cleanup oriented in nature, even when operating - * in a failed/terminating state. - * - * Return: 0 on success, -errno on failure - */ -static int ioctl_common(struct scsi_device *sdev, unsigned int cmd) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - int rc = 0; - - if (unlikely(!lli)) { - dev_dbg(dev, "%s: Unknown LUN\n", __func__); - rc = -EINVAL; - goto out; - } - - rc = check_state(cfg); - if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { - switch (cmd) { - case DK_CXLFLASH_VLUN_RESIZE: - case DK_CXLFLASH_RELEASE: - case DK_CXLFLASH_DETACH: - dev_dbg(dev, "%s: Command override rc=%d\n", - __func__, rc); - rc = 0; - break; - } - } -out: - return rc; -} - -/** - * cxlflash_ioctl() - IOCTL handler for driver - * @sdev: SCSI device associated with LUN. - * @cmd: IOCTL command. - * @arg: Userspace ioctl data structure. - * - * A read/write semaphore is used to implement a 'drain' of currently - * running ioctls. The read semaphore is taken at the beginning of each - * ioctl thread and released upon concluding execution. Additionally the - * semaphore should be released and then reacquired in any ioctl execution - * path which will wait for an event to occur that is outside the scope of - * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, - * a thread simply needs to acquire the write semaphore. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg) -{ - typedef int (*sioctl) (struct scsi_device *, void *); - - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; - struct dk_cxlflash_hdr *hdr; - char buf[sizeof(union cxlflash_ioctls)]; - size_t size = 0; - bool known_ioctl = false; - int idx; - int rc = 0; - struct Scsi_Host *shost = sdev->host; - sioctl do_ioctl = NULL; - - static const struct { - size_t size; - sioctl ioctl; - } ioctl_tbl[] = { /* NOTE: order matters here */ - {sizeof(struct dk_cxlflash_attach), cxlflash_disk_attach}, - {sizeof(struct dk_cxlflash_udirect), cxlflash_disk_direct_open}, - {sizeof(struct dk_cxlflash_release), cxlflash_disk_release}, - {sizeof(struct dk_cxlflash_detach), cxlflash_disk_detach}, - {sizeof(struct dk_cxlflash_verify), cxlflash_disk_verify}, - {sizeof(struct dk_cxlflash_recover_afu), cxlflash_afu_recover}, - {sizeof(struct dk_cxlflash_manage_lun), cxlflash_manage_lun}, - {sizeof(struct dk_cxlflash_uvirtual), cxlflash_disk_virtual_open}, - {sizeof(struct dk_cxlflash_resize), cxlflash_vlun_resize}, - {sizeof(struct dk_cxlflash_clone), cxlflash_disk_clone}, - }; - - /* Hold read semaphore so we can drain if needed */ - down_read(&cfg->ioctl_rwsem); - - /* Restrict command set to physical support only for internal LUN */ - if (afu->internal_lun) - switch (cmd) { - case DK_CXLFLASH_RELEASE: - case DK_CXLFLASH_USER_VIRTUAL: - case DK_CXLFLASH_VLUN_RESIZE: - case DK_CXLFLASH_VLUN_CLONE: - dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", - __func__, decode_ioctl(cmd), afu->internal_lun); - rc = -EINVAL; - goto cxlflash_ioctl_exit; - } - - switch (cmd) { - case DK_CXLFLASH_ATTACH: - case DK_CXLFLASH_USER_DIRECT: - case DK_CXLFLASH_RELEASE: - case DK_CXLFLASH_DETACH: - case DK_CXLFLASH_VERIFY: - case DK_CXLFLASH_RECOVER_AFU: - case DK_CXLFLASH_USER_VIRTUAL: - case DK_CXLFLASH_VLUN_RESIZE: - case DK_CXLFLASH_VLUN_CLONE: - dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", - __func__, decode_ioctl(cmd), cmd, shost->host_no, - sdev->channel, sdev->id, sdev->lun); - rc = ioctl_common(sdev, cmd); - if (unlikely(rc)) - goto cxlflash_ioctl_exit; - - fallthrough; - - case DK_CXLFLASH_MANAGE_LUN: - known_ioctl = true; - idx = _IOC_NR(cmd) - _IOC_NR(DK_CXLFLASH_ATTACH); - size = ioctl_tbl[idx].size; - do_ioctl = ioctl_tbl[idx].ioctl; - - if (likely(do_ioctl)) - break; - - fallthrough; - default: - rc = -EINVAL; - goto cxlflash_ioctl_exit; - } - - if (unlikely(copy_from_user(&buf, arg, size))) { - dev_err(dev, "%s: copy_from_user() fail size=%lu cmd=%u (%s) arg=%p\n", - __func__, size, cmd, decode_ioctl(cmd), arg); - rc = -EFAULT; - goto cxlflash_ioctl_exit; - } - - hdr = (struct dk_cxlflash_hdr *)&buf; - if (hdr->version != DK_CXLFLASH_VERSION_0) { - dev_dbg(dev, "%s: Version %u not supported for %s\n", - __func__, hdr->version, decode_ioctl(cmd)); - rc = -EINVAL; - goto cxlflash_ioctl_exit; - } - - if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { - dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); - rc = -EINVAL; - goto cxlflash_ioctl_exit; - } - - rc = do_ioctl(sdev, (void *)&buf); - if (likely(!rc)) - if (unlikely(copy_to_user(arg, &buf, size))) { - dev_err(dev, "%s: copy_to_user() fail size=%lu cmd=%u (%s) arg=%p\n", - __func__, size, cmd, decode_ioctl(cmd), arg); - rc = -EFAULT; - } - - /* fall through to exit */ - -cxlflash_ioctl_exit: - up_read(&cfg->ioctl_rwsem); - if (unlikely(rc && known_ioctl)) - dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " - "returned rc %d\n", __func__, - decode_ioctl(cmd), cmd, shost->host_no, - sdev->channel, sdev->id, sdev->lun, rc); - else - dev_dbg(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " - "returned rc %d\n", __func__, decode_ioctl(cmd), - cmd, shost->host_no, sdev->channel, sdev->id, - sdev->lun, rc); - return rc; -} diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h deleted file mode 100644 index fe8c975d13d7..000000000000 --- a/drivers/scsi/cxlflash/superpipe.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#ifndef _CXLFLASH_SUPERPIPE_H -#define _CXLFLASH_SUPERPIPE_H - -extern struct cxlflash_global global; - -/* - * Terminology: use afu (and not adapter) to refer to the HW. - * Adapter is the entire slot and includes PSL out of which - * only the AFU is visible to user space. - */ - -/* Chunk size parms: note sislite minimum chunk size is - * 0x10000 LBAs corresponding to a NMASK or 16. - */ -#define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ - -#define CMD_TIMEOUT 30 /* 30 secs */ -#define CMD_RETRIES 5 /* 5 retries for scsi_execute */ - -#define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ - -enum lun_mode { - MODE_NONE = 0, - MODE_VIRTUAL, - MODE_PHYSICAL -}; - -/* Global (entire driver, spans adapters) lun_info structure */ -struct glun_info { - u64 max_lba; /* from read cap(16) */ - u32 blk_len; /* from read cap(16) */ - enum lun_mode mode; /* NONE, VIRTUAL, PHYSICAL */ - int users; /* Number of users w/ references to LUN */ - - u8 wwid[16]; - - struct mutex mutex; - - struct blka blka; - struct list_head list; -}; - -/* Local (per-adapter) lun_info structure */ -struct llun_info { - u64 lun_id[MAX_FC_PORTS]; /* from REPORT_LUNS */ - u32 lun_index; /* Index in the LUN table */ - u32 host_no; /* host_no from Scsi_host */ - u32 port_sel; /* What port to use for this LUN */ - bool in_table; /* Whether a LUN table entry was created */ - - u8 wwid[16]; /* Keep a duplicate copy here? */ - - struct glun_info *parent; /* Pointer to entry in global LUN structure */ - struct scsi_device *sdev; - struct list_head list; -}; - -struct lun_access { - struct llun_info *lli; - struct scsi_device *sdev; - struct list_head list; -}; - -enum ctx_ctrl { - CTX_CTRL_CLONE = (1 << 1), - CTX_CTRL_ERR = (1 << 2), - CTX_CTRL_ERR_FALLBACK = (1 << 3), - CTX_CTRL_NOPID = (1 << 4), - CTX_CTRL_FILE = (1 << 5) -}; - -#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0ULL) << 28) | _id) -#define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) - -struct ctx_info { - struct sisl_ctrl_map __iomem *ctrl_map; /* initialized at startup */ - struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), - * alloc/free on attach/detach - */ - u32 rht_out; /* Number of checked out RHT entries */ - u32 rht_perms; /* User-defined permissions for RHT entries */ - struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ - u8 *rht_needs_ws; /* User-desired write-same function per RHTE */ - - u64 ctxid; - u64 irqs; /* Number of interrupts requested for context */ - pid_t pid; - bool initialized; - bool unavail; - bool err_recovery_active; - struct mutex mutex; /* Context protection */ - struct kref kref; - void *ctx; - struct cxlflash_cfg *cfg; - struct list_head luns; /* LUNs attached to this context */ - const struct vm_operations_struct *cxl_mmap_vmops; - struct file *file; - struct list_head list; /* Link contexts in error recovery */ -}; - -struct cxlflash_global { - struct mutex mutex; - struct list_head gluns;/* list of glun_info structs */ - struct page *err_page; /* One page of all 0xF for error notification */ -}; - -int cxlflash_vlun_resize(struct scsi_device *sdev, void *resize); -int _cxlflash_vlun_resize(struct scsi_device *sdev, struct ctx_info *ctxi, - struct dk_cxlflash_resize *resize); - -int cxlflash_disk_release(struct scsi_device *sdev, - void *release); -int _cxlflash_disk_release(struct scsi_device *sdev, struct ctx_info *ctxi, - struct dk_cxlflash_release *release); - -int cxlflash_disk_clone(struct scsi_device *sdev, void *arg); - -int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg); - -int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked); -void cxlflash_lun_detach(struct glun_info *gli); - -struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxit, void *arg, - enum ctx_ctrl ctrl); -void put_context(struct ctx_info *ctxi); - -struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, - struct llun_info *lli); - -struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, - struct llun_info *lli); -void rhte_checkin(struct ctx_info *ctxi, struct sisl_rht_entry *rhte); - -void cxlflash_ba_terminate(struct ba_lun *ba_lun); - -int cxlflash_manage_lun(struct scsi_device *sdev, void *manage); - -int check_state(struct cxlflash_cfg *cfg); - -#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c deleted file mode 100644 index 32e807703377..000000000000 --- a/drivers/scsi/cxlflash/vlun.c +++ /dev/null @@ -1,1336 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/syscalls.h> -#include <linux/unaligned.h> -#include <asm/bitsperlong.h> - -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_host.h> -#include <uapi/scsi/cxlflash_ioctl.h> - -#include "sislite.h" -#include "common.h" -#include "vlun.h" -#include "superpipe.h" - -/** - * marshal_virt_to_resize() - translate uvirtual to resize structure - * @virt: Source structure from which to translate/copy. - * @resize: Destination structure for the translate/copy. - */ -static void marshal_virt_to_resize(struct dk_cxlflash_uvirtual *virt, - struct dk_cxlflash_resize *resize) -{ - resize->hdr = virt->hdr; - resize->context_id = virt->context_id; - resize->rsrc_handle = virt->rsrc_handle; - resize->req_size = virt->lun_size; - resize->last_lba = virt->last_lba; -} - -/** - * marshal_clone_to_rele() - translate clone to release structure - * @clone: Source structure from which to translate/copy. - * @release: Destination structure for the translate/copy. - */ -static void marshal_clone_to_rele(struct dk_cxlflash_clone *clone, - struct dk_cxlflash_release *release) -{ - release->hdr = clone->hdr; - release->context_id = clone->context_id_dst; -} - -/** - * ba_init() - initializes a block allocator - * @ba_lun: Block allocator to initialize. - * - * Return: 0 on success, -errno on failure - */ -static int ba_init(struct ba_lun *ba_lun) -{ - struct ba_lun_info *bali = NULL; - int lun_size_au = 0, i = 0; - int last_word_underflow = 0; - u64 *lam; - - pr_debug("%s: Initializing LUN: lun_id=%016llx " - "ba_lun->lsize=%lx ba_lun->au_size=%lX\n", - __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); - - /* Calculate bit map size */ - lun_size_au = ba_lun->lsize / ba_lun->au_size; - if (lun_size_au == 0) { - pr_debug("%s: Requested LUN size of 0!\n", __func__); - return -EINVAL; - } - - /* Allocate lun information container */ - bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); - if (unlikely(!bali)) { - pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n", - __func__, ba_lun->lun_id); - return -ENOMEM; - } - - bali->total_aus = lun_size_au; - bali->lun_bmap_size = lun_size_au / BITS_PER_LONG; - - if (lun_size_au % BITS_PER_LONG) - bali->lun_bmap_size++; - - /* Allocate bitmap space */ - bali->lun_alloc_map = kzalloc((bali->lun_bmap_size * sizeof(u64)), - GFP_KERNEL); - if (unlikely(!bali->lun_alloc_map)) { - pr_err("%s: Failed to allocate lun allocation map: " - "lun_id=%016llx\n", __func__, ba_lun->lun_id); - kfree(bali); - return -ENOMEM; - } - - /* Initialize the bit map size and set all bits to '1' */ - bali->free_aun_cnt = lun_size_au; - - for (i = 0; i < bali->lun_bmap_size; i++) - bali->lun_alloc_map[i] = 0xFFFFFFFFFFFFFFFFULL; - - /* If the last word not fully utilized, mark extra bits as allocated */ - last_word_underflow = (bali->lun_bmap_size * BITS_PER_LONG); - last_word_underflow -= bali->free_aun_cnt; - if (last_word_underflow > 0) { - lam = &bali->lun_alloc_map[bali->lun_bmap_size - 1]; - for (i = (HIBIT - last_word_underflow + 1); - i < BITS_PER_LONG; - i++) - clear_bit(i, (ulong *)lam); - } - - /* Initialize high elevator index, low/curr already at 0 from kzalloc */ - bali->free_high_idx = bali->lun_bmap_size; - - /* Allocate clone map */ - bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), - GFP_KERNEL); - if (unlikely(!bali->aun_clone_map)) { - pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n", - __func__, ba_lun->lun_id); - kfree(bali->lun_alloc_map); - kfree(bali); - return -ENOMEM; - } - - /* Pass the allocated LUN info as a handle to the user */ - ba_lun->ba_lun_handle = bali; - - pr_debug("%s: Successfully initialized the LUN: " - "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n", - __func__, ba_lun->lun_id, bali->lun_bmap_size, - bali->free_aun_cnt); - return 0; -} - -/** - * find_free_range() - locates a free bit within the block allocator - * @low: First word in block allocator to start search. - * @high: Last word in block allocator to search. - * @bali: LUN information structure owning the block allocator to search. - * @bit_word: Passes back the word in the block allocator owning the free bit. - * - * Return: The bit position within the passed back word, -1 on failure - */ -static int find_free_range(u32 low, - u32 high, - struct ba_lun_info *bali, int *bit_word) -{ - int i; - u64 bit_pos = -1; - ulong *lam, num_bits; - - for (i = low; i < high; i++) - if (bali->lun_alloc_map[i] != 0) { - lam = (ulong *)&bali->lun_alloc_map[i]; - num_bits = (sizeof(*lam) * BITS_PER_BYTE); - bit_pos = find_first_bit(lam, num_bits); - - pr_devel("%s: Found free bit %llu in LUN " - "map entry %016llx at bitmap index = %d\n", - __func__, bit_pos, bali->lun_alloc_map[i], i); - - *bit_word = i; - bali->free_aun_cnt--; - clear_bit(bit_pos, lam); - break; - } - - return bit_pos; -} - -/** - * ba_alloc() - allocates a block from the block allocator - * @ba_lun: Block allocator from which to allocate a block. - * - * Return: The allocated block, -1 on failure - */ -static u64 ba_alloc(struct ba_lun *ba_lun) -{ - u64 bit_pos = -1; - int bit_word = 0; - struct ba_lun_info *bali = NULL; - - bali = ba_lun->ba_lun_handle; - - pr_debug("%s: Received block allocation request: " - "lun_id=%016llx free_aun_cnt=%llx\n", - __func__, ba_lun->lun_id, bali->free_aun_cnt); - - if (bali->free_aun_cnt == 0) { - pr_debug("%s: No space left on LUN: lun_id=%016llx\n", - __func__, ba_lun->lun_id); - return -1ULL; - } - - /* Search to find a free entry, curr->high then low->curr */ - bit_pos = find_free_range(bali->free_curr_idx, - bali->free_high_idx, bali, &bit_word); - if (bit_pos == -1) { - bit_pos = find_free_range(bali->free_low_idx, - bali->free_curr_idx, - bali, &bit_word); - if (bit_pos == -1) { - pr_debug("%s: Could not find an allocation unit on LUN:" - " lun_id=%016llx\n", __func__, ba_lun->lun_id); - return -1ULL; - } - } - - /* Update the free_curr_idx */ - if (bit_pos == HIBIT) - bali->free_curr_idx = bit_word + 1; - else - bali->free_curr_idx = bit_word; - - pr_debug("%s: Allocating AU number=%llx lun_id=%016llx " - "free_aun_cnt=%llx\n", __func__, - ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, - bali->free_aun_cnt); - - return (u64) ((bit_word * BITS_PER_LONG) + bit_pos); -} - -/** - * validate_alloc() - validates the specified block has been allocated - * @bali: LUN info owning the block allocator. - * @aun: Block to validate. - * - * Return: 0 on success, -1 on failure - */ -static int validate_alloc(struct ba_lun_info *bali, u64 aun) -{ - int idx = 0, bit_pos = 0; - - idx = aun / BITS_PER_LONG; - bit_pos = aun % BITS_PER_LONG; - - if (test_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx])) - return -1; - - return 0; -} - -/** - * ba_free() - frees a block from the block allocator - * @ba_lun: Block allocator from which to allocate a block. - * @to_free: Block to free. - * - * Return: 0 on success, -1 on failure - */ -static int ba_free(struct ba_lun *ba_lun, u64 to_free) -{ - int idx = 0, bit_pos = 0; - struct ba_lun_info *bali = NULL; - - bali = ba_lun->ba_lun_handle; - - if (validate_alloc(bali, to_free)) { - pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n", - __func__, to_free, ba_lun->lun_id); - return -1; - } - - pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx " - "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id, - bali->free_aun_cnt); - - if (bali->aun_clone_map[to_free] > 0) { - pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n", - __func__, to_free, ba_lun->lun_id, - bali->aun_clone_map[to_free]); - bali->aun_clone_map[to_free]--; - return 0; - } - - idx = to_free / BITS_PER_LONG; - bit_pos = to_free % BITS_PER_LONG; - - set_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx]); - bali->free_aun_cnt++; - - if (idx < bali->free_low_idx) - bali->free_low_idx = idx; - else if (idx > bali->free_high_idx) - bali->free_high_idx = idx; - - pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x " - "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx, - ba_lun->lun_id, bali->free_aun_cnt); - - return 0; -} - -/** - * ba_clone() - Clone a chunk of the block allocation table - * @ba_lun: Block allocator from which to allocate a block. - * @to_clone: Block to clone. - * - * Return: 0 on success, -1 on failure - */ -static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) -{ - struct ba_lun_info *bali = ba_lun->ba_lun_handle; - - if (validate_alloc(bali, to_clone)) { - pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n", - __func__, to_clone, ba_lun->lun_id); - return -1; - } - - pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n", - __func__, to_clone, ba_lun->lun_id); - - if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { - pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n", - __func__, to_clone, ba_lun->lun_id); - return -1; - } - - bali->aun_clone_map[to_clone]++; - - return 0; -} - -/** - * ba_space() - returns the amount of free space left in the block allocator - * @ba_lun: Block allocator. - * - * Return: Amount of free space in block allocator - */ -static u64 ba_space(struct ba_lun *ba_lun) -{ - struct ba_lun_info *bali = ba_lun->ba_lun_handle; - - return bali->free_aun_cnt; -} - -/** - * cxlflash_ba_terminate() - frees resources associated with the block allocator - * @ba_lun: Block allocator. - * - * Safe to call in a partially allocated state. - */ -void cxlflash_ba_terminate(struct ba_lun *ba_lun) -{ - struct ba_lun_info *bali = ba_lun->ba_lun_handle; - - if (bali) { - kfree(bali->aun_clone_map); - kfree(bali->lun_alloc_map); - kfree(bali); - ba_lun->ba_lun_handle = NULL; - } -} - -/** - * init_vlun() - initializes a LUN for virtual use - * @lli: LUN information structure that owns the block allocator. - * - * Return: 0 on success, -errno on failure - */ -static int init_vlun(struct llun_info *lli) -{ - int rc = 0; - struct glun_info *gli = lli->parent; - struct blka *blka = &gli->blka; - - memset(blka, 0, sizeof(*blka)); - mutex_init(&blka->mutex); - - /* LUN IDs are unique per port, save the index instead */ - blka->ba_lun.lun_id = lli->lun_index; - blka->ba_lun.lsize = gli->max_lba + 1; - blka->ba_lun.lba_size = gli->blk_len; - - blka->ba_lun.au_size = MC_CHUNK_SIZE; - blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE; - - rc = ba_init(&blka->ba_lun); - if (unlikely(rc)) - pr_debug("%s: cannot init block_alloc, rc=%d\n", __func__, rc); - - pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli); - return rc; -} - -/** - * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN - * @sdev: SCSI device associated with LUN. - * @lba: Logical block address to start write same. - * @nblks: Number of logical blocks to write same. - * - * The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur - * while in scsi_execute_cmd(), the EEH handler will attempt to recover. As - * part of the recovery, the handler drains all currently running ioctls, - * waiting until they have completed before proceeding with a reset. As this - * routine is used on the ioctl path, this can create a condition where the - * EEH handler becomes stuck, infinitely waiting for this ioctl thread. To - * avoid this behavior, temporarily unmark this thread as an ioctl thread by - * releasing the ioctl read semaphore. This will allow the EEH handler to - * proceed with a recovery while this thread is still running. Once the - * scsi_execute_cmd() returns, reacquire the ioctl read semaphore and check the - * adapter state in case it changed while inside of scsi_execute_cmd(). The - * state check will wait if the adapter is still being recovered or return a - * failure if the recovery failed. In the event that the adapter reset failed, - * simply return the failure as the ioctl would be unable to continue. - * - * Note that the above puts a requirement on this routine to only be called on - * an ioctl thread. - * - * Return: 0 on success, -errno on failure - */ -static int write_same16(struct scsi_device *sdev, - u64 lba, - u32 nblks) -{ - u8 *cmd_buf = NULL; - u8 *scsi_cmd = NULL; - int rc = 0; - int result = 0; - u64 offset = lba; - int left = nblks; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - const u32 s = ilog2(sdev->sector_size) - 9; - const u32 to = sdev->request_queue->rq_timeout; - const u32 ws_limit = - sdev->request_queue->limits.max_write_zeroes_sectors >> s; - - cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); - scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); - if (unlikely(!cmd_buf || !scsi_cmd)) { - rc = -ENOMEM; - goto out; - } - - while (left > 0) { - - scsi_cmd[0] = WRITE_SAME_16; - scsi_cmd[1] = cfg->ws_unmap ? 0x8 : 0; - put_unaligned_be64(offset, &scsi_cmd[2]); - put_unaligned_be32(ws_limit < left ? ws_limit : left, - &scsi_cmd[10]); - - /* Drop the ioctl read semaphore across lengthy call */ - up_read(&cfg->ioctl_rwsem); - result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_OUT, - cmd_buf, CMD_BUFSIZE, to, - CMD_RETRIES, NULL); - down_read(&cfg->ioctl_rwsem); - rc = check_state(cfg); - if (rc) { - dev_err(dev, "%s: Failed state result=%08x\n", - __func__, result); - rc = -ENODEV; - goto out; - } - - if (result) { - dev_err_ratelimited(dev, "%s: command failed for " - "offset=%lld result=%08x\n", - __func__, offset, result); - rc = -EIO; - goto out; - } - left -= ws_limit; - offset += ws_limit; - } - -out: - kfree(cmd_buf); - kfree(scsi_cmd); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * grow_lxt() - expands the translation table associated with the specified RHTE - * @afu: AFU associated with the host. - * @sdev: SCSI device associated with LUN. - * @ctxid: Context ID of context owning the RHTE. - * @rhndl: Resource handle associated with the RHTE. - * @rhte: Resource handle entry (RHTE). - * @new_size: Number of translation entries associated with RHTE. - * - * By design, this routine employs a 'best attempt' allocation and will - * truncate the requested size down if there is not sufficient space in - * the block allocator to satisfy the request but there does exist some - * amount of space. The user is made aware of this by returning the size - * allocated. - * - * Return: 0 on success, -errno on failure - */ -static int grow_lxt(struct afu *afu, - struct scsi_device *sdev, - ctx_hndl_t ctxid, - res_hndl_t rhndl, - struct sisl_rht_entry *rhte, - u64 *new_size) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct blka *blka = &gli->blka; - u32 av_size; - u32 ngrps, ngrps_old; - u64 aun; /* chunk# allocated by block allocator */ - u64 delta = *new_size - rhte->lxt_cnt; - u64 my_new_size; - int i, rc = 0; - - /* - * Check what is available in the block allocator before re-allocating - * LXT array. This is done up front under the mutex which must not be - * released until after allocation is complete. - */ - mutex_lock(&blka->mutex); - av_size = ba_space(&blka->ba_lun); - if (unlikely(av_size <= 0)) { - dev_dbg(dev, "%s: ba_space error av_size=%d\n", - __func__, av_size); - mutex_unlock(&blka->mutex); - rc = -ENOSPC; - goto out; - } - - if (av_size < delta) - delta = av_size; - - lxt_old = rhte->lxt_start; - ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); - ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt + delta); - - if (ngrps != ngrps_old) { - /* reallocate to fit new size */ - lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), - GFP_KERNEL); - if (unlikely(!lxt)) { - mutex_unlock(&blka->mutex); - rc = -ENOMEM; - goto out; - } - - /* copy over all old entries */ - memcpy(lxt, lxt_old, (sizeof(*lxt) * rhte->lxt_cnt)); - } else - lxt = lxt_old; - - /* nothing can fail from now on */ - my_new_size = rhte->lxt_cnt + delta; - - /* add new entries to the end */ - for (i = rhte->lxt_cnt; i < my_new_size; i++) { - /* - * Due to the earlier check of available space, ba_alloc - * cannot fail here. If it did due to internal error, - * leave a rlba_base of -1u which will likely be a - * invalid LUN (too large). - */ - aun = ba_alloc(&blka->ba_lun); - if ((aun == -1ULL) || (aun >= blka->nchunk)) - dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu " - "max=%llu\n", __func__, aun, blka->nchunk - 1); - - /* select both ports, use r/w perms from RHT */ - lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | - (lli->lun_index << LXT_LUNIDX_SHIFT) | - (RHT_PERM_RW << LXT_PERM_SHIFT | - lli->port_sel)); - } - - mutex_unlock(&blka->mutex); - - /* - * The following sequence is prescribed in the SISlite spec - * for syncing up with the AFU when adding LXT entries. - */ - dma_wmb(); /* Make LXT updates are visible */ - - rhte->lxt_start = lxt; - dma_wmb(); /* Make RHT entry's LXT table update visible */ - - rhte->lxt_cnt = my_new_size; - dma_wmb(); /* Make RHT entry's LXT table size update visible */ - - rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); - if (unlikely(rc)) - rc = -EAGAIN; - - /* free old lxt if reallocated */ - if (lxt != lxt_old) - kfree(lxt_old); - *new_size = my_new_size; -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * shrink_lxt() - reduces translation table associated with the specified RHTE - * @afu: AFU associated with the host. - * @sdev: SCSI device associated with LUN. - * @rhndl: Resource handle associated with the RHTE. - * @rhte: Resource handle entry (RHTE). - * @ctxi: Context owning resources. - * @new_size: Number of translation entries associated with RHTE. - * - * Return: 0 on success, -errno on failure - */ -static int shrink_lxt(struct afu *afu, - struct scsi_device *sdev, - res_hndl_t rhndl, - struct sisl_rht_entry *rhte, - struct ctx_info *ctxi, - u64 *new_size) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct sisl_lxt_entry *lxt, *lxt_old; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct blka *blka = &gli->blka; - ctx_hndl_t ctxid = DECODE_CTXID(ctxi->ctxid); - bool needs_ws = ctxi->rht_needs_ws[rhndl]; - bool needs_sync = !ctxi->err_recovery_active; - u32 ngrps, ngrps_old; - u64 aun; /* chunk# allocated by block allocator */ - u64 delta = rhte->lxt_cnt - *new_size; - u64 my_new_size; - int i, rc = 0; - - lxt_old = rhte->lxt_start; - ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); - ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt - delta); - - if (ngrps != ngrps_old) { - /* Reallocate to fit new size unless new size is 0 */ - if (ngrps) { - lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), - GFP_KERNEL); - if (unlikely(!lxt)) { - rc = -ENOMEM; - goto out; - } - - /* Copy over old entries that will remain */ - memcpy(lxt, lxt_old, - (sizeof(*lxt) * (rhte->lxt_cnt - delta))); - } else - lxt = NULL; - } else - lxt = lxt_old; - - /* Nothing can fail from now on */ - my_new_size = rhte->lxt_cnt - delta; - - /* - * The following sequence is prescribed in the SISlite spec - * for syncing up with the AFU when removing LXT entries. - */ - rhte->lxt_cnt = my_new_size; - dma_wmb(); /* Make RHT entry's LXT table size update visible */ - - rhte->lxt_start = lxt; - dma_wmb(); /* Make RHT entry's LXT table update visible */ - - if (needs_sync) { - rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); - if (unlikely(rc)) - rc = -EAGAIN; - } - - if (needs_ws) { - /* - * Mark the context as unavailable, so that we can release - * the mutex safely. - */ - ctxi->unavail = true; - mutex_unlock(&ctxi->mutex); - } - - /* Free LBAs allocated to freed chunks */ - mutex_lock(&blka->mutex); - for (i = delta - 1; i >= 0; i--) { - aun = lxt_old[my_new_size + i].rlba_base >> MC_CHUNK_SHIFT; - if (needs_ws) - write_same16(sdev, aun, MC_CHUNK_SIZE); - ba_free(&blka->ba_lun, aun); - } - mutex_unlock(&blka->mutex); - - if (needs_ws) { - /* Make the context visible again */ - mutex_lock(&ctxi->mutex); - ctxi->unavail = false; - } - - /* Free old lxt if reallocated */ - if (lxt != lxt_old) - kfree(lxt_old); - *new_size = my_new_size; -out: - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * _cxlflash_vlun_resize() - changes the size of a virtual LUN - * @sdev: SCSI device associated with LUN owning virtual LUN. - * @ctxi: Context owning resources. - * @resize: Resize ioctl data structure. - * - * On successful return, the user is informed of the new size (in blocks) - * of the virtual LUN in last LBA format. When the size of the virtual - * LUN is zero, the last LBA is reflected as -1. See comment in the - * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts - * on the error recovery list. - * - * Return: 0 on success, -errno on failure - */ -int _cxlflash_vlun_resize(struct scsi_device *sdev, - struct ctx_info *ctxi, - struct dk_cxlflash_resize *resize) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct afu *afu = cfg->afu; - bool put_ctx = false; - - res_hndl_t rhndl = resize->rsrc_handle; - u64 new_size; - u64 nsectors; - u64 ctxid = DECODE_CTXID(resize->context_id), - rctxid = resize->context_id; - - struct sisl_rht_entry *rhte; - - int rc = 0; - - /* - * The requested size (req_size) is always assumed to be in 4k blocks, - * so we have to convert it here from 4k to chunk size. - */ - nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; - new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); - - dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n", - __func__, ctxid, resize->rsrc_handle, resize->req_size, - new_size); - - if (unlikely(gli->mode != MODE_VIRTUAL)) { - dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n", - __func__, gli->mode); - rc = -EINVAL; - goto out; - - } - - if (!ctxi) { - ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); - if (unlikely(!ctxi)) { - dev_dbg(dev, "%s: Bad context ctxid=%llu\n", - __func__, ctxid); - rc = -EINVAL; - goto out; - } - - put_ctx = true; - } - - rhte = get_rhte(ctxi, rhndl, lli); - if (unlikely(!rhte)) { - dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n", - __func__, rhndl); - rc = -EINVAL; - goto out; - } - - if (new_size > rhte->lxt_cnt) - rc = grow_lxt(afu, sdev, ctxid, rhndl, rhte, &new_size); - else if (new_size < rhte->lxt_cnt) - rc = shrink_lxt(afu, sdev, rhndl, rhte, ctxi, &new_size); - else { - /* - * Rare case where there is already sufficient space, just - * need to perform a translation sync with the AFU. This - * scenario likely follows a previous sync failure during - * a resize operation. Accordingly, perform the heavyweight - * form of translation sync as it is unknown which type of - * resize failed previously. - */ - rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); - if (unlikely(rc)) { - rc = -EAGAIN; - goto out; - } - } - - resize->hdr.return_flags = 0; - resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len); - resize->last_lba /= CXLFLASH_BLOCK_SIZE; - resize->last_lba--; - -out: - if (put_ctx) - put_context(ctxi); - dev_dbg(dev, "%s: resized to %llu returning rc=%d\n", - __func__, resize->last_lba, rc); - return rc; -} - -int cxlflash_vlun_resize(struct scsi_device *sdev, void *resize) -{ - return _cxlflash_vlun_resize(sdev, NULL, resize); -} - -/** - * cxlflash_restore_luntable() - Restore LUN table to prior state - * @cfg: Internal structure associated with the host. - */ -void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) -{ - struct llun_info *lli, *temp; - u32 lind; - int k; - struct device *dev = &cfg->dev->dev; - __be64 __iomem *fc_port_luns; - - mutex_lock(&global.mutex); - - list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { - if (!lli->in_table) - continue; - - lind = lli->lun_index; - dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); - - for (k = 0; k < cfg->num_fc_ports; k++) - if (lli->port_sel & (1 << k)) { - fc_port_luns = get_fc_port_luns(cfg, k); - writeq_be(lli->lun_id[k], &fc_port_luns[lind]); - dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); - } - } - - mutex_unlock(&global.mutex); -} - -/** - * get_num_ports() - compute number of ports from port selection mask - * @psm: Port selection mask. - * - * Return: Population count of port selection mask - */ -static inline u8 get_num_ports(u32 psm) -{ - static const u8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, - 1, 2, 2, 3, 2, 3, 3, 4 }; - - return bits[psm & 0xf]; -} - -/** - * init_luntable() - write an entry in the LUN table - * @cfg: Internal structure associated with the host. - * @lli: Per adapter LUN information structure. - * - * On successful return, a LUN table entry is created: - * - at the top for LUNs visible on multiple ports. - * - at the bottom for LUNs visible only on one port. - * - * Return: 0 on success, -errno on failure - */ -static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) -{ - u32 chan; - u32 lind; - u32 nports; - int rc = 0; - int k; - struct device *dev = &cfg->dev->dev; - __be64 __iomem *fc_port_luns; - - mutex_lock(&global.mutex); - - if (lli->in_table) - goto out; - - nports = get_num_ports(lli->port_sel); - if (nports == 0 || nports > cfg->num_fc_ports) { - WARN(1, "Unsupported port configuration nports=%u", nports); - rc = -EIO; - goto out; - } - - if (nports > 1) { - /* - * When LUN is visible from multiple ports, we will put - * it in the top half of the LUN table. - */ - for (k = 0; k < cfg->num_fc_ports; k++) { - if (!(lli->port_sel & (1 << k))) - continue; - - if (cfg->promote_lun_index == cfg->last_lun_index[k]) { - rc = -ENOSPC; - goto out; - } - } - - lind = lli->lun_index = cfg->promote_lun_index; - dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); - - for (k = 0; k < cfg->num_fc_ports; k++) { - if (!(lli->port_sel & (1 << k))) - continue; - - fc_port_luns = get_fc_port_luns(cfg, k); - writeq_be(lli->lun_id[k], &fc_port_luns[lind]); - dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); - } - - cfg->promote_lun_index++; - } else { - /* - * When LUN is visible only from one port, we will put - * it in the bottom half of the LUN table. - */ - chan = PORTMASK2CHAN(lli->port_sel); - if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { - rc = -ENOSPC; - goto out; - } - - lind = lli->lun_index = cfg->last_lun_index[chan]; - fc_port_luns = get_fc_port_luns(cfg, chan); - writeq_be(lli->lun_id[chan], &fc_port_luns[lind]); - cfg->last_lun_index[chan]--; - dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n", - __func__, lind, chan, lli->lun_id[chan]); - } - - lli->in_table = true; -out: - mutex_unlock(&global.mutex); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_disk_virtual_open() - open a virtual disk of specified size - * @sdev: SCSI device associated with LUN owning virtual LUN. - * @arg: UVirtual ioctl data structure. - * - * On successful return, the user is informed of the resource handle - * to be used to identify the virtual LUN and the size (in blocks) of - * the virtual LUN in last LBA format. When the size of the virtual LUN - * is zero, the last LBA is reflected as -1. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) -{ - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - - struct dk_cxlflash_uvirtual *virt = (struct dk_cxlflash_uvirtual *)arg; - struct dk_cxlflash_resize resize; - - u64 ctxid = DECODE_CTXID(virt->context_id), - rctxid = virt->context_id; - u64 lun_size = virt->lun_size; - u64 last_lba = 0; - u64 rsrc_handle = -1; - - int rc = 0; - - struct ctx_info *ctxi = NULL; - struct sisl_rht_entry *rhte = NULL; - - dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); - - /* Setup the LUNs block allocator on first call */ - mutex_lock(&gli->mutex); - if (gli->mode == MODE_NONE) { - rc = init_vlun(lli); - if (rc) { - dev_err(dev, "%s: init_vlun failed rc=%d\n", - __func__, rc); - rc = -ENOMEM; - goto err0; - } - } - - rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); - if (unlikely(rc)) { - dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__); - goto err0; - } - mutex_unlock(&gli->mutex); - - rc = init_luntable(cfg, lli); - if (rc) { - dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc); - goto err1; - } - - ctxi = get_context(cfg, rctxid, lli, 0); - if (unlikely(!ctxi)) { - dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); - rc = -EINVAL; - goto err1; - } - - rhte = rhte_checkout(ctxi, lli); - if (unlikely(!rhte)) { - dev_err(dev, "%s: too many opens ctxid=%llu\n", - __func__, ctxid); - rc = -EMFILE; /* too many opens */ - goto err1; - } - - rsrc_handle = (rhte - ctxi->rht_start); - - /* Populate RHT format 0 */ - rhte->nmask = MC_RHT_NMASK; - rhte->fp = SISL_RHT_FP(0U, ctxi->rht_perms); - - /* Resize even if requested size is 0 */ - marshal_virt_to_resize(virt, &resize); - resize.rsrc_handle = rsrc_handle; - rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); - if (rc) { - dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc); - goto err2; - } - last_lba = resize.last_lba; - - if (virt->hdr.flags & DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME) - ctxi->rht_needs_ws[rsrc_handle] = true; - - virt->hdr.return_flags = 0; - virt->last_lba = last_lba; - virt->rsrc_handle = rsrc_handle; - - if (get_num_ports(lli->port_sel) > 1) - virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE; -out: - if (likely(ctxi)) - put_context(ctxi); - dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", - __func__, rsrc_handle, rc, last_lba); - return rc; - -err2: - rhte_checkin(ctxi, rhte); -err1: - cxlflash_lun_detach(gli); - goto out; -err0: - /* Special common cleanup prior to successful LUN attach */ - cxlflash_ba_terminate(&gli->blka.ba_lun); - mutex_unlock(&gli->mutex); - goto out; -} - -/** - * clone_lxt() - copies translation tables from source to destination RHTE - * @afu: AFU associated with the host. - * @blka: Block allocator associated with LUN. - * @ctxid: Context ID of context owning the RHTE. - * @rhndl: Resource handle associated with the RHTE. - * @rhte: Destination resource handle entry (RHTE). - * @rhte_src: Source resource handle entry (RHTE). - * - * Return: 0 on success, -errno on failure - */ -static int clone_lxt(struct afu *afu, - struct blka *blka, - ctx_hndl_t ctxid, - res_hndl_t rhndl, - struct sisl_rht_entry *rhte, - struct sisl_rht_entry *rhte_src) -{ - struct cxlflash_cfg *cfg = afu->parent; - struct device *dev = &cfg->dev->dev; - struct sisl_lxt_entry *lxt = NULL; - bool locked = false; - u32 ngrps; - u64 aun; /* chunk# allocated by block allocator */ - int j; - int i = 0; - int rc = 0; - - ngrps = LXT_NUM_GROUPS(rhte_src->lxt_cnt); - - if (ngrps) { - /* allocate new LXTs for clone */ - lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), - GFP_KERNEL); - if (unlikely(!lxt)) { - rc = -ENOMEM; - goto out; - } - - /* copy over */ - memcpy(lxt, rhte_src->lxt_start, - (sizeof(*lxt) * rhte_src->lxt_cnt)); - - /* clone the LBAs in block allocator via ref_cnt, note that the - * block allocator mutex must be held until it is established - * that this routine will complete without the need for a - * cleanup. - */ - mutex_lock(&blka->mutex); - locked = true; - for (i = 0; i < rhte_src->lxt_cnt; i++) { - aun = (lxt[i].rlba_base >> MC_CHUNK_SHIFT); - if (ba_clone(&blka->ba_lun, aun) == -1ULL) { - rc = -EIO; - goto err; - } - } - } - - /* - * The following sequence is prescribed in the SISlite spec - * for syncing up with the AFU when adding LXT entries. - */ - dma_wmb(); /* Make LXT updates are visible */ - - rhte->lxt_start = lxt; - dma_wmb(); /* Make RHT entry's LXT table update visible */ - - rhte->lxt_cnt = rhte_src->lxt_cnt; - dma_wmb(); /* Make RHT entry's LXT table size update visible */ - - rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); - if (unlikely(rc)) { - rc = -EAGAIN; - goto err2; - } - -out: - if (locked) - mutex_unlock(&blka->mutex); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; -err2: - /* Reset the RHTE */ - rhte->lxt_cnt = 0; - dma_wmb(); - rhte->lxt_start = NULL; - dma_wmb(); -err: - /* free the clones already made */ - for (j = 0; j < i; j++) { - aun = (lxt[j].rlba_base >> MC_CHUNK_SHIFT); - ba_free(&blka->ba_lun, aun); - } - kfree(lxt); - goto out; -} - -/** - * cxlflash_disk_clone() - clone a context by making snapshot of another - * @sdev: SCSI device associated with LUN owning virtual LUN. - * @arg: Clone ioctl data structure. - * - * This routine effectively performs cxlflash_disk_open operation for each - * in-use virtual resource in the source context. Note that the destination - * context must be in pristine state and cannot have any resource handles - * open at the time of the clone. - * - * Return: 0 on success, -errno on failure - */ -int cxlflash_disk_clone(struct scsi_device *sdev, void *arg) -{ - struct dk_cxlflash_clone *clone = arg; - struct cxlflash_cfg *cfg = shost_priv(sdev->host); - struct device *dev = &cfg->dev->dev; - struct llun_info *lli = sdev->hostdata; - struct glun_info *gli = lli->parent; - struct blka *blka = &gli->blka; - struct afu *afu = cfg->afu; - struct dk_cxlflash_release release = { { 0 }, 0 }; - - struct ctx_info *ctxi_src = NULL, - *ctxi_dst = NULL; - struct lun_access *lun_access_src, *lun_access_dst; - u32 perms; - u64 ctxid_src = DECODE_CTXID(clone->context_id_src), - ctxid_dst = DECODE_CTXID(clone->context_id_dst), - rctxid_src = clone->context_id_src, - rctxid_dst = clone->context_id_dst; - int i, j; - int rc = 0; - bool found; - LIST_HEAD(sidecar); - - dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n", - __func__, ctxid_src, ctxid_dst); - - /* Do not clone yourself */ - if (unlikely(rctxid_src == rctxid_dst)) { - rc = -EINVAL; - goto out; - } - - if (unlikely(gli->mode != MODE_VIRTUAL)) { - rc = -EINVAL; - dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n", - __func__, gli->mode); - goto out; - } - - ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); - ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); - if (unlikely(!ctxi_src || !ctxi_dst)) { - dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n", - __func__, ctxid_src, ctxid_dst); - rc = -EINVAL; - goto out; - } - - /* Verify there is no open resource handle in the destination context */ - for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) - if (ctxi_dst->rht_start[i].nmask != 0) { - rc = -EINVAL; - goto out; - } - - /* Clone LUN access list */ - list_for_each_entry(lun_access_src, &ctxi_src->luns, list) { - found = false; - list_for_each_entry(lun_access_dst, &ctxi_dst->luns, list) - if (lun_access_dst->sdev == lun_access_src->sdev) { - found = true; - break; - } - - if (!found) { - lun_access_dst = kzalloc(sizeof(*lun_access_dst), - GFP_KERNEL); - if (unlikely(!lun_access_dst)) { - dev_err(dev, "%s: lun_access allocation fail\n", - __func__); - rc = -ENOMEM; - goto out; - } - - *lun_access_dst = *lun_access_src; - list_add(&lun_access_dst->list, &sidecar); - } - } - - if (unlikely(!ctxi_src->rht_out)) { - dev_dbg(dev, "%s: Nothing to clone\n", __func__); - goto out_success; - } - - /* User specified permission on attach */ - perms = ctxi_dst->rht_perms; - - /* - * Copy over checked-out RHT (and their associated LXT) entries by - * hand, stopping after we've copied all outstanding entries and - * cleaning up if the clone fails. - * - * Note: This loop is equivalent to performing cxlflash_disk_open and - * cxlflash_vlun_resize. As such, LUN accounting needs to be taken into - * account by attaching after each successful RHT entry clone. In the - * event that a clone failure is experienced, the LUN detach is handled - * via the cleanup performed by _cxlflash_disk_release. - */ - for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { - if (ctxi_src->rht_out == ctxi_dst->rht_out) - break; - if (ctxi_src->rht_start[i].nmask == 0) - continue; - - /* Consume a destination RHT entry */ - ctxi_dst->rht_out++; - ctxi_dst->rht_start[i].nmask = ctxi_src->rht_start[i].nmask; - ctxi_dst->rht_start[i].fp = - SISL_RHT_FP_CLONE(ctxi_src->rht_start[i].fp, perms); - ctxi_dst->rht_lun[i] = ctxi_src->rht_lun[i]; - - rc = clone_lxt(afu, blka, ctxid_dst, i, - &ctxi_dst->rht_start[i], - &ctxi_src->rht_start[i]); - if (rc) { - marshal_clone_to_rele(clone, &release); - for (j = 0; j < i; j++) { - release.rsrc_handle = j; - _cxlflash_disk_release(sdev, ctxi_dst, - &release); - } - - /* Put back the one we failed on */ - rhte_checkin(ctxi_dst, &ctxi_dst->rht_start[i]); - goto err; - } - - cxlflash_lun_attach(gli, gli->mode, false); - } - -out_success: - list_splice(&sidecar, &ctxi_dst->luns); - - /* fall through */ -out: - if (ctxi_src) - put_context(ctxi_src); - if (ctxi_dst) - put_context(ctxi_dst); - dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); - return rc; - -err: - list_for_each_entry_safe(lun_access_src, lun_access_dst, &sidecar, list) - kfree(lun_access_src); - goto out; -} diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h deleted file mode 100644 index 68e3ea52fe80..000000000000 --- a/drivers/scsi/cxlflash/vlun.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CXL Flash Device Driver - * - * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation - * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation - * - * Copyright (C) 2015 IBM Corporation - */ - -#ifndef _CXLFLASH_VLUN_H -#define _CXLFLASH_VLUN_H - -/* RHT - Resource Handle Table */ -#define MC_RHT_NMASK 16 /* in bits */ -#define MC_CHUNK_SHIFT MC_RHT_NMASK /* shift to go from LBA to chunk# */ - -#define HIBIT (BITS_PER_LONG - 1) - -#define MAX_AUN_CLONE_CNT 0xFF - -/* - * LXT - LBA Translation Table - * - * +-------+-------+-------+-------+-------+-------+-------+---+---+ - * | RLBA_BASE |LUN_IDX| P |SEL| - * +-------+-------+-------+-------+-------+-------+-------+---+---+ - * - * The LXT Entry contains the physical LBA where the chunk starts (RLBA_BASE). - * AFU ORes the low order bits from the virtual LBA (offset into the chunk) - * with RLBA_BASE. The result is the physical LBA to be sent to storage. - * The LXT Entry also contains an index to a LUN TBL and a bitmask of which - * outgoing (FC) * ports can be selected. The port select bit-mask is ANDed - * with a global port select bit-mask maintained by the driver. - * In addition, it has permission bits that are ANDed with the - * RHT permissions to arrive at the final permissions for the chunk. - * - * LXT tables are allocated dynamically in groups. This is done to avoid - * a malloc/free overhead each time the LXT has to grow or shrink. - * - * Based on the current lxt_cnt (used), it is always possible to know - * how many are allocated (used+free). The number of allocated entries is - * not stored anywhere. - * - * The LXT table is re-allocated whenever it needs to cross into another group. - */ -#define LXT_GROUP_SIZE 8 -#define LXT_NUM_GROUPS(lxt_cnt) (((lxt_cnt) + 7)/8) /* alloc'ed groups */ -#define LXT_LUNIDX_SHIFT 8 /* LXT entry, shift for LUN index */ -#define LXT_PERM_SHIFT 4 /* LXT entry, shift for permission bits */ - -struct ba_lun_info { - u64 *lun_alloc_map; - u32 lun_bmap_size; - u32 total_aus; - u64 free_aun_cnt; - - /* indices to be used for elevator lookup of free map */ - u32 free_low_idx; - u32 free_curr_idx; - u32 free_high_idx; - - u8 *aun_clone_map; -}; - -struct ba_lun { - u64 lun_id; - u64 wwpn; - size_t lsize; /* LUN size in number of LBAs */ - size_t lba_size; /* LBA size in number of bytes */ - size_t au_size; /* Allocation Unit size in number of LBAs */ - struct ba_lun_info *ba_lun_handle; -}; - -/* Block Allocator */ -struct blka { - struct ba_lun ba_lun; - u64 nchunk; /* number of chunks */ - struct mutex mutex; -}; - -#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index e71de2419758..6183ce05d8cf 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -83,65 +83,6 @@ /*#define DC395x_NO_SYNC*/ /*#define DC395x_NO_WIDE*/ -/*--------------------------------------------------------------------------- - Debugging - ---------------------------------------------------------------------------*/ -/* - * Types of debugging that can be enabled and disabled - */ -#define DBG_KG 0x0001 -#define DBG_0 0x0002 -#define DBG_1 0x0004 -#define DBG_SG 0x0020 -#define DBG_FIFO 0x0040 -#define DBG_PIO 0x0080 - - -/* - * Set set of things to output debugging for. - * Undefine to remove all debugging - */ -/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/ -/*#define DEBUG_MASK DBG_0*/ - - -/* - * Output a kernel mesage at the specified level and append the - * driver name and a ": " to the start of the message - */ -#define dprintkl(level, format, arg...) \ - printk(level DC395X_NAME ": " format , ## arg) - - -#ifdef DEBUG_MASK -/* - * print a debug message - this is formated with KERN_DEBUG, then the - * driver name followed by a ": " and then the message is output. - * This also checks that the specified debug level is enabled before - * outputing the message - */ -#define dprintkdbg(type, format, arg...) \ - do { \ - if ((type) & (DEBUG_MASK)) \ - dprintkl(KERN_DEBUG , format , ## arg); \ - } while (0) - -/* - * Check if the specified type of debugging is enabled - */ -#define debug_enabled(type) ((DEBUG_MASK) & (type)) - -#else -/* - * No debugging. Do nothing - */ -#define dprintkdbg(type, format, arg...) \ - do {} while (0) -#define debug_enabled(type) (0) - -#endif - - #ifndef PCI_VENDOR_ID_TEKRAM #define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ #endif @@ -432,7 +373,6 @@ static void *dc395x_scsi_phase1[] = { /* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 }; -static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; /*--------------------------------------------------------------------------- @@ -564,7 +504,6 @@ static void set_safe_settings(void) { int i; - dprintkl(KERN_INFO, "Using safe settings.\n"); for (i = 0; i < CFG_NUM; i++) { cfg_data[i].value = cfg_data[i].safe; @@ -581,15 +520,6 @@ static void fix_settings(void) { int i; - dprintkdbg(DBG_1, - "setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x " - "AdapterMode=%08x Tags=%08x ResetDelay=%08x\n", - cfg_data[CFG_ADAPTER_ID].value, - cfg_data[CFG_MAX_SPEED].value, - cfg_data[CFG_DEV_MODE].value, - cfg_data[CFG_ADAPTER_MODE].value, - cfg_data[CFG_TAGS].value, - cfg_data[CFG_RESET_DELAY].value); for (i = 0; i < CFG_NUM; i++) { if (cfg_data[i].value < cfg_data[i].min @@ -765,7 +695,7 @@ static void waiting_process_next(struct AdapterCtlBlk *acb) return; if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); + timer_delete(&acb->waiting_timer); if (list_empty(dcb_list_head)) return; @@ -821,9 +751,7 @@ static void waiting_process_next(struct AdapterCtlBlk *acb) static void waiting_timeout(struct timer_list *t) { unsigned long flags; - struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer); - dprintkdbg(DBG_1, - "waiting_timeout: Queue woken up by timer. acb=%p\n", acb); + struct AdapterCtlBlk *acb = timer_container_of(acb, t, waiting_timer); DC395x_LOCK_IO(acb->scsi_host, flags); waiting_process_next(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); @@ -864,8 +792,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, { int nseg; enum dma_data_direction dir = cmd->sc_data_direction; - dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n", - cmd, dcb->target_id, dcb->target_lun); srb->dcb = dcb; srb->cmd = cmd; @@ -887,12 +813,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, nseg = scsi_dma_map(cmd); BUG_ON(nseg < 0); - if (dir == DMA_NONE || !nseg) { - dprintkdbg(DBG_0, - "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", - cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd), - srb->segment_x[0].address); - } else { + if (!(dir == DMA_NONE || !nseg)) { int i; u32 reqlen = scsi_bufflen(cmd); struct scatterlist *sg; @@ -900,11 +821,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, srb->sg_count = nseg; - dprintkdbg(DBG_0, - "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", - reqlen, scsi_sglist(cmd), scsi_sg_count(cmd), - srb->sg_count); - scsi_for_each_sg(cmd, sg, srb->sg_count, i) { u32 busaddr = (u32)sg_dma_address(sg); u32 seglen = (u32)sg->length; @@ -933,8 +849,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev, srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE); - dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", - srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); } srb->request_length = srb->total_xfer_length; @@ -959,15 +873,13 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, * and is expected to be held on return. * */ -static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status dc395x_queue_command_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n", - cmd, cmd->device->id, (u8)cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ set_host_byte(cmd, DID_BAD_TARGET); @@ -975,37 +887,26 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) /* ignore invalid targets */ if (cmd->device->id >= acb->scsi_host->max_id || cmd->device->lun >= acb->scsi_host->max_lun || - cmd->device->lun >31) { + cmd->device->lun > 31) goto complete; - } /* does the specified lun on the specified device exist */ - if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) { - dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n", - cmd->device->id, (u8)cmd->device->lun); + if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) goto complete; - } /* do we have a DCB for the device */ dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); - if (!dcb) { - /* should never happen */ - dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>", - cmd->device->id, (u8)cmd->device->lun); + if (!dcb) goto complete; - } set_host_byte(cmd, DID_OK); set_status_byte(cmd, SAM_STAT_GOOD); srb = list_first_entry_or_null(&acb->srb_free_list, - struct ScsiReqBlk, list); + struct ScsiReqBlk, list); + if (!srb) { - /* - * Return 1 since we are unable to queue this command at this - * point in time. - */ - dprintkdbg(DBG_0, "queue_command: No free srb's\n"); + /* should never happen */ return 1; } list_del(&srb->list); @@ -1020,7 +921,6 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd); return 0; complete: @@ -1036,82 +936,8 @@ complete: static DEF_SCSI_QCMD(dc395x_queue_command) -static void dump_register_info(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - u16 pstat; - struct pci_dev *dev = acb->dev; - pci_read_config_word(dev, PCI_STATUS, &pstat); - if (!dcb) - dcb = acb->active_dcb; - if (!srb && dcb) - srb = dcb->active_srb; - if (srb) { - if (!srb->cmd) - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", - srb, srb->cmd); - else - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p " - "cmnd=0x%02x <%02i-%i>\n", - srb, srb->cmd, - srb->cmd->cmnd[0], srb->cmd->device->id, - (u8)srb->cmd->device->lun); - printk(" sglist=%p cnt=%i idx=%i len=%zu\n", - srb->segment_x, srb->sg_count, srb->sg_index, - srb->total_xfer_length); - printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", - srb->state, srb->status, srb->scsi_phase, - (acb->active_dcb) ? "" : "not"); - } - dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x " - "signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x " - "rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x " - "config2=0x%02x cmd=0x%02x selto=0x%02x}\n", - DC395x_read16(acb, TRM_S1040_SCSI_STATUS), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS), - DC395x_read8(acb, TRM_S1040_SCSI_SYNC), - DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), - DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), - DC395x_read8(acb, TRM_S1040_SCSI_INTEN), - DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), - DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), - DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), - DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); - dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x " - "irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x " - "ctctr=0x%08x addr=0x%08x:0x%08x}\n", - DC395x_read16(acb, TRM_S1040_DMA_COMMAND), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - DC395x_read8(acb, TRM_S1040_DMA_INTEN), - DC395x_read16(acb, TRM_S1040_DMA_CONFIG), - DC395x_read32(acb, TRM_S1040_DMA_XCNT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), - DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); - dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} " - "pci{status=0x%04x}\n", - DC395x_read8(acb, TRM_S1040_GEN_CONTROL), - DC395x_read8(acb, TRM_S1040_GEN_STATUS), - DC395x_read8(acb, TRM_S1040_GEN_TIMER), - pstat); -} - - static inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt) { -#if debug_enabled(DBG_FIFO) - u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); - u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - if (!(fifocnt & 0x40)) - dprintkdbg(DBG_FIFO, - "clear_fifo: (%i bytes) on phase %02x in %s\n", - fifocnt & 0x3f, lines, txt); -#endif DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } @@ -1120,7 +946,6 @@ static void reset_dev_param(struct AdapterCtlBlk *acb) { struct DeviceCtlBlk *dcb; struct NvRamType *eeprom = &acb->eeprom; - dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb); list_for_each_entry(dcb, &acb->dcb_list, list) { u8 period_index; @@ -1148,12 +973,9 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkl(KERN_INFO, - "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n", - cmd, cmd->device->id, (u8)cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); + timer_delete(&acb->waiting_timer); /* * disable interrupt @@ -1216,14 +1038,10 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) (struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; - dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n", - cmd, cmd->device->id, (u8)cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); - if (!dcb) { - dprintkl(KERN_DEBUG, "eh_abort: No such device\n"); + if (!dcb) return FAILED; - } srb = find_cmd(cmd, &dcb->srb_waiting_list); if (srb) { @@ -1232,16 +1050,12 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) pci_unmap_srb(acb, srb); free_tag(dcb, srb); list_add_tail(&srb->list, &acb->srb_free_list); - dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); set_host_byte(cmd, DID_ABORT); return SUCCESS; } srb = find_cmd(cmd, &dcb->srb_going_list); if (srb) { - dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n"); /* XXX: Should abort the command here */ - } else { - dprintkl(KERN_DEBUG, "eh_abort: Command not found\n"); } return FAILED; } @@ -1253,10 +1067,6 @@ static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, { u8 *ptr = srb->msgout_buf + srb->msg_count; if (srb->msg_count > 1) { - dprintkl(KERN_INFO, - "build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); return; } if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) { @@ -1278,13 +1088,9 @@ static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & (acb->config & HCC_WIDE_CARD)) ? 1 : 0; u8 *ptr = srb->msgout_buf + srb->msg_count; - if (srb->msg_count > 1) { - dprintkl(KERN_INFO, - "build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); + if (srb->msg_count > 1) return; - } + srb->msg_count += spi_populate_width_msg(ptr, wide); srb->state |= SRB_DO_WIDE_NEGO; } @@ -1316,11 +1122,9 @@ void selection_timeout_missed(unsigned long ptr) unsigned long flags; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; struct ScsiReqBlk *srb; - dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); - if (!acb->active_dcb || !acb->active_dcb->active_srb) { - dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n"); + if (!acb->active_dcb || !acb->active_dcb->active_srb) return; - } + DC395x_LOCK_IO(acb->scsi_host, flags); srb = acb->active_dcb->active_srb; disconnect(acb); @@ -1335,8 +1139,6 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, u16 __maybe_unused s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; - dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", - dcb->target_id, dcb->target_lun, srb); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ @@ -1345,8 +1147,6 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n", - s_stat, s_stat2); /* * Try anyway? * @@ -1361,24 +1161,16 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, return 1; } #endif - if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a" - "command while another command (0x%p) is active.", - srb->cmd, - acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd : NULL); + if (acb->active_dcb) return 1; - } - if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd); + + if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) return 1; - } + /* Allow starting of SCSI commands half a second before we allow the mid-level * to queue them again after a reset */ - if (time_before(jiffies, acb->last_reset - HZ / 2)) { - dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); + if (time_before(jiffies, acb->last_reset - HZ / 2)) return 1; - } /* Flush FIFO */ clear_fifo(acb, "start_scsi"); @@ -1442,10 +1234,6 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, tag_number++; } if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, "start_scsi: (0x%p) " - "Out of tags target=<%02i-%i>)\n", - srb->cmd, srb->cmd->device->id, - (u8)srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); @@ -1462,9 +1250,6 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, #endif /*polling:*/ /* Send CDB ..command block ......... */ - dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun, - srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); @@ -1486,8 +1271,6 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n", - srb->cmd, dcb->target_id, dcb->target_lun); srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -1551,17 +1334,9 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, /* This acknowledges the IRQ */ scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); - if ((scsi_status & 0x2007) == 0x2002) - dprintkl(KERN_DEBUG, - "COP after COP completed? %04x\n", scsi_status); - if (debug_enabled(DBG_KG)) { - if (scsi_intstatus & INT_SELTIMEOUT) - dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n"); - } - /*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */ if (timer_pending(&acb->selto_timer)) - del_timer(&acb->selto_timer); + timer_delete(&acb->selto_timer); if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) { disconnect(acb); /* bus free interrupt */ @@ -1571,27 +1346,21 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, reselect(acb); goto out_unlock; } - if (scsi_intstatus & INT_SELECT) { - dprintkl(KERN_INFO, "Host does not support target mode!\n"); + if (scsi_intstatus & INT_SELECT) goto out_unlock; - } + if (scsi_intstatus & INT_SCSIRESET) { scsi_reset_detect(acb); goto out_unlock; } if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { dcb = acb->active_dcb; - if (!dcb) { - dprintkl(KERN_DEBUG, - "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", - scsi_status, scsi_intstatus); + if (!dcb) goto out_unlock; - } + srb = dcb->active_srb; - if (dcb->flag & ABORT_DEV_) { - dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); + if (dcb->flag & ABORT_DEV_) enable_msgout_abort(acb, srb); - } /* software sequential machine */ phase = (u16)srb->scsi_phase; @@ -1659,9 +1428,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) } else if (dma_status & 0x20) { /* Error from the DMA engine */ - dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status); #if 0 - dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); if (acb->active_dcb) { acb->active_dcb-> flag |= ABORT_DEV_; if (acb->active_dcb->active_srb) @@ -1669,7 +1436,6 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) } DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); #else - dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n"); acb = NULL; #endif handled = IRQ_HANDLED; @@ -1682,7 +1448,6 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd); if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ @@ -1696,18 +1461,12 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 i; u8 *ptr; - dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgout_phase1"); - if (!(srb->state & SRB_MSGOUT)) { + if (!(srb->state & SRB_MSGOUT)) srb->state |= SRB_MSGOUT; - dprintkl(KERN_DEBUG, - "msgout_phase1: (0x%p) Phase unexpected\n", - srb->cmd); /* So what ? */ - } + if (!srb->msg_count) { - dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n", - srb->cmd); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ @@ -1728,7 +1487,6 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -1739,7 +1497,6 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; - dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); @@ -1768,26 +1525,6 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, /* - * Verify that the remaining space in the hw sg lists is the same as - * the count of remaining bytes in srb->total_xfer_length - */ -static void sg_verify_length(struct ScsiReqBlk *srb) -{ - if (debug_enabled(DBG_SG)) { - unsigned len = 0; - unsigned idx = srb->sg_index; - struct SGentry *psge = srb->segment_x + idx; - for (; idx < srb->sg_count; psge++, idx++) - len += psge->length; - if (len != srb->total_xfer_length) - dprintkdbg(DBG_SG, - "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", - srb->total_xfer_length, len); - } -} - - -/* * Compute the next Scatter Gather list index and adjust its length * and address if necessary */ @@ -1797,15 +1534,11 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) u32 xferred = srb->total_xfer_length - left; /* bytes transferred */ struct SGentry *psge = srb->segment_x + srb->sg_index; - dprintkdbg(DBG_0, - "sg_update_list: Transferred %i of %i bytes, %i remain\n", - xferred, srb->total_xfer_length, left); if (xferred == 0) { /* nothing to update since we did not transfer any data */ return; } - sg_verify_length(srb); srb->total_xfer_length = left; /* update remaining count */ for (idx = srb->sg_index; idx < srb->sg_count; idx++) { if (xferred >= psge->length) { @@ -1826,7 +1559,6 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) } psge++; } - sg_verify_length(srb); } @@ -1882,8 +1614,6 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb = srb->dcb; u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; - dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -1897,14 +1627,6 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * KG: Stop DMA engine pushing more data into the SCSI FIFO * If we need more data, the DMA SG list will be freshly set up, anyway */ - dprintkdbg(DBG_PIO, "data_out_phase0: " - "DMA{fifocnt=0x%02x fifostat=0x%02x} " - "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, - srb->total_xfer_length); DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); if (!(srb->state & SRB_XFERPAD)) { @@ -1928,16 +1650,6 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, if (dcb->sync_period & WIDE_SYNC) d_left_counter <<= 1; - dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n" - "SCSI{fifocnt=0x%02x cnt=0x%08x} " - "DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - (dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); } /* * calculate all the residue data that not yet tranfered @@ -1958,9 +1670,6 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC && scsi_bufflen(srb->cmd) % 2) { d_left_counter = 0; - dprintkl(KERN_INFO, - "data_out_phase0: Discard 1 byte (0x%02x)\n", - scsi_status); } /* * KG: Oops again. Same thinko as above: The SCSI might have been @@ -1991,8 +1700,6 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, || ((oldxferred & ~PAGE_MASK) == (PAGE_SIZE - diff)) ) { - dprintkl(KERN_INFO, "data_out_phase0: " - "Work around chip bug (%i)?\n", diff); d_left_counter = srb->total_xfer_length - diff; sg_update_list(srb, d_left_counter); @@ -2003,17 +1710,14 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, } } } - if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { + if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) cleanup_after_transfer(acb, srb); - } } static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); clear_fifo(acb, "data_out_phase1"); /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); @@ -2024,8 +1728,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 scsi_status = *pscsi_status; - dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2045,8 +1747,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, unsigned int sc, fc; if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, "data_in_phase0: (0x%p) " - "Parity Error\n", srb->cmd); srb->status |= PARITY_ERROR; } /* @@ -2058,26 +1758,14 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) { #if 0 int ctr = 6000000; - dprintkl(KERN_DEBUG, - "DIP0: Wait for DMA FIFO to flush ...\n"); /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ while (! (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80) && --ctr); - if (ctr < 6000000 - 1) - dprintkl(KERN_DEBUG - "DIP0: Had to wait for DMA ...\n"); - if (!ctr) - dprintkl(KERN_ERR, - "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ #endif - dprintkdbg(DBG_KG, "data_in_phase0: " - "DMA{fifocnt=0x%02x fifostat=0x%02x}\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); } /* Now: Check remainig data: The SCSI counters should tell us ... */ sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); @@ -2085,17 +1773,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, d_left_counter = sc + ((fc & 0x1f) << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 0)); - dprintkdbg(DBG_KG, "data_in_phase0: " - "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " - "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " - "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", - fc, - (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - sc, - fc, - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - srb->total_xfer_length, d_left_counter); #if DC395x_LASTPIO /* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */ if (d_left_counter @@ -2104,12 +1781,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, /*u32 addr = (srb->segment_x[srb->sg_index].address); */ /*sg_update_list (srb, d_left_counter); */ - dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) " - "for remaining %i bytes:", - fc & 0x1f, - (srb->dcb->sync_period & WIDE_SYNC) ? - "words" : "bytes", - srb->total_xfer_length); if (srb->dcb->sync_period & WIDE_SYNC) DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); @@ -2133,9 +1804,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); *virt++ = byte; - if (debug_enabled(DBG_PIO)) - printk(" %02x", byte); - d_left_counter--; sg_subtract_one(srb); @@ -2158,8 +1826,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, *virt++ = byte; srb->total_xfer_length--; - if (debug_enabled(DBG_PIO)) - printk(" %02x", byte); } DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); @@ -2168,10 +1834,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, scsi_kunmap_atomic_sg(base); local_irq_restore(flags); } - /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ /*srb->total_xfer_length = 0; */ - if (debug_enabled(DBG_PIO)) - printk("\n"); } #endif /* DC395x_LASTPIO */ @@ -2207,9 +1870,6 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, TempDMAstatus = DC395x_read8(acb, TRM_S1040_DMA_STATUS); } while (!(TempDMAstatus & DMAXFERCOMP) && --ctr); - if (!ctr) - dprintkl(KERN_ERR, - "Deadlock in DataInPhase0 waiting for DMA!!\n"); srb->total_xfer_length = 0; #endif srb->total_xfer_length = d_left_counter; @@ -2226,17 +1886,14 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, } } /* KG: The target may decide to disconnect: Empty FIFO before! */ - if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { + if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) cleanup_after_transfer(acb, srb); - } } static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); } @@ -2246,13 +1903,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, { struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; - dprintkdbg(DBG_0, - "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun, - ((io_dir & DMACMD_DIR) ? 'r' : 'w'), - srb->total_xfer_length, srb->sg_index, srb->sg_count); - if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n"); + if (srb->sg_index >= srb->sg_count) { /* can't happen? out of bounds error */ return; @@ -2265,9 +1916,6 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, * Maybe, even ABORTXFER would be appropriate */ if (dma_status & XFERPENDING) { - dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! " - "Expect trouble!\n"); - dump_register_info(acb, dcb, srb); DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); } /* clear_fifo(acb, "IO"); */ @@ -2346,9 +1994,6 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, left_io -= len; while (len--) { - if (debug_enabled(DBG_PIO)) - printk(" %02x", *virt); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++); sg_subtract_one(srb); @@ -2360,14 +2005,10 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, if (srb->dcb->sync_period & WIDE_SYNC) { if (ln % 2) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - if (debug_enabled(DBG_PIO)) - printk(" |00"); } DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); } /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ - if (debug_enabled(DBG_PIO)) - printk("\n"); DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } @@ -2419,8 +2060,6 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; @@ -2433,8 +2072,6 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); @@ -2464,9 +2101,6 @@ static inline void msgin_reject(struct AdapterCtlBlk *acb, DC395x_ENABLE_MSGOUT; srb->state &= ~SRB_MSGIN; srb->state |= SRB_MSGOUT; - dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n", - srb->msgin_buf[0], - srb->dcb->target_id, srb->dcb->target_lun); } @@ -2475,13 +2109,6 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, { struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; - dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n", - srb->cmd, tag, srb); - - if (!(dcb->tag_mask & (1 << tag))) - dprintkl(KERN_DEBUG, - "msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n", - dcb->tag_mask, tag); if (list_empty(&dcb->srb_going_list)) goto mingx0; @@ -2494,8 +2121,6 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, if (!srb) goto mingx0; - dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n", - srb->cmd, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -2518,7 +2143,6 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, srb->msgout_buf[0] = ABORT_TASK; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; - dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag); return srb; } @@ -2537,8 +2161,6 @@ static inline void reprogram_regs(struct AdapterCtlBlk *acb, static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n", - dcb->target_id, dcb->target_lun); dcb->sync_mode &= ~(SYNC_NEGO_ENABLE); dcb->sync_mode |= SYNC_NEGO_DONE; @@ -2551,7 +2173,6 @@ static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n"); } } @@ -2562,12 +2183,6 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; int fact; - dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins " - "(%02i.%01i MHz) Offset %i\n", - dcb->target_id, srb->msgin_buf[3] << 2, - (250 / srb->msgin_buf[3]), - ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], - srb->msgin_buf[4]); if (srb->msgin_buf[4] > 15) srb->msgin_buf[4] = 15; @@ -2584,10 +2199,7 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) || dcb->min_nego_period > clock_period[bval])) bval++; - if (srb->msgin_buf[3] < clock_period[bval]) - dprintkl(KERN_INFO, - "msgin_set_sync: Increase sync nego period to %ins\n", - clock_period[bval] << 2); + srb->msgin_buf[3] = clock_period[bval]; dcb->sync_period &= 0xf0; dcb->sync_period |= ALT_SYNC | bval; @@ -2598,18 +2210,8 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) else fact = 250; - dprintkl(KERN_INFO, - "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", - dcb->target_id, (fact == 500) ? "Wide16" : "", - dcb->min_nego_period << 2, dcb->sync_offset, - (fact / dcb->min_nego_period), - ((fact % dcb->min_nego_period) * 10 + - dcb->min_nego_period / 2) / dcb->min_nego_period); - if (!(srb->state & SRB_DO_SYNC_NEGO)) { /* Reply with corrected SDTR Message */ - dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n", - srb->msgin_buf[3] << 2, srb->msgin_buf[4]); memcpy(srb->msgout_buf, srb->msgin_buf, 5); srb->msg_count = 5; @@ -2620,7 +2222,6 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n"); } } srb->state &= ~SRB_DO_SYNC_NEGO; @@ -2634,7 +2235,6 @@ static inline void msgin_set_nowide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id); dcb->sync_period &= ~WIDE_SYNC; dcb->sync_mode &= ~(WIDE_NEGO_ENABLE); @@ -2645,7 +2245,6 @@ static inline void msgin_set_nowide(struct AdapterCtlBlk *acb, && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n"); } } @@ -2654,15 +2253,11 @@ static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) struct DeviceCtlBlk *dcb = srb->dcb; u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO && acb->config & HCC_WIDE_CARD) ? 1 : 0; - dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id); if (srb->msgin_buf[3] > wide) srb->msgin_buf[3] = wide; /* Completed */ if (!(srb->state & SRB_DO_WIDE_NEGO)) { - dprintkl(KERN_DEBUG, - "msgin_set_wide: Wide nego initiated <%02i>\n", - dcb->target_id); memcpy(srb->msgout_buf, srb->msgin_buf, 4); srb->msg_count = 4; srb->state |= SRB_DO_WIDE_NEGO; @@ -2676,15 +2271,11 @@ static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) dcb->sync_period &= ~WIDE_SYNC; srb->state &= ~SRB_DO_WIDE_NEGO; /*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ - dprintkdbg(DBG_1, - "msgin_set_wide: Wide (%i bit) negotiated <%02i>\n", - (8 << srb->msgin_buf[3]), dcb->target_id); reprogram_regs(acb, dcb); if ((dcb->sync_mode & SYNC_NEGO_ENABLE) && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n"); } } @@ -2705,7 +2296,6 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { struct DeviceCtlBlk *dcb = acb->active_dcb; - dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { @@ -2759,7 +2349,6 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, case IGNORE_WIDE_RESIDUE: /* Discard wide residual */ - dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n"); break; case COMMAND_COMPLETE: @@ -2771,20 +2360,12 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * SAVE POINTER may be ignored as we have the struct * ScsiReqBlk* associated with the scsi command. */ - dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " - "SAVE POINTER rem=%i Ignore\n", - srb->cmd, srb->total_xfer_length); break; case RESTORE_POINTERS: - dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n"); break; case ABORT: - dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " - "<%02i-%i> ABORT msg\n", - srb->cmd, dcb->target_id, - dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); break; @@ -2792,7 +2373,6 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, default: /* reject unknown messages */ if (srb->msgin_buf[0] & IDENTIFY_BASE) { - dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n"); srb->msg_count = 1; srb->msgout_buf[0] = dcb->identify_msg; DC395x_ENABLE_MSGOUT; @@ -2815,7 +2395,6 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { @@ -2869,7 +2448,6 @@ static void disconnect(struct AdapterCtlBlk *acb) struct ScsiReqBlk *srb; if (!dcb) { - dprintkl(KERN_ERR, "disconnect: No such device\n"); udelay(500); /* Suspend queue for a while */ acb->last_reset = @@ -2881,21 +2459,16 @@ static void disconnect(struct AdapterCtlBlk *acb) } srb = dcb->active_srb; acb->active_dcb = NULL; - dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ clear_fifo(acb, "disconnect"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); if (srb->state & SRB_UNEXPECT_RESEL) { - dprintkl(KERN_ERR, - "disconnect: Unexpected reselection <%02i-%i>\n", - dcb->target_id, dcb->target_lun); srb->state = 0; waiting_process_next(acb); } else if (srb->state & SRB_ABORT_SENT) { dcb->flag &= ~ABORT_DEV_; acb->last_reset = jiffies + HZ / 2 + 1; - dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); doing_srb_done(acb, DID_ABORT, srb->cmd, 1); waiting_process_next(acb); } else { @@ -2910,16 +2483,10 @@ static void disconnect(struct AdapterCtlBlk *acb) if (srb->state != SRB_START_ && srb->state != SRB_MSGOUT) { srb->state = SRB_READY; - dprintkl(KERN_DEBUG, - "disconnect: (0x%p) Unexpected\n", - srb->cmd); srb->target_status = SCSI_STAT_SEL_TIMEOUT; goto disc1; } else { /* Normal selection timeout */ - dprintkdbg(DBG_KG, "disconnect: (0x%p) " - "<%02i-%i> SelTO\n", srb->cmd, - dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { srb->target_status = @@ -2928,9 +2495,6 @@ static void disconnect(struct AdapterCtlBlk *acb) } free_tag(dcb, srb); list_move(&srb->list, &dcb->srb_waiting_list); - dprintkdbg(DBG_KG, - "disconnect: (0x%p) Retry\n", - srb->cmd); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -2939,9 +2503,6 @@ static void disconnect(struct AdapterCtlBlk *acb) * SRB_DISCONNECT (This is what we expect!) */ if (bval & 0x40) { - dprintkdbg(DBG_0, "disconnect: SCSI bus stat " - " 0x%02x: ACK set! Other controllers?\n", - bval); /* It could come from another initiator, therefore don't do much ! */ } else waiting_process_next(acb); @@ -2965,7 +2526,6 @@ static void reselect(struct AdapterCtlBlk *acb) struct ScsiReqBlk *srb = NULL; u16 rsel_tar_lun_id; u8 id, lun; - dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); clear_fifo(acb, "reselect"); /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ @@ -2974,18 +2534,11 @@ static void reselect(struct AdapterCtlBlk *acb) if (dcb) { /* Arbitration lost but Reselection win */ srb = dcb->active_srb; if (!srb) { - dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, " - "but active_srb == NULL\n"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } /* Why the if ? */ if (!acb->scan_devices) { - dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> " - "Arb lost but Resel win rsel=%i stat=0x%04x\n", - srb->cmd, dcb->target_id, - dcb->target_lun, rsel_tar_lun_id, - DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); /*srb->state |= SRB_DISCONNECT; */ srb->state = SRB_READY; @@ -2997,25 +2550,15 @@ static void reselect(struct AdapterCtlBlk *acb) } } /* Read Reselected Target Id and LUN */ - if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8))) - dprintkl(KERN_DEBUG, "reselect: Expects identify msg. " - "Got %i!\n", rsel_tar_lun_id); id = rsel_tar_lun_id & 0xff; lun = (rsel_tar_lun_id >> 8) & 7; dcb = find_dcb(acb, id, lun); if (!dcb) { - dprintkl(KERN_ERR, "reselect: From non existent device " - "<%02i-%i>\n", id, lun); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } acb->active_dcb = dcb; - if (!(dcb->dev_mode & NTC_DO_DISCONNECT)) - dprintkl(KERN_DEBUG, "reselect: in spite of forbidden " - "disconnection? <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - if (dcb->sync_mode & EN_TAG_QUEUEING) { srb = acb->tmp_srb; dcb->active_srb = srb; @@ -3026,9 +2569,6 @@ static void reselect(struct AdapterCtlBlk *acb) /* * abort command */ - dprintkl(KERN_DEBUG, - "reselect: w/o disconnected cmds <%02i-%i>\n", - dcb->target_id, dcb->target_lun); srb = acb->tmp_srb; srb->state = SRB_UNEXPECT_RESEL; dcb->active_srb = srb; @@ -3045,7 +2585,6 @@ static void reselect(struct AdapterCtlBlk *acb) srb->scsi_phase = PH_BUS_FREE; /* initial phase */ /* Program HA ID, target ID, period and offset */ - dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); /* host ID */ DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); /* target ID */ DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); /* offset */ @@ -3111,12 +2650,8 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) if (scsi_sg_count(cmd) && dir != DMA_NONE) { /* unmap DC395x SG list */ - dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", - srb->sg_bus_addr, SEGMENTX_LEN); dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN, DMA_TO_DEVICE); - dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", - scsi_sg_count(cmd), scsi_bufflen(cmd)); /* unmap the sg segments */ scsi_dma_unmap(cmd); } @@ -3130,8 +2665,6 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, if (!(srb->flag & AUTO_REQSENSE)) return; /* Unmap sense buffer */ - dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", - srb->segment_x[0].address); dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address, srb->segment_x[0].length, DMA_FROM_DEVICE); /* Restore SG stuff */ @@ -3155,16 +2688,10 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, enum dma_data_direction dir = cmd->sc_data_direction; int ckc_only = 1; - dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd, - srb->cmd->device->id, (u8)srb->cmd->device->lun); - dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", - srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, - scsi_sgtalbe(cmd)); status = srb->target_status; set_host_byte(cmd, DID_OK); set_status_byte(cmd, SAM_STAT_GOOD); if (srb->flag & AUTO_REQSENSE) { - dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); pci_unmap_srb_sense(acb, srb); /* ** target status.......................... @@ -3172,57 +2699,11 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->flag &= ~AUTO_REQSENSE; srb->adapter_status = 0; srb->target_status = SAM_STAT_CHECK_CONDITION; - if (debug_enabled(DBG_1)) { - switch (cmd->sense_buffer[2] & 0x0f) { - case NOT_READY: - dprintkl(KERN_DEBUG, - "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case UNIT_ATTENTION: - dprintkl(KERN_DEBUG, - "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case ILLEGAL_REQUEST: - dprintkl(KERN_DEBUG, - "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case MEDIUM_ERROR: - dprintkl(KERN_DEBUG, - "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case HARDWARE_ERROR: - dprintkl(KERN_DEBUG, - "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - } - if (cmd->sense_buffer[7] >= 6) - printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x " - "(0x%08x 0x%08x)\n", - cmd->sense_buffer[2], cmd->sense_buffer[12], - cmd->sense_buffer[13], - *((unsigned int *)(cmd->sense_buffer + 3)), - *((unsigned int *)(cmd->sense_buffer + 8))); - else - printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n", - cmd->sense_buffer[2], - *((unsigned int *)(cmd->sense_buffer + 3))); - } if (status == SAM_STAT_CHECK_CONDITION) { set_host_byte(cmd, DID_BAD_TARGET); goto ckc_e; } - dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n"); set_status_byte(cmd, SAM_STAT_CHECK_CONDITION); @@ -3239,8 +2720,6 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, return; } else if (status == SAM_STAT_TASK_SET_FULL) { tempcnt = (u8)list_size(&dcb->srb_going_list); - dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n", - dcb->target_id, dcb->target_lun, tempcnt); if (tempcnt > 1) tempcnt--; dcb->max_command = tempcnt; @@ -3314,21 +2793,10 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, /* Here is the info for Doug Gilbert's sg3 ... */ scsi_set_resid(cmd, srb->total_xfer_length); - if (debug_enabled(DBG_KG)) { - if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> " - "cmnd=0x%02x Missed %i bytes\n", - cmd, cmd->device->id, (u8)cmd->device->lun, - cmd->cmnd[0], srb->total_xfer_length); - } if (srb != acb->tmp_srb) { /* Add to free list */ - dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", - cmd, cmd->result); list_move_tail(&srb->list, &acb->srb_free_list); - } else { - dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); } scsi_done(cmd); @@ -3341,7 +2809,6 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, struct scsi_cmnd *cmd, u8 force) { struct DeviceCtlBlk *dcb; - dprintkl(KERN_INFO, "doing_srb_done: pids "); list_for_each_entry(dcb, &acb->dcb_list, list) { struct ScsiReqBlk *srb; @@ -3365,15 +2832,6 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, scsi_done(p); } } - if (!list_empty(&dcb->srb_going_list)) - dprintkl(KERN_DEBUG, - "How could the ML send cmnds to the Going queue? <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - if (dcb->tag_mask) - dprintkl(KERN_DEBUG, - "tag_mask for <%02i-%i> should be empty, is %08x!\n", - dcb->target_id, dcb->target_lun, - dcb->tag_mask); /* Waiting queue */ list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) { @@ -3392,19 +2850,13 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, scsi_done(cmd); } } - if (!list_empty(&dcb->srb_waiting_list)) - dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n", - list_size(&dcb->srb_waiting_list), dcb->target_id, - dcb->target_lun); dcb->flag &= ~ABORT_DEV_; } - printk("\n"); } static void reset_scsi_bus(struct AdapterCtlBlk *acb) { - dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb); acb->acb_flag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); @@ -3451,10 +2903,9 @@ static void set_basic_config(struct AdapterCtlBlk *acb) static void scsi_reset_detect(struct AdapterCtlBlk *acb) { - dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb); /* delay half a second */ if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); + timer_delete(&acb->waiting_timer); DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); @@ -3488,8 +2939,6 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct scsi_cmnd *cmd = srb->cmd; - dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n", - cmd, cmd->device->id, (u8)cmd->device->lun); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; @@ -3511,16 +2960,10 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->segment_x[0].address = dma_map_single(&acb->dev->dev, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", - cmd->sense_buffer, srb->segment_x[0].address, - SCSI_SENSE_BUFFERSIZE); srb->sg_count = 1; srb->sg_index = 0; if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ - dprintkl(KERN_DEBUG, - "request_sense: (0x%p) failed <%02i-%i>\n", - srb->cmd, dcb->target_id, dcb->target_lun); list_move(&srb->list, &dcb->srb_waiting_list); waiting_set_timer(acb, HZ / 100); } @@ -3547,8 +2990,7 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, u8 period_index = eeprom->target[target].period & 0x07; struct DeviceCtlBlk *dcb; - dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); - dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun); + dcb = kmalloc_obj(struct DeviceCtlBlk, GFP_ATOMIC); if (!dcb) return NULL; dcb->acb = NULL; @@ -3598,10 +3040,6 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, return NULL; } - dprintkdbg(DBG_1, - "device_alloc: <%02i-%i> copy from <%02i-%i>\n", - dcb->target_id, dcb->target_lun, - p->target_id, p->target_lun); dcb->sync_mode = p->sync_mode; dcb->sync_period = p->sync_period; dcb->min_nego_period = p->min_nego_period; @@ -3651,8 +3089,6 @@ static void adapter_remove_device(struct AdapterCtlBlk *acb, { struct DeviceCtlBlk *i; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n", - dcb->target_id, dcb->target_lun); /* fix up any pointers to this device that we have in the adapter */ if (acb->active_dcb == dcb) @@ -3685,10 +3121,6 @@ static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) { if (list_size(&dcb->srb_going_list) > 1) { - dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> " - "Won't remove because of %i active requests.\n", - dcb->target_id, dcb->target_lun, - list_size(&dcb->srb_going_list)); return; } adapter_remove_device(acb, dcb); @@ -3706,8 +3138,6 @@ static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) { struct DeviceCtlBlk *dcb; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n", - list_size(&acb->dcb_list)); list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) adapter_remove_and_free_device(acb, dcb); @@ -4002,8 +3432,6 @@ static void check_eeprom(struct NvRamType *eeprom, unsigned long io_port) * Checksum is wrong. * Load a set of defaults into the eeprom buffer */ - dprintkl(KERN_WARNING, - "EEProm checksum error: using default values and options.\n"); eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; @@ -4055,15 +3483,6 @@ static void check_eeprom(struct NvRamType *eeprom, unsigned long io_port) **/ static void print_eeprom_settings(struct NvRamType *eeprom) { - dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n", - eeprom->scsi_id, - eeprom->target[0].period, - clock_speed[eeprom->target[0].period] / 10, - clock_speed[eeprom->target[0].period] % 10, - eeprom->target[0].cfg0); - dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", - eeprom->channel_cfg, eeprom->max_tag, - 1 << eeprom->max_tag, eeprom->delay_time); } @@ -4094,15 +3513,12 @@ static int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) for (i = 0; i < DC395x_MAX_SRB_CNT; i++) acb->srb_array[i].segment_x = NULL; - dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages); while (pages--) { ptr = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) { adapter_sg_tables_free(acb); return 1; } - dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n", - PAGE_SIZE, ptr, srb_idx); i = 0; while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT) acb->srb_array[srb_idx++].segment_x = @@ -4111,8 +3527,6 @@ static int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) if (i < srbs_per_page) acb->srb.segment_x = ptr + (i * DC395x_MAX_SG_LISTENTRY); - else - dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n"); return 0; } @@ -4132,8 +3546,6 @@ static void adapter_print_config(struct AdapterCtlBlk *acb) u8 bval; bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS); - dprintkl(KERN_INFO, "%sConnectors: ", - ((bval & WIDESCSI) ? "(Wide) " : "")); if (!(bval & CON5068)) printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); if (!(bval & CON68)) @@ -4293,7 +3705,6 @@ static void adapter_init_chip(struct AdapterCtlBlk *acb) acb->config |= HCC_SCSI_RESET; if (acb->config & HCC_SCSI_RESET) { - dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n"); DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); /*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */ @@ -4327,7 +3738,6 @@ static int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port, u32 io_port_len, unsigned int irq) { if (!request_region(io_port, io_port_len, DC395X_NAME)) { - dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port); goto failed; } /* store port base to indicate we have registered it */ @@ -4336,7 +3746,6 @@ static int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port, if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) { /* release the region we just claimed */ - dprintkl(KERN_INFO, "Failed to register IRQ\n"); goto failed; } /* store irq to indicate we have registered it */ @@ -4353,18 +3762,12 @@ static int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port, adapter_print_config(acb); if (adapter_sg_tables_alloc(acb)) { - dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n"); goto failed; } adapter_init_scsi_host(acb->scsi_host); adapter_init_chip(acb); set_basic_config(acb); - dprintkdbg(DBG_0, - "adapter_init: acb=%p, pdcb_map=%p psrb_array=%p " - "size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n", - acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), - sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); return 0; failed: @@ -4415,9 +3818,9 @@ static void adapter_uninit(struct AdapterCtlBlk *acb) /* remove timers */ if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); + timer_delete(&acb->waiting_timer); if (timer_pending(&acb->selto_timer)) - del_timer(&acb->selto_timer); + timer_delete(&acb->selto_timer); adapter_uninit_chip(acb); adapter_remove_and_free_all_devices(acb); @@ -4528,14 +3931,6 @@ static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host) seq_putc(m, '\n'); } - if (debug_enabled(DBG_1)) { - seq_printf(m, "DCB list for ACB %p:\n", acb); - list_for_each_entry(dcb, &acb->dcb_list, list) { - seq_printf(m, "%p -> ", dcb); - } - seq_puts(m, "END\n"); - } - DC395x_UNLOCK_IO(acb->scsi_host, flags); return 0; } @@ -4560,21 +3955,6 @@ static const struct scsi_host_template dc395x_driver_template = { /** - * banner_display - Display banner on first instance of driver - * initialized. - **/ -static void banner_display(void) -{ - static int banner_done = 0; - if (!banner_done) - { - dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION); - banner_done = 1; - } -} - - -/** * dc395x_init_one - Initialise a single instance of the adapter. * * The PCI layer will call this once for each instance of the adapter @@ -4595,33 +3975,25 @@ static int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id) unsigned int io_port_len; unsigned int irq; - dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev)); - banner_display(); - if (pci_enable_device(dev)) - { - dprintkl(KERN_INFO, "PCI Enable device failed.\n"); return -ENODEV; - } + io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK; io_port_len = pci_resource_len(dev, 0); irq = dev->irq; - dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq); /* allocate scsi host information (includes out adapter) */ scsi_host = scsi_host_alloc(&dc395x_driver_template, sizeof(struct AdapterCtlBlk)); - if (!scsi_host) { - dprintkl(KERN_INFO, "scsi_host_alloc failed\n"); + if (!scsi_host) goto fail; - } + acb = (struct AdapterCtlBlk*)scsi_host->hostdata; acb->scsi_host = scsi_host; acb->dev = dev; /* initialise the adapter and everything we need */ if (adapter_init(acb, io_port_base, io_port_len, irq)) { - dprintkl(KERN_INFO, "adapter init failed\n"); acb = NULL; goto fail; } @@ -4629,10 +4001,9 @@ static int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_set_master(dev); /* get the scsi mid level to scan for new devices on the bus */ - if (scsi_add_host(scsi_host, &dev->dev)) { - dprintkl(KERN_ERR, "scsi_add_host failed\n"); + if (scsi_add_host(scsi_host, &dev->dev)) goto fail; - } + pci_set_drvdata(dev, scsi_host); scsi_scan_host(scsi_host); @@ -4659,8 +4030,6 @@ static void dc395x_remove_one(struct pci_dev *dev) struct Scsi_Host *scsi_host = pci_get_drvdata(dev); struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata); - dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb); - scsi_remove_host(scsi_host); adapter_uninit(acb); pci_disable_device(dev); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 1bf5948d1188..80ab0ff921d4 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -37,7 +37,7 @@ #define TPGS_MODE_EXPLICIT 0x2 #define ALUA_RTPG_SIZE 128 -#define ALUA_FAILOVER_TIMEOUT 60 +#define ALUA_FAILOVER_TIMEOUT 255 /* max 255 (8-bit value) */ #define ALUA_FAILOVER_RETRIES 5 #define ALUA_RTPG_DELAY_MSECS 5 #define ALUA_RTPG_RETRY_DELAY 2 @@ -219,7 +219,7 @@ static struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, { struct alua_port_group *pg, *tmp_pg; - pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); + pg = kzalloc_obj(struct alua_port_group); if (!pg) return ERR_PTR(-ENOMEM); @@ -1137,7 +1137,7 @@ static int alua_activate(struct scsi_device *sdev, struct alua_queue_data *qdata; struct alua_port_group *pg; - qdata = kzalloc(sizeof(*qdata), GFP_KERNEL); + qdata = kzalloc_obj(*qdata); if (!qdata) { err = SCSI_DH_RES_TEMP_UNAVAIL; goto out; @@ -1239,7 +1239,7 @@ static int alua_bus_attach(struct scsi_device *sdev) struct alua_dh_data *h; int err; - h = kzalloc(sizeof(*h) , GFP_KERNEL); + h = kzalloc_obj(*h); if (!h) return SCSI_DH_NOMEM; spin_lock_init(&h->pg_lock); @@ -1300,7 +1300,7 @@ static int __init alua_init(void) { int r; - kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0); + kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!kaluad_wq) return -ENOMEM; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 3cf88db2d5b2..ff41b51ef462 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -478,7 +478,7 @@ static int clariion_bus_attach(struct scsi_device *sdev) struct clariion_dh_data *h; int err; - h = kzalloc(sizeof(*h) , GFP_KERNEL); + h = kzalloc_obj(*h); if (!h) return SCSI_DH_NOMEM; h->lun_state = CLARIION_LUN_UNINITIALIZED; diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index b6eaf49dfb00..6e8849d7f0a3 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -226,7 +226,7 @@ static int hp_sw_bus_attach(struct scsi_device *sdev) struct hp_sw_dh_data *h; int ret; - h = kzalloc(sizeof(*h), GFP_KERNEL); + h = kzalloc_obj(*h); if (!h) return SCSI_DH_NOMEM; h->path_state = HP_SW_PATH_UNINITIALIZED; diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 6e1b252cea0e..88c8e36b221e 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -336,7 +336,7 @@ static struct rdac_controller *get_controller(int index, char *array_name, return tmp; } } - ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); + ctlr = kmalloc_obj(*ctlr, GFP_ATOMIC); if (!ctlr) return NULL; @@ -601,7 +601,7 @@ static int queue_mode_select(struct scsi_device *sdev, struct rdac_queue_data *qdata; struct rdac_controller *ctlr; - qdata = kzalloc(sizeof(*qdata), GFP_KERNEL); + qdata = kzalloc_obj(*qdata); if (!qdata) return SCSI_DH_RETRY; @@ -741,7 +741,7 @@ static int rdac_bus_attach(struct scsi_device *sdev) char array_name[ARRAY_LABEL_LEN]; char array_id[UNIQUE_ID_LEN]; - h = kzalloc(sizeof(*h) , GFP_KERNEL); + h = kzalloc_obj(*h); if (!h) return SCSI_DH_NOMEM; h->lun = UNINITIALIZED_LUN; diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c index 8469c156ab33..07c2f453459e 100644 --- a/drivers/scsi/elx/efct/efct_driver.c +++ b/drivers/scsi/elx/efct/efct_driver.c @@ -93,7 +93,7 @@ efct_efclib_config(struct efct *efct, struct libefc_function_template *tt) struct sli4 *sli; int rc = 0; - efc = kzalloc(sizeof(*efc), GFP_KERNEL); + efc = kzalloc_obj(*efc); if (!efc) return -ENOMEM; @@ -310,7 +310,7 @@ efct_fw_reset(struct efct *efct) * during attach. */ if (timer_pending(&efct->xport->stats_timer)) - del_timer(&efct->xport->stats_timer); + timer_delete(&efct->xport->stats_timer); if (efct_hw_reset(&efct->hw, EFCT_HW_RESET_FIRMWARE)) { efc_log_info(efct, "failed to reset firmware\n"); @@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) return IRQ_HANDLED; } -static irqreturn_t -efct_intr_msix(int irq, void *handle) -{ - return IRQ_WAKE_THREAD; -} - static int efct_setup_msix(struct efct *efct, u32 num_intrs) { @@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) intr_ctx->index = i; rc = request_threaded_irq(pci_irq_vector(efct->pci, i), - efct_intr_msix, efct_intr_thread, 0, + NULL, efct_intr_thread, IRQF_ONESHOT, EFCT_DRIVER_NAME, intr_ctx); if (rc) { dev_err(&efct->pci->dev, @@ -735,7 +729,7 @@ efct_pci_io_resume(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, efct_pci_table); -static struct pci_error_handlers efct_pci_err_handler = { +static const struct pci_error_handlers efct_pci_err_handler = { .error_detected = efct_pci_io_error_detected, .slot_reset = efct_pci_io_slot_reset, .resume = efct_pci_io_resume, diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c index 5a5525054d71..1838032f6486 100644 --- a/drivers/scsi/elx/efct/efct_hw.c +++ b/drivers/scsi/elx/efct/efct_hw.c @@ -487,14 +487,14 @@ efct_hw_setup_io(struct efct_hw *hw) struct efct *efct = hw->os; if (!hw->io) { - hw->io = kmalloc_array(hw->config.n_io, sizeof(io), GFP_KERNEL); + hw->io = kmalloc_objs(io, hw->config.n_io); if (!hw->io) return -ENOMEM; memset(hw->io, 0, hw->config.n_io * sizeof(io)); for (i = 0; i < hw->config.n_io; i++) { - hw->io[i] = kzalloc(sizeof(*io), GFP_KERNEL); + hw->io[i] = kzalloc_obj(*io); if (!hw->io[i]) goto error; } @@ -611,7 +611,7 @@ efct_hw_init_prereg_io(struct efct_hw *hw) struct efc_dma req; struct efct *efct = hw->os; - sgls = kmalloc_array(sgls_per_request, sizeof(*sgls), GFP_KERNEL); + sgls = kmalloc_objs(*sgls, sgls_per_request); if (!sgls) return -ENOMEM; @@ -1120,7 +1120,7 @@ int efct_hw_parse_filter(struct efct_hw *hw, void *value) { int rc = 0; - char *p = NULL; + char *p = NULL, *pp = NULL; char *token; u32 idx = 0; @@ -1132,6 +1132,7 @@ efct_hw_parse_filter(struct efct_hw *hw, void *value) efc_log_err(hw->os, "p is NULL\n"); return -ENOMEM; } + pp = p; idx = 0; while ((token = strsep(&p, ",")) && *token) { @@ -1144,7 +1145,7 @@ efct_hw_parse_filter(struct efct_hw *hw, void *value) if (idx == ARRAY_SIZE(hw->config.filter_def)) break; } - kfree(p); + kfree(pp); return rc; } @@ -1181,7 +1182,7 @@ efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count, if (!count) return NULL; - rq_buf = kmalloc_array(count, sizeof(*rq_buf), GFP_KERNEL); + rq_buf = kmalloc_objs(*rq_buf, count); if (!rq_buf) return NULL; memset(rq_buf, 0, sizeof(*rq_buf) * count); @@ -1286,8 +1287,7 @@ efct_hw_rx_post(struct efct_hw *hw) for (i = 0; i < hw->hw_rq_count; i++) count += hw->hw_rq[i]->entry_count; - hw->seq_pool = kmalloc_array(count, - sizeof(struct efc_hw_sequence), GFP_KERNEL); + hw->seq_pool = kmalloc_objs(struct efc_hw_sequence, count); if (!hw->seq_pool) return -ENOMEM; } @@ -2063,7 +2063,7 @@ efct_hw_reqtag_pool_alloc(struct efct_hw *hw) struct reqtag_pool *reqtag_pool; struct hw_wq_callback *wqcb; - reqtag_pool = kzalloc(sizeof(*reqtag_pool), GFP_KERNEL); + reqtag_pool = kzalloc_obj(*reqtag_pool); if (!reqtag_pool) return NULL; @@ -2071,7 +2071,7 @@ efct_hw_reqtag_pool_alloc(struct efct_hw *hw) /* initialize reqtag pool lock */ spin_lock_init(&reqtag_pool->lock); for (i = 0; i < U16_MAX; i++) { - wqcb = kmalloc(sizeof(*wqcb), GFP_KERNEL); + wqcb = kmalloc_obj(*wqcb); if (!wqcb) break; @@ -3104,7 +3104,7 @@ efct_hw_get_link_stats(struct efct_hw *hw, u8 req_ext_counters, struct efct_hw_link_stat_cb_arg *cb_arg; u8 mbxdata[SLI4_BMBX_SIZE]; - cb_arg = kzalloc(sizeof(*cb_arg), GFP_ATOMIC); + cb_arg = kzalloc_obj(*cb_arg, GFP_ATOMIC); if (!cb_arg) return -ENOMEM; @@ -3188,7 +3188,7 @@ efct_hw_get_host_stats(struct efct_hw *hw, u8 cc, struct efct_hw_host_stat_cb_arg *cb_arg; u8 mbxdata[SLI4_BMBX_SIZE]; - cb_arg = kmalloc(sizeof(*cb_arg), GFP_ATOMIC); + cb_arg = kmalloc_obj(*cb_arg, GFP_ATOMIC); if (!cb_arg) return -ENOMEM; @@ -3238,7 +3238,7 @@ efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg) * we need this to be persistent as the mbox cmd submission may be * queued and executed later execution. */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc_obj(*ctx); if (!ctx) return -ENOMEM; @@ -3306,7 +3306,7 @@ efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma, u32 size, struct efct_hw_fw_wr_cb_arg *cb_arg; int noc = 0; - cb_arg = kzalloc(sizeof(*cb_arg), GFP_KERNEL); + cb_arg = kzalloc_obj(*cb_arg); if (!cb_arg) return -ENOMEM; diff --git a/drivers/scsi/elx/efct/efct_hw_queues.c b/drivers/scsi/elx/efct/efct_hw_queues.c index 3a1d1a5864a3..3c27f927f96c 100644 --- a/drivers/scsi/elx/efct/efct_hw_queues.c +++ b/drivers/scsi/elx/efct/efct_hw_queues.c @@ -127,7 +127,7 @@ efct_hw_map_wq_cpu(struct efct_hw *hw) struct hw_eq * efct_hw_new_eq(struct efct_hw *hw, u32 entry_count) { - struct hw_eq *eq = kzalloc(sizeof(*eq), GFP_KERNEL); + struct hw_eq *eq = kzalloc_obj(*eq); if (!eq) return NULL; @@ -159,7 +159,7 @@ struct hw_cq * efct_hw_new_cq(struct hw_eq *eq, u32 entry_count) { struct efct_hw *hw = eq->hw; - struct hw_cq *cq = kzalloc(sizeof(*cq), GFP_KERNEL); + struct hw_cq *cq = kzalloc_obj(*cq); if (!cq) return NULL; @@ -204,7 +204,7 @@ efct_hw_new_cq_set(struct hw_eq *eqs[], struct hw_cq *cqs[], cqs[i] = NULL; for (i = 0; i < num_cqs; i++) { - cq = kzalloc(sizeof(*cq), GFP_KERNEL); + cq = kzalloc_obj(*cq); if (!cq) goto error; @@ -244,7 +244,7 @@ struct hw_mq * efct_hw_new_mq(struct hw_cq *cq, u32 entry_count) { struct efct_hw *hw = cq->eq->hw; - struct hw_mq *mq = kzalloc(sizeof(*mq), GFP_KERNEL); + struct hw_mq *mq = kzalloc_obj(*mq); if (!mq) return NULL; @@ -275,7 +275,7 @@ struct hw_wq * efct_hw_new_wq(struct hw_cq *cq, u32 entry_count) { struct efct_hw *hw = cq->eq->hw; - struct hw_wq *wq = kzalloc(sizeof(*wq), GFP_KERNEL); + struct hw_wq *wq = kzalloc_obj(*wq); if (!wq) return NULL; @@ -324,7 +324,7 @@ efct_hw_new_rq_set(struct hw_cq *cqs[], struct hw_rq *rqs[], * encapsulates 2 SLI queues (for rq pair) */ for (i = 0, q_count = 0; i < num_rq_pairs; i++, q_count += 2) { - rq = kzalloc(sizeof(*rq), GFP_KERNEL); + rq = kzalloc_obj(*rq); if (!rq) goto error; diff --git a/drivers/scsi/elx/efct/efct_io.c b/drivers/scsi/elx/efct/efct_io.c index c612f0a48839..91ab64ce9f97 100644 --- a/drivers/scsi/elx/efct/efct_io.c +++ b/drivers/scsi/elx/efct/efct_io.c @@ -25,7 +25,7 @@ efct_io_pool_create(struct efct *efct, u32 num_sgl) struct efct_io *io; /* Allocate the IO pool */ - io_pool = kzalloc(sizeof(*io_pool), GFP_KERNEL); + io_pool = kzalloc_obj(*io_pool); if (!io_pool) return NULL; @@ -35,7 +35,7 @@ efct_io_pool_create(struct efct *efct, u32 num_sgl) spin_lock_init(&io_pool->lock); for (i = 0; i < EFCT_NUM_SCSI_IOS; i++) { - io = kzalloc(sizeof(*io), GFP_KERNEL); + io = kzalloc_obj(*io); if (!io) break; diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c index 9ac69356b13e..67d686dd6fb3 100644 --- a/drivers/scsi/elx/efct/efct_lio.c +++ b/drivers/scsi/elx/efct/efct_lio.c @@ -382,7 +382,7 @@ efct_lio_sg_unmap(struct efct_io *io) return; dma_unmap_sg(&io->efct->pci->dev, cmd->t_data_sg, - ocp->seg_map_cnt, cmd->data_direction); + cmd->t_data_nents, cmd->data_direction); ocp->seg_map_cnt = 0; } @@ -744,7 +744,7 @@ efct_lio_make_nport(struct target_fabric_configfs *tf, return ERR_PTR(-ENXIO); } - lio_nport = kzalloc(sizeof(*lio_nport), GFP_KERNEL); + lio_nport = kzalloc_obj(*lio_nport); if (!lio_nport) return ERR_PTR(-ENOMEM); @@ -796,7 +796,7 @@ efct_lio_npiv_make_nport(struct target_fabric_configfs *tf, return ERR_PTR(-ENXIO); } - lio_vport = kzalloc(sizeof(*lio_vport), GFP_KERNEL); + lio_vport = kzalloc_obj(*lio_vport); if (!lio_vport) return ERR_PTR(-ENOMEM); @@ -808,7 +808,7 @@ efct_lio_npiv_make_nport(struct target_fabric_configfs *tf, efct_format_wwn(lio_vport->wwpn_str, sizeof(lio_vport->wwpn_str), "naa.", npiv_wwpn); - vport_list = kzalloc(sizeof(*vport_list), GFP_KERNEL); + vport_list = kzalloc_obj(*vport_list); if (!vport_list) { kfree(lio_vport); return ERR_PTR(-ENOMEM); @@ -895,7 +895,7 @@ efct_lio_make_tpg(struct se_wwn *wwn, const char *name) if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX) return ERR_PTR(-EINVAL); - tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); + tpg = kzalloc_obj(*tpg); if (!tpg) return ERR_PTR(-ENOMEM); @@ -958,7 +958,7 @@ efct_lio_npiv_make_tpg(struct se_wwn *wwn, const char *name) return ERR_PTR(-EINVAL); } - tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); + tpg = kzalloc_obj(*tpg); if (!tpg) return ERR_PTR(-ENOMEM); @@ -1069,7 +1069,7 @@ static int efct_session_cb(struct se_portal_group *se_tpg, struct efct_node *tgt_node; struct efct *efct = node->efc->base; - tgt_node = kzalloc(sizeof(*tgt_node), GFP_KERNEL); + tgt_node = kzalloc_obj(*tgt_node); if (!tgt_node) return -ENOMEM; @@ -1227,7 +1227,7 @@ int efct_scsi_new_initiator(struct efc *efc, struct efc_node *node) * Since LIO only supports initiator validation at thread level, * we are open minded and accept all callers. */ - wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC); + wq_data = kzalloc_obj(*wq_data, GFP_ATOMIC); if (!wq_data) return -ENOMEM; @@ -1292,7 +1292,7 @@ int efct_scsi_del_initiator(struct efc *efc, struct efc_node *node, int reason) return -EIO; } - wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC); + wq_data = kzalloc_obj(*wq_data, GFP_ATOMIC); if (!wq_data) return -ENOMEM; @@ -1612,6 +1612,7 @@ static const struct target_core_fabric_ops efct_lio_ops = { .sess_get_initiator_sid = NULL, .tfc_tpg_base_attrs = efct_lio_tpg_attrs, .tfc_tpg_attrib_attrs = efct_lio_tpg_attrib_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; @@ -1650,6 +1651,7 @@ static const struct target_core_fabric_ops efct_lio_npiv_ops = { .tfc_tpg_base_attrs = efct_lio_npiv_tpg_attrs, .tfc_tpg_attrib_attrs = efct_lio_npiv_tpg_attrib_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; diff --git a/drivers/scsi/elx/efct/efct_xport.c b/drivers/scsi/elx/efct/efct_xport.c index cf4dced20b8b..9dcaef6fc188 100644 --- a/drivers/scsi/elx/efct/efct_xport.c +++ b/drivers/scsi/elx/efct/efct_xport.c @@ -28,7 +28,7 @@ efct_xport_alloc(struct efct *efct) { struct efct_xport *xport; - xport = kzalloc(sizeof(*xport), GFP_KERNEL); + xport = kzalloc_obj(*xport); if (!xport) return xport; @@ -180,7 +180,7 @@ efct_xport_config_stats_timer(struct efct *efct); static void efct_xport_stats_timer_cb(struct timer_list *t) { - struct efct_xport *xport = from_timer(xport, t, stats_timer); + struct efct_xport *xport = timer_container_of(xport, t, stats_timer); struct efct *efct = xport->efct; efct_xport_config_stats_timer(efct); @@ -508,7 +508,7 @@ efct_xport_detach(struct efct_xport *xport) /*Shutdown FC Statistics timer*/ if (timer_pending(&xport->stats_timer)) - del_timer(&xport->stats_timer); + timer_delete(&xport->stats_timer); efct_hw_teardown(&efct->hw); diff --git a/drivers/scsi/elx/libefc/efc_domain.c b/drivers/scsi/elx/libefc/efc_domain.c index ca9d7ff2c0d2..554a538ffd33 100644 --- a/drivers/scsi/elx/libefc/efc_domain.c +++ b/drivers/scsi/elx/libefc/efc_domain.c @@ -134,7 +134,7 @@ efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn) { struct efc_domain *domain; - domain = kzalloc(sizeof(*domain), GFP_ATOMIC); + domain = kzalloc_obj(*domain, GFP_ATOMIC); if (!domain) return NULL; diff --git a/drivers/scsi/elx/libefc/efc_els.c b/drivers/scsi/elx/libefc/efc_els.c index 84bc81d7ce76..1786cee08729 100644 --- a/drivers/scsi/elx/libefc/efc_els.c +++ b/drivers/scsi/elx/libefc/efc_els.c @@ -147,7 +147,7 @@ efc_els_retry(struct efc_els_io_req *els); static void efc_els_delay_timer_cb(struct timer_list *t) { - struct efc_els_io_req *els = from_timer(els, t, delay_timer); + struct efc_els_io_req *els = timer_container_of(els, t, delay_timer); /* Retry delay timer expired, retry the ELS request */ efc_els_retry(els); diff --git a/drivers/scsi/elx/libefc/efc_fabric.c b/drivers/scsi/elx/libefc/efc_fabric.c index 9661eea93aa1..12e82deb2a35 100644 --- a/drivers/scsi/elx/libefc/efc_fabric.c +++ b/drivers/scsi/elx/libefc/efc_fabric.c @@ -685,7 +685,7 @@ efc_process_gidpt_payload(struct efc_node *node, } /* Allocate a buffer for all nodes */ - active_nodes = kcalloc(port_count, sizeof(*active_nodes), GFP_ATOMIC); + active_nodes = kzalloc_objs(*active_nodes, port_count, GFP_ATOMIC); if (!active_nodes) { node_printf(node, "efc_malloc failed\n"); return -EIO; @@ -886,9 +886,9 @@ __efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg) static void gidpt_delay_timer_cb(struct timer_list *t) { - struct efc_node *node = from_timer(node, t, gidpt_delay_timer); + struct efc_node *node = timer_container_of(node, t, gidpt_delay_timer); - del_timer(&node->gidpt_delay_timer); + timer_delete(&node->gidpt_delay_timer); efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL); } diff --git a/drivers/scsi/elx/libefc/efc_node.c b/drivers/scsi/elx/libefc/efc_node.c index a1b4ce6a27b4..f17e052fe537 100644 --- a/drivers/scsi/elx/libefc/efc_node.c +++ b/drivers/scsi/elx/libefc/efc_node.c @@ -149,7 +149,7 @@ efc_node_free(struct efc_node *node) /* if the gidpt_delay_timer is still running, then delete it */ if (timer_pending(&node->gidpt_delay_timer)) - del_timer(&node->gidpt_delay_timer); + timer_delete(&node->gidpt_delay_timer); xa_erase(&nport->lookup, node->rnode.fc_id); diff --git a/drivers/scsi/elx/libefc/efc_nport.c b/drivers/scsi/elx/libefc/efc_nport.c index 1a7437f4328e..1ea26c7337eb 100644 --- a/drivers/scsi/elx/libefc/efc_nport.c +++ b/drivers/scsi/elx/libefc/efc_nport.c @@ -82,7 +82,7 @@ efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn, } } - nport = kzalloc(sizeof(*nport), GFP_ATOMIC); + nport = kzalloc_obj(*nport, GFP_ATOMIC); if (!nport) return nport; @@ -756,7 +756,7 @@ efc_vport_create_spec(struct efc *efc, uint64_t wwnn, uint64_t wwpn, } } - vport = kzalloc(sizeof(*vport), GFP_ATOMIC); + vport = kzalloc_obj(*vport, GFP_ATOMIC); if (!vport) { spin_unlock_irqrestore(&efc->vport_lock, flags); return NULL; diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c index 5e7fb110bc3f..d9a231fc0e0d 100644 --- a/drivers/scsi/elx/libefc_sli/sli4.c +++ b/drivers/scsi/elx/libefc_sli/sli4.c @@ -3804,7 +3804,7 @@ sli_cmd_common_write_object(struct sli4 *sli4, void *buf, u16 noc, wr_obj->desired_write_len_dword = cpu_to_le32(dwflags); wr_obj->write_offset = cpu_to_le32(offset); - strncpy(wr_obj->object_name, obj_name, sizeof(wr_obj->object_name) - 1); + strscpy(wr_obj->object_name, obj_name); wr_obj->host_buffer_descriptor_count = cpu_to_le32(1); bde = (struct sli4_bde *)wr_obj->host_buffer_descriptor; @@ -3833,7 +3833,7 @@ sli_cmd_common_delete_object(struct sli4 *sli4, void *buf, char *obj_name) SLI4_SUBSYSTEM_COMMON, CMD_V0, SLI4_RQST_PYLD_LEN(cmn_delete_object)); - strncpy(req->object_name, obj_name, sizeof(req->object_name) - 1); + strscpy(req->object_name, obj_name); return 0; } @@ -3856,7 +3856,7 @@ sli_cmd_common_read_object(struct sli4 *sli4, void *buf, u32 desired_read_len, cpu_to_le32(desired_read_len & SLI4_REQ_DESIRE_READLEN); rd_obj->read_offset = cpu_to_le32(offset); - strncpy(rd_obj->object_name, obj_name, sizeof(rd_obj->object_name) - 1); + strscpy(rd_obj->object_name, obj_name); rd_obj->host_buffer_descriptor_count = cpu_to_le32(1); bde = (struct sli4_bde *)rd_obj->host_buffer_descriptor; diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index c48275d53aef..a763edd05fe4 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -968,7 +968,8 @@ int esas2r_ioctl_handler(void *hostdata, unsigned int cmd, void __user *arg); int esas2r_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *arg); u8 handle_hba_ioctl(struct esas2r_adapter *a, struct atto_ioctl *ioctl_hba); -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd); +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd); int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh); long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 0cea5f3d1a08..0a35f1953768 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -103,8 +103,7 @@ static void esas2r_initmem_free(struct esas2r_adapter *a, static bool alloc_vda_req(struct esas2r_adapter *a, struct esas2r_request *rq) { - struct esas2r_mem_desc *memdesc = kzalloc( - sizeof(struct esas2r_mem_desc), GFP_KERNEL); + struct esas2r_mem_desc *memdesc = kzalloc_obj(struct esas2r_mem_desc); if (memdesc == NULL) { esas2r_hdebug("could not alloc mem for vda request memdesc\n"); @@ -439,7 +438,7 @@ static void esas2r_adapter_power_down(struct esas2r_adapter *a, if ((test_bit(AF2_INIT_DONE, &a->flags2)) && (!test_bit(AF_DEGRADED_MODE, &a->flags))) { if (!power_management) { - del_timer_sync(&a->timer); + timer_delete_sync(&a->timer); tasklet_kill(&a->tasklet); } esas2r_power_down(a); @@ -783,8 +782,7 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, /* allocate requests for asynchronous events */ a->first_ae_req = - kcalloc(num_ae_requests, sizeof(struct esas2r_request), - GFP_KERNEL); + kzalloc_objs(struct esas2r_request, num_ae_requests); if (a->first_ae_req == NULL) { esas2r_log(ESAS2R_LOG_CRIT, @@ -793,8 +791,7 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, } /* allocate the S/G list memory descriptors */ - a->sg_list_mds = kcalloc(num_sg_lists, sizeof(struct esas2r_mem_desc), - GFP_KERNEL); + a->sg_list_mds = kzalloc_objs(struct esas2r_mem_desc, num_sg_lists); if (a->sg_list_mds == NULL) { esas2r_log(ESAS2R_LOG_CRIT, @@ -804,9 +801,8 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, /* allocate the request table */ a->req_table = - kcalloc(num_requests + num_ae_requests + 1, - sizeof(struct esas2r_request *), - GFP_KERNEL); + kzalloc_objs(struct esas2r_request *, + num_requests + num_ae_requests + 1); if (a->req_table == NULL) { esas2r_log(ESAS2R_LOG_CRIT, diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c index d6c87a0bae09..46f489b2263c 100644 --- a/drivers/scsi/esas2r/esas2r_log.c +++ b/drivers/scsi/esas2r/esas2r_log.c @@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) } } -#pragma GCC diagnostic push -#ifndef __clang__ -#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" -#endif - /* * the master logging function. this function will format the message as * outlined by the formatting string, the input device information and the @@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) * * @return 0 on success, or -1 if an error occurred. */ -static int esas2r_log_master(const long level, - const struct device *dev, - const char *format, - va_list args) +static __printf(3, 0) +int esas2r_log_master(const long level, const struct device *dev, + const char *format, va_list args) { if (level <= event_log_level) { unsigned long flags = 0; @@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, return 0; } -#pragma GCC diagnostic pop - /* * formats and logs a message to the system log. * diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 44871746944a..ada278c24c51 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -194,8 +194,7 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj, int length = min(sizeof(struct atto_ioctl), count); if (!a->local_atto_ioctl) { - a->local_atto_ioctl = kmalloc(sizeof(struct atto_ioctl), - GFP_KERNEL); + a->local_atto_ioctl = kmalloc_obj(struct atto_ioctl); if (a->local_atto_ioctl == NULL) { esas2r_log(ESAS2R_LOG_WARN, "write_hw kzalloc failed for %zu bytes", @@ -215,8 +214,8 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj, .attr = \ { .name = __stringify(_name), .mode = S_IRUSR | S_IWUSR }, \ .size = 0, \ - .read_new = read_ ## _name, \ - .write_new = write_ ## _name } + .read = read_ ## _name, \ + .write = write_ ## _name } ESAS2R_RW_BIN_ATTR(fw); ESAS2R_RW_BIN_ATTR(fs); @@ -227,7 +226,7 @@ ESAS2R_RW_BIN_ATTR(live_nvram); const struct bin_attribute bin_attr_default_nvram = { .attr = { .name = "default_nvram", .mode = S_IRUGO }, .size = 0, - .read_new = read_default_nvram, + .read = read_default_nvram, .write = NULL }; @@ -818,7 +817,8 @@ static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr) return len; } -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct esas2r_adapter *a = (struct esas2r_adapter *)cmd->device->host->hostdata; @@ -1585,7 +1585,7 @@ void esas2r_kickoff_timer(struct esas2r_adapter *a) static void esas2r_timer_callback(struct timer_list *t) { - struct esas2r_adapter *a = from_timer(a, t, timer); + struct esas2r_adapter *a = timer_container_of(a, t, timer); set_bit(AF2_TIMER_TICK, &a->flags2); @@ -1830,7 +1830,7 @@ void esas2r_queue_fw_event(struct esas2r_adapter *a, struct esas2r_fw_event_work *fw_event; unsigned long flags; - fw_event = kzalloc(sizeof(struct esas2r_fw_event_work), GFP_ATOMIC); + fw_event = kzalloc_obj(struct esas2r_fw_event_work, GFP_ATOMIC); if (!fw_event) { esas2r_log(ESAS2R_LOG_WARN, "esas2r_queue_fw_event failed to alloc"); diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 802718ffad84..897a01d3e303 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -881,7 +881,7 @@ static struct esp_cmd_entry *esp_get_ent(struct esp *esp) struct esp_cmd_entry *ret; if (list_empty(head)) { - ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC); + ret = kzalloc_obj(struct esp_cmd_entry, GFP_ATOMIC); } else { ret = list_entry(head->next, struct esp_cmd_entry, list); list_del(&ret->list); @@ -952,7 +952,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) scsi_track_queue_full(dev, lp->num_tagged - 1); } -static int esp_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status esp_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_device *dev = cmd->device; struct esp *esp = shost_priv(dev->host); @@ -2447,7 +2447,7 @@ static int esp_sdev_init(struct scsi_device *dev) struct esp_target_data *tp = &esp->target[dev->id]; struct esp_lun_data *lp; - lp = kzalloc(sizeof(*lp), GFP_KERNEL); + lp = kzalloc_obj(*lp); if (!lp) return -ENOMEM; dev->hostdata = lp; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 038e38578676..534596c6d76c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -820,7 +820,7 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev) if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) { struct netdev_fcoe_hbainfo *fdmi; - fdmi = kzalloc(sizeof(*fdmi), GFP_KERNEL); + fdmi = kzalloc_obj(*fdmi); if (!fdmi) return; @@ -1013,7 +1013,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) fc_lport_destroy(lport); /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); + timer_delete_sync(&port->timer); /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); @@ -1300,26 +1300,6 @@ static void fcoe_thread_cleanup_local(unsigned int cpu) } /** - * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming - * command. - * - * This routine selects next CPU based on cpumask to distribute - * incoming requests in round robin. - * - * Returns: int CPU number - */ -static inline unsigned int fcoe_select_cpu(void) -{ - static unsigned int selected_cpu; - - selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); - if (selected_cpu >= nr_cpu_ids) - selected_cpu = cpumask_first(cpu_online_mask); - - return selected_cpu; -} - -/** * fcoe_rcv() - Receive packets from a net device * @skb: The received packet * @netdev: The net device that the packet was received on @@ -1405,7 +1385,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; else { if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN) - cpu = fcoe_select_cpu(); + cpu = skb->alloc_cpu; else cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; } @@ -2458,7 +2438,7 @@ static int __init fcoe_init(void) unsigned int cpu; int rc = 0; - fcoe_wq = alloc_workqueue("fcoe", 0, 0); + fcoe_wq = alloc_workqueue("fcoe", WQ_PERCPU, 0); if (!fcoe_wq) return -ENOMEM; diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 5c8d1ba3f8f3..02cd4410efca 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -168,7 +168,7 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", new->fabric_name, new->fcf_mac); - temp = kzalloc(sizeof(*temp), GFP_KERNEL); + temp = kzalloc_obj(*temp); if (!temp) goto out; @@ -302,7 +302,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) fcoe_ctlr_set_state(fip, FIP_ST_DISABLED); fcoe_ctlr_reset_fcfs(fip); mutex_unlock(&fip->ctlr_mutex); - del_timer_sync(&fip->timer); + timer_delete_sync(&fip->timer); cancel_work_sync(&fip->timer_work); } EXPORT_SYMBOL(fcoe_ctlr_destroy); @@ -478,7 +478,7 @@ EXPORT_SYMBOL(fcoe_ctlr_link_up); static void fcoe_ctlr_reset(struct fcoe_ctlr *fip) { fcoe_ctlr_reset_fcfs(fip); - del_timer(&fip->timer); + timer_delete(&fip->timer); fip->ctlr_ka_time = 0; fip->port_ka_time = 0; fip->sol_time = 0; @@ -1043,7 +1043,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT) goto out; - fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC); + fcf = kmalloc_obj(*fcf, GFP_ATOMIC); if (!fcf) goto out; @@ -1378,8 +1378,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, */ num_vlink_desc = rlen / sizeof(*vp); if (num_vlink_desc) - vlink_desc_arr = kmalloc_array(num_vlink_desc, sizeof(vp), - GFP_ATOMIC); + vlink_desc_arr = kmalloc_objs(vp, num_vlink_desc, GFP_ATOMIC); if (!vlink_desc_arr) return; num_vlink_desc = 0; @@ -1773,7 +1772,7 @@ unlock: */ static void fcoe_ctlr_timeout(struct timer_list *t) { - struct fcoe_ctlr *fip = from_timer(fip, t, timer); + struct fcoe_ctlr *fip = timer_container_of(fip, t, timer); schedule_work(&fip->timer_work); } diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 0609ca6b9353..afea5763a3c0 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -986,7 +986,7 @@ struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, } } - fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC); + fcf = kzalloc_obj(struct fcoe_fcf_device, GFP_ATOMIC); if (unlikely(!fcf)) goto out; diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index a48d24af9ac3..88d85fc9a52a 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -447,7 +447,7 @@ EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); */ void fcoe_queue_timer(struct timer_list *t) { - struct fcoe_port *port = from_timer(port, t, timer); + struct fcoe_port *port = timer_container_of(port, t, timer); fcoe_check_wait_queue(port->lport, NULL); } @@ -638,7 +638,7 @@ static int fcoe_add_netdev_mapping(struct net_device *netdev, { struct fcoe_netdev_mapping *nm; - nm = kmalloc(sizeof(*nm), GFP_KERNEL); + nm = kmalloc_obj(*nm); if (!nm) { printk(KERN_ERR "Unable to allocate netdev_mapping"); return -ENOMEM; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 504c4e0c5d17..22fbb0222f07 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -402,7 +402,8 @@ static irqreturn_t fdomain_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status fdomain_queue(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = fdomain_scsi_pointer(cmd); struct fdomain *fd = shost_priv(cmd->device->host); @@ -469,10 +470,10 @@ static int fdomain_host_reset(struct scsi_cmnd *cmd) } static int fdomain_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, + struct gendisk *disk, sector_t capacity, int geom[]) { - unsigned char *p = scsi_bios_ptable(bdev); + unsigned char *p = scsi_bios_ptable(disk); if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ && p[4]) { /* Partition type */ diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c index 11211c469583..554dea767885 100644 --- a/drivers/scsi/fnic/fdls_disc.c +++ b/drivers/scsi/fnic/fdls_disc.c @@ -272,7 +272,7 @@ void fdls_schedule_oxid_free(struct fnic_iport_s *iport, uint16_t *active_oxid) *active_oxid = FNIC_UNASSIGNED_OXID; reclaim_entry = (struct reclaim_entry_s *) - kzalloc(sizeof(struct reclaim_entry_s), GFP_ATOMIC); + kzalloc_obj(struct reclaim_entry_s, GFP_ATOMIC); if (!reclaim_entry) { FNIC_FCS_DBG(KERN_WARNING, fnic->host, fnic->fnic_num, @@ -308,43 +308,29 @@ void fdls_schedule_oxid_free_retry_work(struct work_struct *work) struct fnic *fnic = iport->fnic; struct reclaim_entry_s *reclaim_entry; unsigned long delay_j = msecs_to_jiffies(OXID_RECLAIM_TOV(iport)); + unsigned long flags; int idx; - spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); - for_each_set_bit(idx, oxid_pool->pending_schedule_free, FNIC_OXID_POOL_SZ) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Schedule oxid free. oxid idx: %d\n", idx); - spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - reclaim_entry = (struct reclaim_entry_s *) - kzalloc(sizeof(struct reclaim_entry_s), GFP_KERNEL); - spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); - + reclaim_entry = kzalloc_obj(*reclaim_entry); if (!reclaim_entry) { - FNIC_FCS_DBG(KERN_WARNING, fnic->host, fnic->fnic_num, - "Failed to allocate memory for reclaim struct for oxid idx: 0x%x\n", - idx); - schedule_delayed_work(&oxid_pool->schedule_oxid_free_retry, msecs_to_jiffies(SCHEDULE_OXID_FREE_RETRY_TIME)); - spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); return; } - if (test_and_clear_bit(idx, oxid_pool->pending_schedule_free)) { - reclaim_entry->oxid_idx = idx; - reclaim_entry->expires = round_jiffies(jiffies + delay_j); - list_add_tail(&reclaim_entry->links, &oxid_pool->oxid_reclaim_list); - schedule_delayed_work(&oxid_pool->oxid_reclaim_work, delay_j); - } else { - /* unlikely scenario, free the allocated memory and continue */ - kfree(reclaim_entry); - } -} - - spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); + clear_bit(idx, oxid_pool->pending_schedule_free); + reclaim_entry->oxid_idx = idx; + reclaim_entry->expires = round_jiffies(jiffies + delay_j); + spin_lock_irqsave(&fnic->fnic_lock, flags); + list_add_tail(&reclaim_entry->links, &oxid_pool->oxid_reclaim_list); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + schedule_delayed_work(&oxid_pool->oxid_reclaim_work, delay_j); + } } static bool fdls_is_oxid_fabric_req(uint16_t oxid) @@ -408,7 +394,7 @@ void fnic_del_fabric_timer_sync(struct fnic *fnic) { fnic->iport.fabric.del_timer_inprogress = 1; spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - del_timer_sync(&fnic->iport.fabric.retry_timer); + timer_delete_sync(&fnic->iport.fabric.retry_timer); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); fnic->iport.fabric.del_timer_inprogress = 0; } @@ -418,7 +404,7 @@ void fnic_del_tport_timer_sync(struct fnic *fnic, { tport->del_timer_inprogress = 1; spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - del_timer_sync(&tport->retry_timer); + timer_delete_sync(&tport->retry_timer); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); tport->del_timer_inprogress = 0; } @@ -777,50 +763,86 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) iport->fabric.timer_pending = 1; } -static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) +static uint8_t *fdls_alloc_init_fdmi_abts_frame(struct fnic_iport_s *iport, + uint16_t oxid) { - uint8_t *frame; + struct fc_frame_header *pfdmi_abts; uint8_t d_id[3]; + uint8_t *frame; struct fnic *fnic = iport->fnic; - struct fc_frame_header *pfabric_abts; - unsigned long fdmi_tov; - uint16_t oxid; - uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET + - sizeof(struct fc_frame_header); frame = fdls_alloc_frame(iport); if (frame == NULL) { FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, "Failed to allocate frame to send FDMI ABTS"); - return; + return NULL; } - pfabric_abts = (struct fc_frame_header *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET); + pfdmi_abts = (struct fc_frame_header *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET); fdls_init_fabric_abts_frame(frame, iport); hton24(d_id, FC_FID_MGMT_SERV); - FNIC_STD_SET_D_ID(*pfabric_abts, d_id); + FNIC_STD_SET_D_ID(*pfdmi_abts, d_id); + FNIC_STD_SET_OX_ID(*pfdmi_abts, oxid); + + return frame; +} + +static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) +{ + uint8_t *frame; + struct fnic *fnic = iport->fnic; + unsigned long fdmi_tov; + uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET + + sizeof(struct fc_frame_header); if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { - oxid = iport->active_oxid_fdmi_plogi; - FNIC_STD_SET_OX_ID(*pfabric_abts, oxid); + frame = fdls_alloc_init_fdmi_abts_frame(iport, + iport->active_oxid_fdmi_plogi); + if (frame == NULL) + return; + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: FDLS send FDMI PLOGI abts. iport->fabric.state: %d oxid: 0x%x", + iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_plogi); fnic_send_fcoe_frame(iport, frame, frame_size); } else { if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { - oxid = iport->active_oxid_fdmi_rhba; - FNIC_STD_SET_OX_ID(*pfabric_abts, oxid); + frame = fdls_alloc_init_fdmi_abts_frame(iport, + iport->active_oxid_fdmi_rhba); + if (frame == NULL) + return; + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: FDLS send FDMI RHBA abts. iport->fabric.state: %d oxid: 0x%x", + iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_rhba); fnic_send_fcoe_frame(iport, frame, frame_size); } if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { - oxid = iport->active_oxid_fdmi_rpa; - FNIC_STD_SET_OX_ID(*pfabric_abts, oxid); + frame = fdls_alloc_init_fdmi_abts_frame(iport, + iport->active_oxid_fdmi_rpa); + if (frame == NULL) { + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) + goto arm_timer; + else + return; + } + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: FDLS send FDMI RPA abts. iport->fabric.state: %d oxid: 0x%x", + iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_rpa); fnic_send_fcoe_frame(iport, frame, frame_size); } } +arm_timer: fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING; + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); } static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) @@ -1248,7 +1270,7 @@ bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) if (tport->flags & FNIC_FDLS_SCSI_REGISTERED) { tport_del_evt = - kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); + kzalloc_obj(struct fnic_tport_event_s, GFP_ATOMIC); if (!tport_del_evt) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for tport fcid: 0x%0x\n", @@ -1567,9 +1589,9 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "0x%x: FDLS send fabric LOGO with oxid: 0x%x", - iport->fcid, oxid); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: FDLS send fabric LOGO with oxid: 0x%x", + iport->fcid, oxid); fnic_send_fcoe_frame(iport, frame, frame_size); @@ -1754,7 +1776,7 @@ static struct fnic_tport_s *fdls_create_tport(struct fnic_iport_s *iport, FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "FDLS create tport: fcid: 0x%x wwpn: 0x%llx", fcid, wwpn); - tport = kzalloc(sizeof(struct fnic_tport_s), GFP_ATOMIC); + tport = kzalloc_obj(struct fnic_tport_s, GFP_ATOMIC); if (!tport) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Memory allocation failure while creating tport: 0x%x\n", @@ -1898,7 +1920,6 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) if (fnic->subsys_desc_len >= FNIC_FDMI_MODEL_LEN) fnic->subsys_desc_len = FNIC_FDMI_MODEL_LEN - 1; strscpy_pad(data, fnic->subsys_desc, FNIC_FDMI_MODEL_LEN); - data[FNIC_FDMI_MODEL_LEN - 1] = 0; fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_MODEL, FNIC_FDMI_MODEL_LEN, data, &attr_off_bytes); @@ -2061,7 +2082,6 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) snprintf(tmp_data, FNIC_FDMI_OS_NAME_LEN - 1, "host%d", fnic->host->host_no); strscpy_pad(data, tmp_data, FNIC_FDMI_OS_NAME_LEN); - data[FNIC_FDMI_OS_NAME_LEN - 1] = 0; fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_OS_NAME, FNIC_FDMI_OS_NAME_LEN, data, &attr_off_bytes); @@ -2071,7 +2091,6 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) sprintf(fc_host_system_hostname(fnic->host), "%s", utsname()->nodename); strscpy_pad(data, fc_host_system_hostname(fnic->host), FNIC_FDMI_HN_LEN); - data[FNIC_FDMI_HN_LEN - 1] = 0; fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_HOST_NAME, FNIC_FDMI_HN_LEN, data, &attr_off_bytes); @@ -2091,7 +2110,8 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) void fdls_fabric_timer_callback(struct timer_list *t) { - struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, retry_timer); + struct fnic_fdls_fabric_s *fabric = timer_container_of(fabric, t, + retry_timer); struct fnic_iport_s *iport = container_of(fabric, struct fnic_iport_s, fabric); struct fnic *fnic = iport->fnic; @@ -2261,9 +2281,25 @@ void fdls_fabric_timer_callback(struct timer_list *t) spin_unlock_irqrestore(&fnic->fnic_lock, flags); } +void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport) +{ + struct fnic *fnic = iport->fnic; + + iport->fabric.fdmi_pending = 0; + /* If max retries not exhausted, start over from fdmi plogi */ + if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { + iport->fabric.fdmi_retry++; + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Retry FDMI PLOGI. FDMI retry: %d", + iport->fabric.fdmi_retry); + fdls_send_fdmi_plogi(iport); + } +} + void fdls_fdmi_timer_callback(struct timer_list *t) { - struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, fdmi_timer); + struct fnic_fdls_fabric_s *fabric = timer_container_of(fabric, t, + fdmi_timer); struct fnic_iport_s *iport = container_of(fabric, struct fnic_iport_s, fabric); struct fnic *fnic = iport->fnic; @@ -2272,7 +2308,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t) spin_lock_irqsave(&fnic->fnic_lock, flags); FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending); + "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); if (!iport->fabric.fdmi_pending) { /* timer expired after fdmi responses received. */ @@ -2280,7 +2316,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t) return; } FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending); + "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); /* if not abort pending, send an abort */ if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) { @@ -2289,33 +2325,37 @@ void fdls_fdmi_timer_callback(struct timer_list *t) return; } FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending); + "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); /* ABTS pending for an active fdmi request that is pending. * That means FDMI ABTS timed out * Schedule to free the OXID after 2*r_a_tov and proceed */ if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "FDMI PLOGI ABTS timed out. Schedule oxid free: 0x%x\n", + iport->active_oxid_fdmi_plogi); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_plogi); } else { - if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "FDMI RHBA ABTS timed out. Schedule oxid free: 0x%x\n", + iport->active_oxid_fdmi_rhba); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_rhba); - if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) + } + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "FDMI RPA ABTS timed out. Schedule oxid free: 0x%x\n", + iport->active_oxid_fdmi_rpa); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_rpa); + } } FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending); + "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); - iport->fabric.fdmi_pending = 0; - /* If max retries not exhaused, start over from fdmi plogi */ - if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { - iport->fabric.fdmi_retry++; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "retry fdmi timer %d", iport->fabric.fdmi_retry); - fdls_send_fdmi_plogi(iport); - } + fdls_fdmi_retry_plogi(iport); FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending); + "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); spin_unlock_irqrestore(&fnic->fnic_lock, flags); } @@ -2325,7 +2365,7 @@ static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) struct fnic *fnic = iport->fnic; struct fnic_tport_event_s *tport_del_evt; - tport_del_evt = kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); + tport_del_evt = kzalloc_obj(struct fnic_tport_event_s, GFP_ATOMIC); if (!tport_del_evt) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for tport event fcid: 0x%x", @@ -2340,7 +2380,7 @@ static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) static void fdls_tport_timer_callback(struct timer_list *t) { - struct fnic_tport_s *tport = from_timer(tport, t, retry_timer); + struct fnic_tport_s *tport = timer_container_of(tport, t, retry_timer); struct fnic_iport_s *iport = (struct fnic_iport_s *) tport->iport; struct fnic *fnic = iport->fnic; uint16_t oxid; @@ -2812,7 +2852,7 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, fdls_set_tport_state(tport, FDLS_TGT_STATE_READY); /* Inform the driver about new target added */ - tport_add_evt = kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); + tport_add_evt = kzalloc_obj(struct fnic_tport_event_s, GFP_ATOMIC); if (!tport_add_evt) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "tport event memory allocation failure: 0x%0x\n", @@ -3634,7 +3674,7 @@ static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_plogi); if (ntoh24(fchdr->fh_s_id) == FC_FID_MGMT_SERV) { - del_timer_sync(&iport->fabric.fdmi_timer); + timer_delete_sync(&iport->fabric.fdmi_timer); iport->fabric.fdmi_pending = 0; switch (plogi_rsp->els.fl_cmd) { case ELS_LS_ACC: @@ -3703,7 +3743,7 @@ static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, iport->fcid); if (!iport->fabric.fdmi_pending) { - del_timer_sync(&iport->fabric.fdmi_timer); + timer_delete_sync(&iport->fabric.fdmi_timer); FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "iport fcid: 0x%x: Canceling FDMI timer\n", iport->fcid); @@ -3730,13 +3770,60 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, switch (FNIC_FRAME_TYPE(oxid)) { case FNIC_FRAME_TYPE_FDMI_PLOGI: + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Received FDMI PLOGI ABTS rsp with oxid: 0x%x", oxid); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_plogi); + + iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING; + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); break; case FNIC_FRAME_TYPE_FDMI_RHBA: + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Received FDMI RHBA ABTS rsp with oxid: 0x%x", oxid); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); + + iport->fabric.fdmi_pending &= ~FDLS_FDMI_REG_HBA_PENDING; + + /* If RPA is still pending, don't turn off ABORT PENDING. + * We count on the timer to detect the ABTS timeout and take + * corrective action. + */ + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING)) + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; + fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rhba); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); break; case FNIC_FRAME_TYPE_FDMI_RPA: + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Received FDMI RPA ABTS rsp with oxid: 0x%x", oxid); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); + + iport->fabric.fdmi_pending &= ~FDLS_FDMI_RPA_PENDING; + + /* If RHBA is still pending, don't turn off ABORT PENDING. + * We count on the timer to detect the ABTS timeout and take + * corrective action. + */ + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING)) + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; + fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rpa); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "0x%x: iport->fabric.fdmi_pending: 0x%x", + iport->fcid, iport->fabric.fdmi_pending); break; default: FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, @@ -3745,10 +3832,16 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, break; } - del_timer_sync(&iport->fabric.fdmi_timer); - iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; - - fdls_send_fdmi_plogi(iport); + /* + * Only if ABORT PENDING is off, delete the timer, and if no other + * operations are pending, retry FDMI. + * Otherwise, let the timer pop and take the appropriate action. + */ + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) { + timer_delete_sync(&iport->fabric.fdmi_timer); + if (!iport->fabric.fdmi_pending) + fdls_fdmi_retry_plogi(iport); + } } static void @@ -4520,7 +4613,7 @@ void fnic_fdls_disc_start(struct fnic_iport_s *iport) if (!iport->usefip) { if (iport->flags & FNIC_FIRST_LINK_UP) { spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); iport->flags &= ~FNIC_FIRST_LINK_UP; @@ -4659,13 +4752,13 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, d_id = ntoh24(fchdr->fh_d_id); /* some common validation */ - if (fdls_get_state(fabric) > FDLS_STATE_FABRIC_FLOGI) { - if ((iport->fcid != d_id) || (!FNIC_FC_FRAME_CS_CTL(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "invalid frame received. Dropping frame"); - return -1; - } + if (fdls_get_state(fabric) > FDLS_STATE_FABRIC_FLOGI) { + if (iport->fcid != d_id || (!FNIC_FC_FRAME_CS_CTL(fchdr))) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "invalid frame received. Dropping frame"); + return -1; } + } /* BLS ABTS response */ if ((fchdr->fh_r_ctl == FC_RCTL_BA_ACC) @@ -4682,7 +4775,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, "Received unexpected ABTS RSP(oxid:0x%x) from 0x%x. Dropping frame", oxid, s_id); return -1; - } + } return FNIC_FABRIC_BLS_ABTS_RSP; } else if (fdls_is_oxid_fdmi_req(oxid)) { return FNIC_FDMI_BLS_ABTS_RSP; @@ -4979,7 +5072,7 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport) iport->fabric.flags = 0; spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); list_for_each_entry_safe(tport, next, &iport->tport_list, links) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, @@ -4987,9 +5080,12 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport) fdls_delete_tport(iport, tport); } - if ((fnic_fdmi_support == 1) && (iport->fabric.fdmi_pending > 0)) { - del_timer_sync(&iport->fabric.fdmi_timer); - iport->fabric.fdmi_pending = 0; + if (fnic_fdmi_support == 1) { + if (iport->fabric.fdmi_pending > 0) { + timer_delete_sync(&iport->fabric.fdmi_timer); + iport->fabric.fdmi_pending = 0; + } + iport->flags &= ~FNIC_FDMI_ACTIVE; } FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, diff --git a/drivers/scsi/fnic/fip.c b/drivers/scsi/fnic/fip.c index 7bb85949033f..132f00512ee1 100644 --- a/drivers/scsi/fnic/fip.c +++ b/drivers/scsi/fnic/fip.c @@ -139,7 +139,7 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph) FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "process_vlan_resp: FIP VLAN %d\n", vid); - vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); + vlan = kzalloc_obj(*vlan); if (!vlan) { /* retry from timer */ @@ -200,7 +200,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic) return; } - memset(iport->selected_fcf.fcf_mac, 0, ETH_ALEN); + eth_zero_addr(iport->selected_fcf.fcf_mac); pdisc_sol = (struct fip_discovery *) frame; *pdisc_sol = (struct fip_discovery) { @@ -319,7 +319,7 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph) round_jiffies(fcs_ka_tov)); } else { if (timer_pending(&fnic->fcs_ka_timer)) - del_timer_sync(&fnic->fcs_ka_timer); + timer_delete_sync(&fnic->fcs_ka_timer); } if (fka_has_changed) { @@ -497,7 +497,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) oxid = FNIC_STD_GET_OX_ID(fchdr); fdls_free_oxid(iport, oxid, &iport->active_oxid_fabric_req); - del_timer_sync(&fnic->retry_fip_timer); + timer_delete_sync(&fnic->retry_fip_timer); if ((be16_to_cpu(flogi_rsp->fip.fip_dl_len) == FIP_FLOGI_LEN) && (flogi_rsp->rsp_desc.flogi.els.fl_cmd == ELS_LS_ACC)) { @@ -580,20 +580,20 @@ void fnic_common_fip_cleanup(struct fnic *fnic) iport->fip.state = FDLS_FIP_INIT; - del_timer_sync(&fnic->retry_fip_timer); - del_timer_sync(&fnic->fcs_ka_timer); - del_timer_sync(&fnic->enode_ka_timer); - del_timer_sync(&fnic->vn_ka_timer); + timer_delete_sync(&fnic->retry_fip_timer); + timer_delete_sync(&fnic->fcs_ka_timer); + timer_delete_sync(&fnic->enode_ka_timer); + timer_delete_sync(&fnic->vn_ka_timer); if (!is_zero_ether_addr(iport->fpma)) vnic_dev_del_addr(fnic->vdev, iport->fpma); - memset(iport->fpma, 0, ETH_ALEN); + eth_zero_addr(iport->fpma); iport->fcid = 0; iport->r_a_tov = 0; iport->e_d_tov = 0; - memset(fnic->iport.fcfmac, 0, ETH_ALEN); - memset(iport->selected_fcf.fcf_mac, 0, ETH_ALEN); + eth_zero_addr(fnic->iport.fcfmac); + eth_zero_addr(iport->selected_fcf.fcf_mac); iport->selected_fcf.fcf_priority = 0; iport->selected_fcf.fka_adv_period = 0; iport->selected_fcf.ka_disabled = 0; @@ -737,7 +737,7 @@ void fnic_work_on_fip_timer(struct work_struct *work) if (memcmp(iport->selected_fcf.fcf_mac, zmac, ETH_ALEN) != 0) { if (iport->flags & FNIC_FIRST_LINK_UP) { - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); iport->flags &= ~FNIC_FIRST_LINK_UP; } @@ -777,7 +777,7 @@ void fnic_work_on_fip_timer(struct work_struct *work) */ void fnic_handle_fip_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, retry_fip_timer); + struct fnic *fnic = timer_container_of(fnic, t, retry_fip_timer); INIT_WORK(&fnic->fip_timer_work, fnic_work_on_fip_timer); queue_work(fnic_fip_queue, &fnic->fip_timer_work); @@ -790,7 +790,7 @@ void fnic_handle_fip_timer(struct timer_list *t) void fnic_handle_enode_ka_timer(struct timer_list *t) { uint8_t *frame; - struct fnic *fnic = from_timer(fnic, t, enode_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, enode_ka_timer); struct fnic_iport_s *iport = &fnic->iport; struct fip_enode_ka *penode_ka; @@ -843,7 +843,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t) void fnic_handle_vn_ka_timer(struct timer_list *t) { uint8_t *frame; - struct fnic *fnic = from_timer(fnic, t, vn_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, vn_ka_timer); struct fnic_iport_s *iport = &fnic->iport; struct fip_vn_port_ka *pvn_port_ka; @@ -998,7 +998,7 @@ void fnic_work_on_fcs_ka_timer(struct work_struct *work) */ void fnic_handle_fcs_ka_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, fcs_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, fcs_ka_timer); INIT_WORK(&fnic->fip_timer_work, fnic_work_on_fcs_ka_timer); queue_work(fnic_fip_queue, &fnic->fip_timer_work); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 6c5f6046b1f5..8724d64f2525 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -30,7 +30,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.8.0.0" +#define DRV_VERSION "1.8.0.3" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " @@ -323,8 +323,6 @@ enum fnic_state { FNIC_IN_ETH_TRANS_FC_MODE, }; -struct mempool; - enum fnic_role_e { FNIC_ROLE_FCP_INITIATOR = 0, }; @@ -440,6 +438,7 @@ struct fnic { struct list_head tx_queue; mempool_t *frame_pool; mempool_t *frame_elem_pool; + mempool_t *frame_recv_pool; struct work_struct tport_work; struct list_head tport_event_list; @@ -505,7 +504,8 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); void fnic_flush_tx(struct work_struct *work); void fnic_update_mac_locked(struct fnic *, u8 *new); -int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int fnic_abort_cmd(struct scsi_cmnd *); int fnic_device_reset(struct scsi_cmnd *); int fnic_eh_host_reset_handler(struct scsi_cmnd *sc); @@ -513,7 +513,6 @@ int fnic_host_reset(struct Scsi_Host *shost); void fnic_reset(struct Scsi_Host *shost); int fnic_issue_fc_host_lip(struct Scsi_Host *shost); void fnic_get_host_port_state(struct Scsi_Host *shost); -void fnic_scsi_fcpio_reset(struct fnic *fnic); int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index); int fnic_wq_cmpl_handler(struct fnic *fnic, int); int fnic_flogi_reg_handler(struct fnic *fnic, u32); @@ -542,7 +541,8 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) } void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long); void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *); -void fnic_free_txq(struct list_head *head); +void fnic_free_txq(struct fnic *fnic); +void fnic_free_rxq(struct fnic *fnic); int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, char **subsys_desc); void fnic_fdls_link_status_change(struct fnic *fnic, int linkup); diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index 5767862ae42f..ba86964fb45e 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -200,7 +200,7 @@ static int fnic_trace_debugfs_open(struct inode *inode, fnic_dbgfs_t *fnic_dbg_prt; u8 *rdata_ptr; rdata_ptr = (u8 *)inode->i_private; - fnic_dbg_prt = kzalloc(sizeof(fnic_dbgfs_t), GFP_KERNEL); + fnic_dbg_prt = kzalloc_obj(fnic_dbgfs_t); if (!fnic_dbg_prt) return -ENOMEM; @@ -436,7 +436,7 @@ static int fnic_reset_stats_open(struct inode *inode, struct file *file) { struct stats_debug_info *debug; - debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL); + debug = kzalloc_obj(struct stats_debug_info); if (!debug) return -ENOMEM; @@ -583,7 +583,7 @@ static int fnic_stats_debugfs_open(struct inode *inode, struct stats_debug_info *debug; int buf_size = 2 * PAGE_SIZE; - debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL); + debug = kzalloc_obj(struct stats_debug_info); if (!debug) return -ENOMEM; diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 1e8cd64f9a5c..063eb864a5cd 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -291,7 +291,7 @@ void fnic_handle_frame(struct work_struct *work) if (fnic->stop_rx_link_events) { list_del(&cur_frame->links); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - kfree(cur_frame->fp); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); mempool_free(cur_frame, fnic->frame_elem_pool); return; } @@ -317,7 +317,7 @@ void fnic_handle_frame(struct work_struct *work) fnic_fdls_recv_frame(&fnic->iport, cur_frame->fp, cur_frame->frame_len, fchdr_offset); - kfree(cur_frame->fp); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); mempool_free(cur_frame, fnic->frame_elem_pool); } spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); @@ -337,8 +337,8 @@ void fnic_handle_fip_frame(struct work_struct *work) if (fnic->stop_rx_link_events) { list_del(&cur_frame->links); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); return; } @@ -355,8 +355,8 @@ void fnic_handle_fip_frame(struct work_struct *work) list_del(&cur_frame->links); if (fdls_fip_recv_frame(fnic, cur_frame->fp)) { - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); } } spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); @@ -375,10 +375,10 @@ static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, void *fp) eh = (struct ethhdr *) fp; if ((eh->h_proto == cpu_to_be16(ETH_P_FIP)) && (fnic->iport.usefip)) { - fip_fr_elem = (struct fnic_frame_list *) - kzalloc(sizeof(struct fnic_frame_list), GFP_ATOMIC); + fip_fr_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!fip_fr_elem) return 0; + memset(fip_fr_elem, 0, sizeof(struct fnic_frame_list)); fip_fr_elem->fp = fp; spin_lock_irqsave(&fnic->fnic_lock, flags); list_add_tail(&fip_fr_elem->links, &fnic->fip_frame_queue); @@ -519,13 +519,13 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc spin_unlock_irqrestore(&fnic->fnic_lock, flags); - frame_elem = mempool_alloc(fnic->frame_elem_pool, - GFP_ATOMIC | __GFP_ZERO); + frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!frame_elem) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for frame elem"); goto drop; } + memset(frame_elem, 0, sizeof(struct fnic_frame_list)); frame_elem->fp = fp; frame_elem->rx_ethhdr_stripped = ethhdr_stripped; frame_elem->frame_len = bytes_written; @@ -538,7 +538,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc return; drop: - kfree(fp); + mempool_free(fp, fnic->frame_recv_pool); } static int fnic_rq_cmpl_handler_cont(struct vnic_dev *vdev, @@ -591,7 +591,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) int ret; len = FNIC_FRAME_HT_ROOM; - buf = kmalloc(len, GFP_ATOMIC); + buf = mempool_alloc(fnic->frame_recv_pool, GFP_ATOMIC); if (!buf) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Unable to allocate RQ buffer of size: %d\n", len); @@ -609,7 +609,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) fnic_queue_rq_desc(rq, buf, pa, len); return 0; free_buf: - kfree(buf); + mempool_free(buf, fnic->frame_recv_pool); return ret; } @@ -621,7 +621,7 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, DMA_FROM_DEVICE); - kfree(rq_buf); + mempool_free(rq_buf, fnic->frame_recv_pool); buf->os_buf = NULL; } @@ -636,6 +636,8 @@ static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len) unsigned long flags; pa = dma_map_single(&fnic->pdev->dev, frame, frame_len, DMA_TO_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, pa)) + return -ENOMEM; if ((fnic_fc_trace_set_data(fnic->fnic_num, FNIC_FC_SEND | 0x80, (char *) frame, @@ -702,13 +704,13 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size, */ if ((fnic->state != FNIC_IN_FC_MODE) && (fnic->state != FNIC_IN_ETH_MODE)) { - frame_elem = mempool_alloc(fnic->frame_elem_pool, - GFP_ATOMIC | __GFP_ZERO); + frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!frame_elem) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for frame elem"); return -ENOMEM; } + memset(frame_elem, 0, sizeof(struct fnic_frame_list)); FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "Queueing FC frame: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x\n", @@ -834,14 +836,34 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, return 0; } -void fnic_free_txq(struct list_head *head) +void fnic_free_txq(struct fnic *fnic) +{ + struct fnic_frame_list *cur_frame, *next; + + list_for_each_entry_safe(cur_frame, next, &fnic->tx_queue, links) { + list_del(&cur_frame->links); + mempool_free(cur_frame->fp, fnic->frame_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } +} + +void fnic_free_rxq(struct fnic *fnic) { struct fnic_frame_list *cur_frame, *next; - list_for_each_entry_safe(cur_frame, next, head, links) { + list_for_each_entry_safe(cur_frame, next, &fnic->frame_queue, links) { list_del(&cur_frame->links); - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } + + if (fnic->config.flags & VFCF_FIP_CAPABLE) { + list_for_each_entry_safe(cur_frame, next, + &fnic->fip_frame_queue, links) { + list_del(&cur_frame->links); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } } } @@ -896,7 +918,7 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, DMA_TO_DEVICE); - kfree(buf->os_buf); + mempool_free(buf->os_buf, fnic->frame_pool); buf->os_buf = NULL; } @@ -1106,3 +1128,53 @@ void fnic_reset_work_handler(struct work_struct *work) spin_unlock_irqrestore(&reset_fnic_list_lock, reset_fnic_list_lock_flags); } + +void fnic_fcpio_reset(struct fnic *fnic) +{ + unsigned long flags; + enum fnic_state old_state; + struct fnic_iport_s *iport = &fnic->iport; + DECLARE_COMPLETION_ONSTACK(fw_reset_done); + int time_remain; + + /* issue fw reset */ + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { + /* fw reset is in progress, poll for its completion */ + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "fnic is in unexpected state: %d for fw_reset\n", + fnic->state); + return; + } + + old_state = fnic->state; + fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; + + fnic_update_mac_locked(fnic, iport->hwmac); + fnic->fw_reset_done = &fw_reset_done; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Issuing fw reset\n"); + if (fnic_fw_reset_handler(fnic)) { + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) + fnic->state = old_state; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + } else { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Waiting for fw completion\n"); + time_remain = wait_for_completion_timeout(&fw_reset_done, + msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Woken up after fw completion timeout\n"); + if (time_remain == 0) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "FW reset completion timed out after %d ms\n", + FNIC_FW_RESET_TIMEOUT); + } + atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); + } + fnic->fw_reset_done = NULL; +} diff --git a/drivers/scsi/fnic/fnic_fdls.h b/drivers/scsi/fnic/fnic_fdls.h index 8e610b65ad57..e2959120c4f9 100644 --- a/drivers/scsi/fnic/fnic_fdls.h +++ b/drivers/scsi/fnic/fnic_fdls.h @@ -394,6 +394,7 @@ void fdls_send_tport_abts(struct fnic_iport_s *iport, bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport); void fdls_fdmi_timer_callback(struct timer_list *t); +void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport); /* fnic_fcs.c */ void fnic_fdls_init(struct fnic *fnic, int usefip); @@ -409,6 +410,7 @@ void fnic_fdls_add_tport(struct fnic_iport_s *iport, void fnic_fdls_remove_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport, unsigned long flags); +void fnic_fcpio_reset(struct fnic *fnic); /* fip.c */ void fnic_fcoe_send_vlan_req(struct fnic *fnic); @@ -421,7 +423,6 @@ void fnic_handle_fip_timer(struct timer_list *t); extern void fdls_fabric_timer_callback(struct timer_list *t); /* fnic_scsi.c */ -void fnic_scsi_fcpio_reset(struct fnic *fnic); extern void fdls_fabric_timer_callback(struct timer_list *t); void fnic_rport_exch_reset(struct fnic *fnic, u32 fcid); int fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 0b20ac8c3f46..24d62c0874ac 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -40,6 +40,7 @@ static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; static struct kmem_cache *fnic_io_req_cache; static struct kmem_cache *fdls_frame_cache; static struct kmem_cache *fdls_frame_elem_cache; +static struct kmem_cache *fdls_frame_recv_cache; static LIST_HEAD(fnic_list); static DEFINE_SPINLOCK(fnic_list_lock); static DEFINE_IDA(fnic_ida); @@ -446,7 +447,7 @@ static int fnic_notify_set(struct fnic *fnic) static void fnic_notify_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, notify_timer); + struct fnic *fnic = timer_container_of(fnic, t, notify_timer); fnic_handle_link_event(fnic); mod_timer(&fnic->notify_timer, @@ -554,6 +555,7 @@ static int fnic_cleanup(struct fnic *fnic) mempool_destroy(fnic->io_req_pool); mempool_destroy(fnic->frame_pool); mempool_destroy(fnic->frame_elem_pool); + mempool_destroy(fnic->frame_recv_pool); for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) mempool_destroy(fnic->io_sgl_pool[i]); @@ -715,7 +717,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* * Allocate fnic */ - fnic = kzalloc(sizeof(struct fnic), GFP_KERNEL); + fnic = kzalloc_obj(struct fnic); if (!fnic) { err = -ENOMEM; goto err_out_fnic_alloc; @@ -928,6 +930,14 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } fnic->frame_elem_pool = pool; + pool = mempool_create_slab_pool(FDLS_MIN_FRAMES, + fdls_frame_recv_cache); + if (!pool) { + err = -ENOMEM; + goto err_out_fdls_frame_recv_pool; + } + fnic->frame_recv_pool = pool; + /* setup vlan config, hw inserts vlan header */ fnic->vlan_hw_insert = 1; fnic->vlan_id = 0; @@ -1085,6 +1095,8 @@ err_out_alloc_rq_buf: } vnic_dev_notify_unset(fnic->vdev); err_out_fnic_notify_set: + mempool_destroy(fnic->frame_recv_pool); +err_out_fdls_frame_recv_pool: mempool_destroy(fnic->frame_elem_pool); err_out_fdls_frame_elem_pool: mempool_destroy(fnic->frame_pool); @@ -1149,20 +1161,19 @@ static void fnic_remove(struct pci_dev *pdev) fnic_scsi_unload(fnic); if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) - del_timer_sync(&fnic->notify_timer); + timer_delete_sync(&fnic->notify_timer); if (fnic->config.flags & VFCF_FIP_CAPABLE) { - del_timer_sync(&fnic->retry_fip_timer); - del_timer_sync(&fnic->fcs_ka_timer); - del_timer_sync(&fnic->enode_ka_timer); - del_timer_sync(&fnic->vn_ka_timer); + timer_delete_sync(&fnic->retry_fip_timer); + timer_delete_sync(&fnic->fcs_ka_timer); + timer_delete_sync(&fnic->enode_ka_timer); + timer_delete_sync(&fnic->vn_ka_timer); - fnic_free_txq(&fnic->fip_frame_queue); fnic_fcoe_reset_vlans(fnic); } if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0)) - del_timer_sync(&fnic->iport.fabric.fdmi_timer); + timer_delete_sync(&fnic->iport.fabric.fdmi_timer); fnic_stats_debugfs_remove(fnic); @@ -1177,8 +1188,8 @@ static void fnic_remove(struct pci_dev *pdev) list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); - fnic_free_txq(&fnic->frame_queue); - fnic_free_txq(&fnic->tx_queue); + fnic_free_rxq(fnic); + fnic_free_txq(fnic); vnic_dev_notify_unset(fnic->vdev); fnic_free_intr(fnic); @@ -1287,6 +1298,15 @@ static int __init fnic_init_module(void) goto err_create_fdls_frame_cache_elem; } + fdls_frame_recv_cache = kmem_cache_create("fdls_frame_recv", + FNIC_FRAME_HT_ROOM, + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fdls_frame_recv_cache) { + pr_err("fnic fdls frame recv cach create failed\n"); + err = -ENOMEM; + goto err_create_fdls_frame_recv_cache; + } + fnic_event_queue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_event_wq"); if (!fnic_event_queue) { @@ -1339,6 +1359,8 @@ err_create_fip_workq: if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) destroy_workqueue(reset_fnic_work_queue); err_create_reset_fnic_workq: + kmem_cache_destroy(fdls_frame_recv_cache); +err_create_fdls_frame_recv_cache: destroy_workqueue(fnic_event_queue); err_create_fnic_workq: kmem_cache_destroy(fdls_frame_elem_cache); @@ -1365,10 +1387,9 @@ static void __exit fnic_cleanup_module(void) if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) destroy_workqueue(reset_fnic_work_queue); - if (fnic_fip_queue) { - flush_workqueue(fnic_fip_queue); + if (fnic_fip_queue) destroy_workqueue(fnic_fip_queue); - } + kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); kmem_cache_destroy(fnic_io_req_cache); diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c index 763475587b7f..9801e5fbb0dd 100644 --- a/drivers/scsi/fnic/fnic_res.c +++ b/drivers/scsi/fnic/fnic_res.c @@ -134,7 +134,6 @@ int fnic_get_vnic_config(struct fnic *fnic) c->luns_per_tgt)); c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); - c->intr_timer_type = c->intr_timer_type; /* for older firmware, GET_CONFIG will not return anything */ if (c->wq_copy_count == 0) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 7133b254cbe4..6ee3c559e129 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -454,7 +454,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, return 0; } -int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct request *const rq = scsi_cmd_to_rq(sc); uint32_t mqtag = 0; @@ -470,7 +471,6 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) int sg_count = 0; unsigned long flags = 0; unsigned long ptr; - int io_lock_acquired = 0; uint16_t hwq = 0; struct fnic_tport_s *tport = NULL; struct rport_dd_data_s *rdd_data; @@ -635,7 +635,6 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); /* initialize rest of io_req */ - io_lock_acquired = 1; io_req->port_id = rport->port_id; io_req->start_time = jiffies; fnic_priv(sc)->state = FNIC_IOREQ_CMD_PENDING; @@ -688,6 +687,9 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) /* REVISIT: Use per IO lock in the final code */ fnic_priv(sc)->flags |= FNIC_IO_ISSUED; } + + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + out: cmd_trace = ((u64)sc->cmnd[0] << 56 | (u64)sc->cmnd[7] << 40 | (u64)sc->cmnd[8] << 32 | (u64)sc->cmnd[2] << 24 | @@ -698,10 +700,6 @@ out: mqtag, sc, io_req, sg_count, cmd_trace, fnic_flags_and_state(sc)); - /* if only we issued IO, will we have the io lock */ - if (io_lock_acquired) - spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - atomic_dec(&fnic->in_flight); atomic_dec(&tport->in_flight); @@ -776,7 +774,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, */ if (ret) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fnic_free_txq(&fnic->tx_queue); + fnic_free_txq(fnic); goto reset_cmpl_handler_end; } @@ -1046,7 +1044,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) atomic64_inc(&fnic_stats->misc_stats.queue_fulls); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "xfer_len: %llu", xfer_len); break; @@ -1971,15 +1969,11 @@ void fnic_scsi_unload(struct fnic *fnic) */ spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->iport.state = FNIC_IPORT_STATE_LINK_WAIT; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - if (fdls_get_state(&fnic->iport.fabric) != FDLS_STATE_INIT) - fnic_scsi_fcpio_reset(fnic); - - spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); + fnic_fcpio_reset(fnic); + fnic_flush_tport_event_list(fnic); fnic_delete_fcp_tports(fnic); } @@ -3039,54 +3033,3 @@ int fnic_eh_host_reset_handler(struct scsi_cmnd *sc) ret = fnic_host_reset(shost); return ret; } - - -void fnic_scsi_fcpio_reset(struct fnic *fnic) -{ - unsigned long flags; - enum fnic_state old_state; - struct fnic_iport_s *iport = &fnic->iport; - DECLARE_COMPLETION_ONSTACK(fw_reset_done); - int time_remain; - - /* issue fw reset */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { - /* fw reset is in progress, poll for its completion */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fnic is in unexpected state: %d for fw_reset\n", - fnic->state); - return; - } - - old_state = fnic->state; - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - - fnic_update_mac_locked(fnic, iport->hwmac); - fnic->fw_reset_done = &fw_reset_done; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Issuing fw reset\n"); - if (fnic_fw_reset_handler(fnic)) { - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) - fnic->state = old_state; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } else { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Waiting for fw completion\n"); - time_remain = wait_for_completion_timeout(&fw_reset_done, - msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Woken up after fw completion timeout\n"); - if (time_remain == 0) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "FW reset completion timed out after %d ms)\n", - FNIC_FW_RESET_TIMEOUT); - } - atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); - } - fnic->fw_reset_done = NULL; -} diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index cdc6b12b1ec2..4ed57ea1f854 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -138,9 +138,8 @@ int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt) */ 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, - val.tv_nsec, str, tbp->host_no, tbp->tag, + "%ptSp %-50s %8x %8x %16llx %16llx %16llx %16llx %16llx\n", + &val, str, tbp->host_no, tbp->tag, tbp->data[0], tbp->data[1], tbp->data[2], tbp->data[3], tbp->data[4]); rd_idx++; @@ -180,9 +179,8 @@ int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt) */ 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, - val.tv_nsec, str, tbp->host_no, tbp->tag, + "%ptSp %-50s %8x %8x %16llx %16llx %16llx %16llx %16llx\n", + &val, str, tbp->host_no, tbp->tag, tbp->data[0], tbp->data[1], tbp->data[2], tbp->data[3], tbp->data[4]); rd_idx++; @@ -215,32 +213,29 @@ int fnic_get_stats_data(struct stats_debug_info *debug, { int len = 0; int buf_size = debug->buf_size; - struct timespec64 val1, val2; + struct timespec64 val, val1, val2; int i = 0; - ktime_get_real_ts64(&val1); + ktime_get_real_ts64(&val); len = scnprintf(debug->debug_buffer + len, buf_size - len, "------------------------------------------\n" "\t\tTime\n" "------------------------------------------\n"); + val1 = timespec64_sub(val, stats->stats_timestamps.last_reset_time); + val2 = timespec64_sub(val, stats->stats_timestamps.last_read_time); 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" - "delta since last reset: [%lld:%ld]\n" - "delta since last read: [%lld:%ld]\n", - (s64)val1.tv_sec, val1.tv_nsec, - (s64)stats->stats_timestamps.last_reset_time.tv_sec, - stats->stats_timestamps.last_reset_time.tv_nsec, - (s64)stats->stats_timestamps.last_read_time.tv_sec, - stats->stats_timestamps.last_read_time.tv_nsec, - (s64)timespec64_sub(val1, stats->stats_timestamps.last_reset_time).tv_sec, - timespec64_sub(val1, stats->stats_timestamps.last_reset_time).tv_nsec, - (s64)timespec64_sub(val1, stats->stats_timestamps.last_read_time).tv_sec, - timespec64_sub(val1, stats->stats_timestamps.last_read_time).tv_nsec); - - stats->stats_timestamps.last_read_time = val1; + "Current time : [%ptSp]\n" + "Last stats reset time: [%ptSp]\n" + "Last stats read time: [%ptSp]\n" + "delta since last reset: [%ptSp]\n" + "delta since last read: [%ptSp]\n", + &val, + &stats->stats_timestamps.last_reset_time, + &stats->stats_timestamps.last_read_time, + &val1, &val2); + + stats->stats_timestamps.last_read_time = val; len += scnprintf(debug->debug_buffer + len, buf_size - len, "------------------------------------------\n" @@ -416,8 +411,8 @@ int fnic_get_stats_data(struct stats_debug_info *debug, jiffies_to_timespec64(stats->misc_stats.last_ack_time, &val2); len += scnprintf(debug->debug_buffer + len, buf_size - len, - "Last ISR time: %llu (%8llu.%09lu)\n" - "Last ACK time: %llu (%8llu.%09lu)\n" + "Last ISR time: %llu (%ptSp)\n" + "Last ACK time: %llu (%ptSp)\n" "Max ISR jiffies: %llu\n" "Max ISR time (ms) (0 denotes < 1 ms): %llu\n" "Corr. work done: %llu\n" @@ -437,10 +432,8 @@ int fnic_get_stats_data(struct stats_debug_info *debug, "Number of rport not ready: %lld\n" "Number of receive frame errors: %lld\n" "Port speed (in Mbps): %lld\n", - (u64)stats->misc_stats.last_isr_time, - (s64)val1.tv_sec, val1.tv_nsec, - (u64)stats->misc_stats.last_ack_time, - (s64)val2.tv_sec, val2.tv_nsec, + (u64)stats->misc_stats.last_isr_time, &val1, + (u64)stats->misc_stats.last_ack_time, &val2, (u64)atomic64_read(&stats->misc_stats.max_isr_jiffies), (u64)atomic64_read(&stats->misc_stats.max_isr_time_ms), (u64)atomic64_read(&stats->misc_stats.corr_work_done), @@ -857,8 +850,8 @@ void copy_and_format_trace_data(struct fc_trace_hdr *tdata, len = *orig_len; len += scnprintf(fnic_dbgfs_prt->buffer + len, max_size - len, - "%ptTs.%09lu ns%8x %c%8x\t", - &tdata->time_stamp.tv_sec, tdata->time_stamp.tv_nsec, + "%ptSs ns%8x %c%8x\t", + &tdata->time_stamp, tdata->host_no, tdata->frame_type, tdata->frame_len); fc_trace = (char *)FC_TRACE_ADDRESS(tdata); diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index e0b173cc9d5f..991c86eb5aff 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -422,7 +422,7 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev) if (vdev->devcmd2) return 0; - vdev->devcmd2 = kzalloc(sizeof(*vdev->devcmd2), GFP_ATOMIC); + vdev->devcmd2 = kzalloc_obj(*vdev->devcmd2, GFP_ATOMIC); if (!vdev->devcmd2) return -ENOMEM; @@ -911,7 +911,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) { if (!vdev) { - vdev = kzalloc(sizeof(struct vnic_dev), GFP_KERNEL); + vdev = kzalloc_obj(struct vnic_dev); if (!vdev) return NULL; } diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 2d438d722d0b..1323ed8aa717 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -46,6 +46,13 @@ #define HISI_SAS_IOST_ITCT_CACHE_DW_SZ 10 #define HISI_SAS_FIFO_DATA_DW_SIZE 32 +#define HISI_SAS_REG_MEM_SIZE 4 +#define HISI_SAS_MAX_CDB_LEN 16 +#define HISI_SAS_BLK_QUEUE_DEPTH 64 + +#define BYTE_TO_DW 4 +#define BYTE_TO_DDW 8 + #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) @@ -92,6 +99,8 @@ #define HISI_SAS_WAIT_PHYUP_TIMEOUT (30 * HZ) #define HISI_SAS_CLEAR_ITCT_TIMEOUT (20 * HZ) +#define HISI_SAS_DELAY_FOR_PHY_DISABLE 100 +#define NAME_BUF_SIZE 256 struct hisi_hba; @@ -167,6 +176,8 @@ struct hisi_sas_debugfs_fifo { u32 rd_data[HISI_SAS_FIFO_DATA_DW_SIZE]; }; +#define FRAME_RCVD_BUF 32 +#define SAS_PHY_RESV_SIZE 2 struct hisi_sas_phy { struct work_struct works[HISI_PHYES_NUM]; struct hisi_hba *hisi_hba; @@ -178,10 +189,10 @@ struct hisi_sas_phy { spinlock_t lock; u64 port_id; /* from hw */ u64 frame_rcvd_size; - u8 frame_rcvd[32]; + u8 frame_rcvd[FRAME_RCVD_BUF]; u8 phy_attached; u8 in_reset; - u8 reserved[2]; + u8 reserved[SAS_PHY_RESV_SIZE]; u32 phy_type; u32 code_violation_err_count; enum sas_linkrate minimum_linkrate; @@ -348,7 +359,8 @@ struct hisi_sas_hw { const struct scsi_host_template *sht; }; -#define HISI_SAS_MAX_DEBUGFS_DUMP (50) +#define HISI_SAS_MAX_DEBUGFS_DUMP 50 +#define HISI_SAS_DEFAULT_DEBUGFS_DUMP 1 struct hisi_sas_debugfs_cq { struct hisi_sas_cq *cq; @@ -448,12 +460,12 @@ struct hisi_hba { dma_addr_t sata_breakpoint_dma; struct hisi_sas_slot *slot_info; unsigned long flags; - const struct hisi_sas_hw *hw; /* Low level hw interface */ + const struct hisi_sas_hw *hw; /* Low level hw interface */ unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; struct work_struct rst_work; u32 phy_state; - u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ - u32 intr_coal_count; /* Interrupt count to coalesce */ + u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ + u32 intr_coal_count; /* Interrupt count to coalesce */ int cq_nvecs; @@ -528,12 +540,13 @@ struct hisi_sas_cmd_hdr { __le64 dif_prd_table_addr; }; +#define ITCT_RESV_DDW 12 struct hisi_sas_itct { __le64 qw0; __le64 sas_addr; __le64 qw2; __le64 qw3; - __le64 qw4_15[12]; + __le64 qw4_15[ITCT_RESV_DDW]; }; struct hisi_sas_iost { @@ -543,22 +556,26 @@ struct hisi_sas_iost { __le64 qw3; }; +#define ERROR_RECORD_BUF_DW 4 struct hisi_sas_err_record { - u32 data[4]; + u32 data[ERROR_RECORD_BUF_DW]; }; +#define FIS_RESV_DW 3 struct hisi_sas_initial_fis { struct hisi_sas_err_record err_record; struct dev_to_host_fis fis; - u32 rsvd[3]; + u32 rsvd[FIS_RESV_DW]; }; +#define BREAKPOINT_DATA_SIZE 128 struct hisi_sas_breakpoint { - u8 data[128]; + u8 data[BREAKPOINT_DATA_SIZE]; }; +#define BREAKPOINT_TAG_NUM 32 struct hisi_sas_sata_breakpoint { - struct hisi_sas_breakpoint tag[32]; + struct hisi_sas_breakpoint tag[BREAKPOINT_TAG_NUM]; }; struct hisi_sas_sge { @@ -569,13 +586,15 @@ struct hisi_sas_sge { __le32 data_off; }; +#define SMP_CMD_TABLE_SIZE 44 struct hisi_sas_command_table_smp { - u8 bytes[44]; + u8 bytes[SMP_CMD_TABLE_SIZE]; }; +#define DUMMY_BUF_SIZE 12 struct hisi_sas_command_table_stp { struct host_to_dev_fis command_fis; - u8 dummy[12]; + u8 dummy[DUMMY_BUF_SIZE]; u8 atapi_cdb[ATAPI_CDB_LEN]; }; @@ -589,12 +608,13 @@ struct hisi_sas_sge_dif_page { struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT]; } __aligned(16); +#define PROT_BUF_SIZE 7 struct hisi_sas_command_table_ssp { struct ssp_frame_hdr hdr; union { struct { struct ssp_command_iu task; - u32 prot[7]; + u32 prot[PROT_BUF_SIZE]; }; struct ssp_tmf_iu ssp_task; struct xfer_rdy_iu xfer_rdy; @@ -608,9 +628,10 @@ union hisi_sas_command_table { struct hisi_sas_command_table_stp stp; } __aligned(16); +#define IU_BUF_SIZE 1024 struct hisi_sas_status_buffer { struct hisi_sas_err_record err; - u8 iu[1024]; + u8 iu[IU_BUF_SIZE]; } __aligned(16); struct hisi_sas_slot_buf_table { @@ -633,8 +654,7 @@ extern struct dentry *hisi_sas_debugfs_dir; extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba); extern int hisi_sas_alloc(struct hisi_hba *hisi_hba); extern void hisi_sas_free(struct hisi_hba *hisi_hba); -extern u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, - int direction); +extern u8 hisi_sas_get_ata_protocol(struct sas_task *task); extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index da4a2ed8ee86..944ce19ae2fc 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -7,6 +7,16 @@ #include "hisi_sas.h" #define DRV_NAME "hisi_sas" +#define LINK_RATE_BIT_MASK 2 +#define FIS_BUF_SIZE 20 +#define WAIT_CMD_COMPLETE_DELAY 100 +#define WAIT_CMD_COMPLETE_TMROUT 5000 +#define DELAY_FOR_LINK_READY 2000 +#define BLK_CNT_OPTIMIZE_MARK 64 +#define HZ_TO_MHZ 1000000 +#define DELAY_FOR_SOFTRESET_MAX 1000 +#define DELAY_FOR_SOFTRESET_MIN 900 + #define DEV_IS_GONE(dev) \ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) @@ -21,8 +31,32 @@ struct hisi_sas_internal_abort_data { bool rst_ha_timeout; /* reset the HA for timeout */ }; -u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) +static u8 hisi_sas_get_ata_protocol_from_tf(struct ata_queued_cmd *qc) +{ + if (!qc) + return HISI_SAS_SATA_PROTOCOL_PIO; + + switch (qc->tf.protocol) { + case ATA_PROT_NODATA: + return HISI_SAS_SATA_PROTOCOL_NONDATA; + case ATA_PROT_PIO: + return HISI_SAS_SATA_PROTOCOL_PIO; + case ATA_PROT_DMA: + return HISI_SAS_SATA_PROTOCOL_DMA; + case ATA_PROT_NCQ_NODATA: + case ATA_PROT_NCQ: + return HISI_SAS_SATA_PROTOCOL_FPDMA; + default: + return HISI_SAS_SATA_PROTOCOL_PIO; + } +} + +u8 hisi_sas_get_ata_protocol(struct sas_task *task) { + struct host_to_dev_fis *fis = &task->ata_task.fis; + struct ata_queued_cmd *qc = task->uldd_task; + int direction = task->data_dir; + switch (fis->command) { case ATA_CMD_FPDMA_WRITE: case ATA_CMD_FPDMA_READ: @@ -90,11 +124,9 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) } default: - { if (direction == DMA_NONE) return HISI_SAS_SATA_PROTOCOL_NONDATA; - return HISI_SAS_SATA_PROTOCOL_PIO; - } + return hisi_sas_get_ata_protocol_from_tf(qc); } } EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); @@ -107,7 +139,7 @@ void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_status_buffer *status_buf = hisi_sas_status_buf_addr_mem(slot); u8 *iu = &status_buf->iu[0]; - struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu; + struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu; resp->frame_len = sizeof(struct dev_to_host_fis); memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); @@ -127,7 +159,7 @@ u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max) max -= SAS_LINK_RATE_1_5_GBPS; for (i = 0; i <= max; i++) - rate |= 1 << (i * 2); + rate |= 1 << (i * LINK_RATE_BIT_MASK); return rate; } EXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask); @@ -844,7 +876,7 @@ static int hisi_sas_dev_found(struct domain_device *device) device->lldd_dev = sas_dev; hisi_hba->hw->setup_itct(hisi_hba, sas_dev); - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(device)) { int phy_no; phy_no = sas_find_attached_phy_id(&parent_dev->ex_dev, device); @@ -876,7 +908,7 @@ int hisi_sas_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) if (ret) return ret; if (!dev_is_sata(dev)) - sas_change_queue_depth(sdev, 64); + sas_change_queue_depth(sdev, HISI_SAS_BLK_QUEUE_DEPTH); return 0; } @@ -911,8 +943,28 @@ static void hisi_sas_phyup_work_common(struct work_struct *work, container_of(work, typeof(*phy), works[event]); struct hisi_hba *hisi_hba = phy->hisi_hba; struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct asd_sas_port *sas_port = sas_phy->port; + struct hisi_sas_port *port = phy->port; + struct device *dev = hisi_hba->dev; + struct domain_device *port_dev; int phy_no = sas_phy->id; + if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) && + sas_port && port && (port->id != phy->port_id)) { + dev_info(dev, "phy%d's hw port id changed from %d to %llu\n", + phy_no, port->id, phy->port_id); + port_dev = sas_port->port_dev; + if (port_dev && !dev_is_expander(port_dev->dev_type)) { + /* + * Set the device state to gone to block + * sending IO to the device. + */ + set_bit(SAS_DEV_GONE, &port_dev->state); + hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); + return; + } + } + phy->wait_phyup_cnt = 0; if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP) hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no); @@ -964,7 +1016,7 @@ EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event); static void hisi_sas_wait_phyup_timedout(struct timer_list *t) { - struct hisi_sas_phy *phy = from_timer(phy, t, timer); + struct hisi_sas_phy *phy = timer_container_of(phy, t, timer); struct hisi_hba *hisi_hba = phy->hisi_hba; struct device *dev = hisi_hba->dev; int phy_no = phy->sas_phy.id; @@ -1218,7 +1270,7 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->minimum_linkrate = min; hisi_sas_phy_enable(hisi_hba, phy_no, 0); - msleep(100); + msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); hisi_sas_phy_enable(hisi_hba, phy_no, 1); @@ -1248,7 +1300,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, case PHY_FUNC_LINK_RESET: hisi_sas_phy_enable(hisi_hba, phy_no, 0); - msleep(100); + msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); hisi_sas_phy_enable(hisi_hba, phy_no, 1); break; @@ -1274,7 +1326,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, if (sts && !wait_for_completion_timeout(&completion, HISI_SAS_WAIT_PHYUP_TIMEOUT)) { - dev_warn(dev, "phy%d wait phyup timed out for func %d\n", + dev_warn(dev, "phy%d wait phyup timed out for func %u\n", phy_no, func); if (phy->in_reset) ret = -ETIMEDOUT; @@ -1303,7 +1355,7 @@ static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, static int hisi_sas_softreset_ata_disk(struct domain_device *device) { - u8 fis[20] = {0}; + u8 fis[FIS_BUF_SIZE] = {0}; struct ata_port *ap = device->sata_dev.ap; struct ata_link *link; int rc = TMF_RESP_FUNC_FAILED; @@ -1320,7 +1372,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) } if (rc == TMF_RESP_FUNC_COMPLETE) { - usleep_range(900, 1000); + usleep_range(DELAY_FOR_SOFTRESET_MIN, DELAY_FOR_SOFTRESET_MAX); ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link); @@ -1450,7 +1502,7 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; int rc = TMF_RESP_FUNC_FAILED; struct ata_link *link; - u8 fis[20] = {0}; + u8 fis[FIS_BUF_SIZE] = {0}; int i; for (i = 0; i < hisi_hba->n_phy; i++) { @@ -1517,14 +1569,16 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); scsi_block_requests(shost); - hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); + hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, + WAIT_CMD_COMPLETE_DELAY, + WAIT_CMD_COMPLETE_TMROUT); /* * hisi_hba->timer is only used for v1/v2 hw, and check hw->sht * which is also only used for v1/v2 hw to skip it for v3 hw */ if (hisi_hba->hw->sht) - del_timer_sync(&hisi_hba->timer); + timer_delete_sync(&hisi_hba->timer); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); } @@ -1818,7 +1872,7 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) rc = ata_wait_after_reset(link, jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT, smp_ata_check_ready_type); } else { - msleep(2000); + msleep(DELAY_FOR_LINK_READY); } return rc; @@ -1841,33 +1895,14 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) } hisi_sas_dereg_device(hisi_hba, device); - rc = hisi_sas_debug_I_T_nexus_reset(device); - if (rc == TMF_RESP_FUNC_COMPLETE && dev_is_sata(device)) { - struct sas_phy *local_phy; - + if (dev_is_sata(device)) { rc = hisi_sas_softreset_ata_disk(device); - switch (rc) { - case -ECOMM: - rc = -ENODEV; - break; - case TMF_RESP_FUNC_FAILED: - case -EMSGSIZE: - case -EIO: - local_phy = sas_get_local_phy(device); - rc = sas_phy_enable(local_phy, 0); - if (!rc) { - local_phy->enabled = 0; - dev_err(dev, "Disabled local phy of ATA disk %016llx due to softreset fail (%d)\n", - SAS_ADDR(device->sas_addr), rc); - rc = -ENODEV; - } - sas_put_local_phy(local_phy); - break; - default: - break; - } + if (rc == TMF_RESP_FUNC_FAILED) + dev_err(dev, "ata disk %016llx reset (%d)\n", + SAS_ADDR(device->sas_addr), rc); } + rc = hisi_sas_debug_I_T_nexus_reset(device); if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) hisi_sas_release_task(hisi_hba, device); @@ -1890,12 +1925,9 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) hisi_sas_dereg_device(hisi_hba, device); if (dev_is_sata(device)) { - struct sas_phy *phy; - - phy = sas_get_local_phy(device); + struct sas_phy *phy = sas_get_local_phy(device); rc = sas_phy_reset(phy, true); - if (rc == 0) hisi_sas_release_task(hisi_hba, device); sas_put_local_phy(phy); @@ -2079,7 +2111,7 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy, hisi_sas_bytes_dmaed(hisi_hba, phy_no, gfp_flags); hisi_sas_port_notify_formed(sas_phy); } else { - struct hisi_sas_port *port = phy->port; + struct hisi_sas_port *port = phy->port; if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) || phy->in_reset) { @@ -2252,12 +2284,14 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) goto err_out; /* roundup to avoid overly large block size */ - max_command_entries_ru = roundup(max_command_entries, 64); + max_command_entries_ru = roundup(max_command_entries, + BLK_CNT_OPTIMIZE_MARK); if (hisi_hba->prot_mask & HISI_SAS_DIX_PROT_MASK) sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table); else sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table); - sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64); + + sz_slot_buf_ru = roundup(sz_slot_buf_ru, BLK_CNT_OPTIMIZE_MARK); s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE); blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; slots_per_blk = s / sz_slot_buf_ru; @@ -2339,7 +2373,7 @@ void hisi_sas_free(struct hisi_hba *hisi_hba) for (i = 0; i < hisi_hba->n_phy; i++) { struct hisi_sas_phy *phy = &hisi_hba->phy[i]; - del_timer_sync(&phy->timer); + timer_delete_sync(&phy->timer); } if (hisi_hba->wq) @@ -2422,7 +2456,8 @@ int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) if (IS_ERR(refclk)) dev_dbg(dev, "no ref clk property\n"); else - hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000; + hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / + HZ_TO_MHZ; if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) { dev_err(dev, "could not get property phy-count\n"); @@ -2543,8 +2578,8 @@ int hisi_sas_probe(struct platform_device *pdev, shost->transportt = hisi_sas_stt; shost->max_id = HISI_SAS_MAX_DEVICES; shost->max_lun = ~0; - shost->max_channel = 1; - shost->max_cmd_len = 16; + shost->max_channel = 0; + shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN; if (hisi_hba->hw->slot_index_alloc) { shost->can_queue = HISI_SAS_MAX_COMMANDS; shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS; @@ -2601,7 +2636,7 @@ void hisi_sas_remove(struct platform_device *pdev) struct hisi_hba *hisi_hba = sha->lldd_ha; struct Scsi_Host *shost = sha->shost; - del_timer_sync(&hisi_hba->timer); + timer_delete_sync(&hisi_hba->timer); sas_unregister_ha(sha); sas_remove_host(shost); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index bb78e53c66e2..fa94d7110714 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -795,7 +795,7 @@ static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no) static void start_phys_v1_hw(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i; for (i = 0; i < hisi_hba->n_phy; i++) { @@ -1759,7 +1759,7 @@ static const struct scsi_host_template sht_v1_hw = { .sg_tablesize = HISI_SAS_SGE_PAGE_CNT, .sdev_init = hisi_sas_sdev_init, .shost_groups = host_v1_hw_groups, - .host_reset = hisi_sas_host_reset, + .host_reset = hisi_sas_host_reset, }; static const struct hisi_sas_hw hisi_sas_v1_hw = { @@ -1806,7 +1806,7 @@ static struct platform_driver hisi_sas_v1_driver = { .driver = { .name = DRV_NAME, .of_match_table = sas_v1_of_match, - .acpi_match_table = ACPI_PTR(sas_v1_acpi_match), + .acpi_match_table = sas_v1_acpi_match, }, }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 71cd5b4450c2..f3516a0611dd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -925,7 +925,6 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; - struct domain_device *parent_dev = device->parent; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); u64 sas_addr; @@ -942,7 +941,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -1328,7 +1327,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) static void link_timeout_enable_link(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i, reg_val; for (i = 0; i < hisi_hba->n_phy; i++) { @@ -1349,7 +1348,7 @@ static void link_timeout_enable_link(struct timer_list *t) static void link_timeout_disable_link(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i, reg_val; reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); @@ -2372,18 +2371,18 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba, case STAT_IO_COMPLETE: /* internal abort command complete */ ts->stat = TMF_RESP_FUNC_SUCC; - del_timer_sync(&slot->internal_abort_timer); + timer_delete_sync(&slot->internal_abort_timer); goto out; case STAT_IO_NO_DEVICE: ts->stat = TMF_RESP_FUNC_COMPLETE; - del_timer_sync(&slot->internal_abort_timer); + timer_delete_sync(&slot->internal_abort_timer); goto out; case STAT_IO_NOT_VALID: /* abort single io, controller don't find * the io need to abort */ ts->stat = TMF_RESP_FUNC_FAILED; - del_timer_sync(&slot->internal_abort_timer); + timer_delete_sync(&slot->internal_abort_timer); goto out; default: break; @@ -2401,7 +2400,7 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba, slot_err_v2_hw(hisi_hba, task, slot, 2); if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", slot->idx, task, sas_dev->device_id, complete_hdr->dw0, complete_hdr->dw1, complete_hdr->act, complete_hdr->dw3, @@ -2467,7 +2466,7 @@ out: spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { spin_unlock_irqrestore(&task->task_state_lock, flags); - dev_info(dev, "slot complete: task(%pK) aborted\n", task); + dev_info(dev, "slot complete: task(%p) aborted\n", task); return; } task->task_state_flags |= SAS_TASK_STATE_DONE; @@ -2478,7 +2477,7 @@ out: spin_lock_irqsave(&device->done_lock, flags); if (test_bit(SAS_HA_FROZEN, &ha->state)) { spin_unlock_irqrestore(&device->done_lock, flags); - dev_info(dev, "slot complete: task(%pK) ignored\n", + dev_info(dev, "slot complete: task(%p) ignored\n", task); return; } @@ -2494,13 +2493,13 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, { struct sas_task *task = slot->task; struct domain_device *device = task->dev; - struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); struct sas_ata_task *ata_task = &task->ata_task; struct sas_tmf_task *tmf = slot->tmf; + int phy_id; u8 *buf_cmd; int has_data = 0, hdr_tag = 0; u32 dw0, dw1 = 0, dw2 = 0; @@ -2508,10 +2507,14 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, /* create header */ /* dw0 */ dw0 = port->id << CMD_HDR_PORT_OFF; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) { dw0 |= 3 << CMD_HDR_CMD_OFF; - else + } else { + phy_id = device->phy->identify.phy_identifier; + dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF; + dw0 |= CMD_HDR_FORCE_PHY_MSK; dw0 |= 4 << CMD_HDR_CMD_OFF; + } if (tmf && ata_task->force_phy) { dw0 |= CMD_HDR_FORCE_PHY_MSK; @@ -2538,9 +2541,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, (task->ata_task.fis.control & ATA_SRST)) dw1 |= 1 << CMD_HDR_RESET_OFF; - dw1 |= (hisi_sas_get_ata_protocol( - &task->ata_task.fis, task->data_dir)) - << CMD_HDR_FRAME_TYPE_OFF; + dw1 |= (hisi_sas_get_ata_protocol(task)) << CMD_HDR_FRAME_TYPE_OFF; dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; hdr->dw1 = cpu_to_le32(dw1); @@ -2578,7 +2579,8 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) { - struct hisi_sas_slot *slot = from_timer(slot, t, internal_abort_timer); + struct hisi_sas_slot *slot = timer_container_of(slot, t, + internal_abort_timer); struct hisi_sas_port *port = slot->port; struct asd_sas_port *asd_sas_port; struct asd_sas_phy *sas_phy; @@ -2656,7 +2658,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) if (is_sata_phy_v2_hw(hisi_hba, phy_no)) goto end; - del_timer(&phy->timer); + timer_delete(&phy->timer); if (phy_no == 8) { u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE); @@ -2732,7 +2734,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) struct hisi_sas_port *port = phy->port; struct device *dev = hisi_hba->dev; - del_timer(&phy->timer); + timer_delete(&phy->timer); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); @@ -2746,7 +2748,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) if (port && !get_wideport_bitmap_v2_hw(hisi_hba, port->id)) if (!check_any_wideports_v2_hw(hisi_hba) && timer_pending(&hisi_hba->timer)) - del_timer(&hisi_hba->timer); + timer_delete(&hisi_hba->timer); txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, @@ -2768,7 +2770,7 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff; while (irq_msk) { - if (irq_msk & 1) { + if (irq_msk & 1) { u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0); @@ -3108,7 +3110,7 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) return IRQ_HANDLED; } -static irqreturn_t cq_thread_v2_hw(int irq_no, void *p) +static irqreturn_t cq_thread_v2_hw(int irq_no, void *p) { struct hisi_sas_cq *cq = p; struct hisi_hba *hisi_hba = cq->hisi_hba; @@ -3206,7 +3208,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; int phy_no, offset; - del_timer(&phy->timer); + timer_delete(&phy->timer); phy_no = sas_phy->id; initial_fis = &hisi_hba->initial_fis[phy_no]; @@ -3496,7 +3498,7 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, * numbered drive in the fourth byte. * See SFF-8485 Rev. 0.7 Table 24. */ - void __iomem *reg_addr = hisi_hba->sgpio_regs + + void __iomem *reg_addr = hisi_hba->sgpio_regs + reg_index * 4 + phy_no; int data_idx = phy_no + 3 - (phy_no % 4) * 2; @@ -3653,7 +3655,7 @@ static struct platform_driver hisi_sas_v2_driver = { .driver = { .name = DRV_NAME, .of_match_table = sas_v2_of_match, - .acpi_match_table = ACPI_PTR(sas_v2_acpi_match), + .acpi_match_table = sas_v2_acpi_match, }, }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 48b95d9a7927..14d563e82d20 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -359,6 +359,10 @@ #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF) #define CMD_HDR_TLR_CTRL_OFF 6 #define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF) +#define CMD_HDR_PHY_ID_OFF 8 +#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF) +#define CMD_HDR_FORCE_PHY_OFF 17 +#define CMD_HDR_FORCE_PHY_MSK (0x1U << CMD_HDR_FORCE_PHY_OFF) #define CMD_HDR_PORT_OFF 18 #define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF) #define CMD_HDR_PRIORITY_OFF 27 @@ -428,7 +432,7 @@ #define CMPLT_HDR_IPTT_OFF 0 #define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF) #define CMPLT_HDR_DEV_ID_OFF 16 -#define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF) +#define CMPLT_HDR_DEV_ID_MSK (0xffffU << CMPLT_HDR_DEV_ID_OFF) /* dw3 */ #define SATA_DISK_IN_ERROR_STATUS_OFF 8 #define SATA_DISK_IN_ERROR_STATUS_MSK (0x1 << SATA_DISK_IN_ERROR_STATUS_OFF) @@ -440,7 +444,7 @@ #define FIS_ATA_STATUS_ERR_OFF 18 #define FIS_ATA_STATUS_ERR_MSK (0x1 << FIS_ATA_STATUS_ERR_OFF) #define FIS_TYPE_SDB_OFF 31 -#define FIS_TYPE_SDB_MSK (0x1 << FIS_TYPE_SDB_OFF) +#define FIS_TYPE_SDB_MSK (0x1U << FIS_TYPE_SDB_OFF) /* ITCT header */ /* qw0 */ @@ -462,6 +466,12 @@ #define ITCT_HDR_RTOLT_OFF 48 #define ITCT_HDR_RTOLT_MSK (0xffffULL << ITCT_HDR_RTOLT_OFF) +/*debugfs*/ +#define TWO_PARA_PER_LINE 2 +#define FOUR_PARA_PER_LINE 4 +#define DUMP_BUF_SIZE 8 +#define BIST_BUF_SIZE 16 + struct hisi_sas_protect_iu_v3_hw { u32 dw0; u32 lbrtcv; @@ -532,6 +542,43 @@ struct hisi_sas_err_record_v3 { #define BASE_VECTORS_V3_HW 16 #define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1) +#define IRQ_PHY_UP_DOWN_INDEX 1 +#define IRQ_CHL_INDEX 2 +#define IRQ_AXI_INDEX 11 + +#define DELAY_FOR_RESET_HW 100 +#define HDR_SG_MOD 0x2 +#define LUN_SIZE 8 +#define ATTR_PRIO_REGION 9 +#define CDB_REGION 12 +#define PRIO_OFF 3 +#define TMF_REGION 10 +#define TAG_MSB 12 +#define TAG_LSB 13 +#define SMP_FRAME_TYPE 2 +#define SMP_CRC_SIZE 4 +#define HDR_TAG_OFF 3 +#define HOST_NO_OFF 6 +#define PHY_NO_OFF 7 +#define IDENTIFY_REG_READ 6 +#define LINK_RESET_TIMEOUT_OFF 4 +#define DECIMALISM_FLAG 10 +#define WAIT_RETRY 100 +#define WAIT_TMROUT 5000 + +#define ID_DWORD0_INDEX 0 +#define ID_DWORD1_INDEX 1 +#define ID_DWORD2_INDEX 2 +#define ID_DWORD3_INDEX 3 +#define ID_DWORD4_INDEX 4 +#define ID_DWORD5_INDEX 5 +#define TICKS_BIT_INDEX 24 +#define COUNT_BIT_INDEX 8 + +#define PORT_REG_LENGTH 0x100 +#define GLOBAL_REG_LENGTH 0x800 +#define AXI_REG_LENGTH 0x61 +#define RAS_REG_LENGTH 0x10 #define CHNL_INT_STS_MSK 0xeeeeeeee #define CHNL_INT_STS_PHY_MSK 0xe @@ -807,17 +854,17 @@ static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no) identify_buffer = (u32 *)(&identify_frame); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, - __swab32(identify_buffer[0])); + __swab32(identify_buffer[ID_DWORD0_INDEX])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, - __swab32(identify_buffer[1])); + __swab32(identify_buffer[ID_DWORD1_INDEX])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, - __swab32(identify_buffer[2])); + __swab32(identify_buffer[ID_DWORD2_INDEX])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, - __swab32(identify_buffer[3])); + __swab32(identify_buffer[ID_DWORD3_INDEX])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, - __swab32(identify_buffer[4])); + __swab32(identify_buffer[ID_DWORD4_INDEX])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, - __swab32(identify_buffer[5])); + __swab32(identify_buffer[ID_DWORD5_INDEX])); } static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, @@ -827,7 +874,6 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; - struct domain_device *parent_dev = device->parent; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); u64 sas_addr; @@ -844,13 +890,13 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; break; default: - dev_warn(dev, "setup itct: unsupported dev type (%d)\n", + dev_warn(dev, "setup itct: unsupported dev type (%u)\n", sas_dev->dev_type); } @@ -937,7 +983,7 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba) /* Disable all of the PHYs */ hisi_sas_stop_phys(hisi_hba); - udelay(50); + udelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); /* Ensure axi bus idle */ ret = hisi_sas_read32_poll_timeout(AXI_CFG, val, !val, @@ -977,7 +1023,7 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba) return rc; } - msleep(100); + msleep(DELAY_FOR_RESET_HW); init_reg_v3_hw(hisi_hba); if (guid_parse("D5918B4B-37AE-4E10-A99F-E5E8A6EF4C1F", &guid)) { @@ -1026,7 +1072,7 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) cfg &= ~PHY_CFG_ENA_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); - mdelay(50); + mdelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); state = hisi_sas_read32(hisi_hba, PHY_STATE); if (state & BIT(phy_no)) { @@ -1062,7 +1108,7 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, txid_auto | TX_HARDRST_MSK); } - msleep(100); + msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); hisi_sas_phy_enable(hisi_hba, phy_no, 1); } @@ -1107,7 +1153,8 @@ static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id) for (i = 0; i < hisi_hba->n_phy; i++) if (phy_state & BIT(i)) - if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id) + if (((phy_port_num_ma >> (i * HISI_SAS_REG_MEM_SIZE)) & 0xf) == + port_id) bitmap |= BIT(i); return bitmap; @@ -1304,10 +1351,10 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, /* map itct entry */ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; - dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) - + 3) / 4) << CMD_HDR_CFL_OFF) | - ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) | - (2 << CMD_HDR_SG_MOD_OFF); + dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) + + 3) / BYTE_TO_DW) << CMD_HDR_CFL_OFF) | + ((HISI_SAS_MAX_SSP_RESP_SZ / BYTE_TO_DW) << CMD_HDR_MRFL_OFF) | + (HDR_SG_MOD << CMD_HDR_SG_MOD_OFF); hdr->dw2 = cpu_to_le32(dw2); hdr->transfer_tags = cpu_to_le32(slot->idx); @@ -1327,18 +1374,19 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) + sizeof(struct ssp_frame_hdr); - memcpy(buf_cmd, &task->ssp_task.LUN, 8); + memcpy(buf_cmd, &task->ssp_task.LUN, LUN_SIZE); if (!tmf) { - buf_cmd[9] = ssp_task->task_attr; - memcpy(buf_cmd + 12, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + buf_cmd[ATTR_PRIO_REGION] = ssp_task->task_attr; + memcpy(buf_cmd + CDB_REGION, scsi_cmnd->cmnd, + scsi_cmnd->cmd_len); } else { - buf_cmd[10] = tmf->tmf; + buf_cmd[TMF_REGION] = tmf->tmf; switch (tmf->tmf) { case TMF_ABORT_TASK: case TMF_QUERY_TASK: - buf_cmd[12] = + buf_cmd[TAG_MSB] = (tmf->tag_of_task_to_be_managed >> 8) & 0xff; - buf_cmd[13] = + buf_cmd[TAG_LSB] = tmf->tag_of_task_to_be_managed & 0xff; break; default: @@ -1371,7 +1419,8 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, unsigned int interval = scsi_prot_interval(scsi_cmnd); unsigned int ilog2_interval = ilog2(interval); - len = (task->total_xfer_len >> ilog2_interval) * 8; + len = (task->total_xfer_len >> ilog2_interval) * + BYTE_TO_DDW; } } @@ -1391,6 +1440,7 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev = device->lldd_dev; dma_addr_t req_dma_addr; unsigned int req_len; + u32 cfl; /* req */ sg_req = &task->smp_task.smp_req; @@ -1401,7 +1451,7 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, /* dw0 */ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */ - (2 << CMD_HDR_CMD_OFF)); /* smp */ + (SMP_FRAME_TYPE << CMD_HDR_CMD_OFF)); /* smp */ /* map itct entry */ hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) | @@ -1409,8 +1459,9 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, (DIR_NO_DATA << CMD_HDR_DIR_OFF)); /* dw2 */ - hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) | - (HISI_SAS_MAX_SMP_RESP_SZ / 4 << + cfl = (req_len - SMP_CRC_SIZE) / BYTE_TO_DW; + hdr->dw2 = cpu_to_le32((cfl << CMD_HDR_CFL_OFF) | + (HISI_SAS_MAX_SMP_RESP_SZ / BYTE_TO_DW << CMD_HDR_MRFL_OFF)); hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF); @@ -1424,20 +1475,25 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, { struct sas_task *task = slot->task; struct domain_device *device = task->dev; - struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + int phy_id; u8 *buf_cmd; int has_data = 0, hdr_tag = 0; u32 dw1 = 0, dw2 = 0; hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) { hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); - else + } else { + phy_id = device->phy->identify.phy_identifier; + hdr->dw0 |= cpu_to_le32((1U << phy_id) + << CMD_HDR_PHY_ID_OFF); + hdr->dw0 |= cpu_to_le32(CMD_HDR_FORCE_PHY_MSK); hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF); + } switch (task->data_dir) { case DMA_TO_DEVICE: @@ -1456,9 +1512,7 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, (task->ata_task.fis.control & ATA_SRST)) dw1 |= 1 << CMD_HDR_RESET_OFF; - dw1 |= (hisi_sas_get_ata_protocol( - &task->ata_task.fis, task->data_dir)) - << CMD_HDR_FRAME_TYPE_OFF; + dw1 |= (hisi_sas_get_ata_protocol(task)) << CMD_HDR_FRAME_TYPE_OFF; dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; if (FIS_CMD_IS_UNCONSTRAINED(task->ata_task.fis)) @@ -1471,12 +1525,13 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, struct ata_queued_cmd *qc = task->uldd_task; hdr_tag = qc->tag; - task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); + task->ata_task.fis.sector_count |= + (u8)(hdr_tag << HDR_TAG_OFF); dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; } - dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF | - 2 << CMD_HDR_SG_MOD_OFF; + dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / BYTE_TO_DW) << CMD_HDR_CFL_OFF | + HDR_SG_MOD << CMD_HDR_SG_MOD_OFF; hdr->dw2 = cpu_to_le32(dw2); /* dw3 */ @@ -1536,9 +1591,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); - port_id = (port_id >> (4 * phy_no)) & 0xf; + port_id = (port_id >> (HISI_SAS_REG_MEM_SIZE * phy_no)) & 0xf; link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); - link_rate = (link_rate >> (phy_no * 4)) & 0xf; + link_rate = (link_rate >> (phy_no * HISI_SAS_REG_MEM_SIZE)) & 0xf; if (port_id == 0xf) { dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); @@ -1571,8 +1626,8 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) sas_phy->oob_mode = SATA_OOB_MODE; attached_sas_addr[0] = 0x50; - attached_sas_addr[6] = shost->host_no; - attached_sas_addr[7] = phy_no; + attached_sas_addr[HOST_NO_OFF] = shost->host_no; + attached_sas_addr[PHY_NO_OFF] = phy_no; memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE); @@ -1588,7 +1643,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) (struct sas_identify_frame *)frame_rcvd; dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); - for (i = 0; i < 6; i++) { + for (i = 0; i < IDENTIFY_REG_READ; i++) { u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, RX_IDAF_DWORD0 + (i * 4)); frame_rcvd[i] = __swab32(idaf); @@ -1611,7 +1666,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) phy->port_id = port_id; spin_lock(&phy->lock); /* Delete timer and set phy_attached atomically */ - del_timer(&phy->timer); + timer_delete(&phy->timer); phy->phy_attached = 1; spin_unlock(&phy->lock); @@ -1645,7 +1700,7 @@ static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) atomic_inc(&phy->down_cnt); - del_timer(&phy->timer); + timer_delete(&phy->timer); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); @@ -1693,7 +1748,7 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) & 0x11111111; while (irq_msk) { - if (irq_msk & 1) { + if (irq_msk & 1) { u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0); u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); @@ -1858,7 +1913,7 @@ static void handle_chl_int2_v3_hw(struct hisi_hba *hisi_hba, int phy_no) dev_warn(dev, "phy%d stp link timeout (0x%x)\n", phy_no, reg_value); - if (reg_value & BIT(4)) + if (reg_value & BIT(LINK_RESET_TIMEOUT_OFF)) hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); } @@ -1916,8 +1971,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) u32 irq_msk; int phy_no = 0; - irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) - & CHNL_INT_STS_MSK; + irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) & CHNL_INT_STS_MSK; while (irq_msk) { if (irq_msk & (CHNL_INT_STS_INT0_MSK << (phy_no * CHNL_WIDTH))) @@ -2353,7 +2407,7 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba, if (slot_err_v3_hw(hisi_hba, task, slot)) { if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d addr=%016llx CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d addr=%016llx CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", slot->idx, task, sas_dev->device_id, SAS_ADDR(device->sas_addr), dw0, dw1, complete_hdr->act, dw3, @@ -2414,7 +2468,7 @@ out: spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { spin_unlock_irqrestore(&task->task_state_lock, flags); - dev_info(dev, "slot complete: task(%pK) aborted\n", task); + dev_info(dev, "slot complete: task(%p) aborted\n", task); return; } task->task_state_flags |= SAS_TASK_STATE_DONE; @@ -2425,7 +2479,7 @@ out: spin_lock_irqsave(&device->done_lock, flags); if (test_bit(SAS_HA_FROZEN, &ha->state)) { spin_unlock_irqrestore(&device->done_lock, flags); - dev_info(dev, "slot complete: task(%pK) ignored\n", + dev_info(dev, "slot complete: task(%p) ignored\n", task); return; } @@ -2562,7 +2616,6 @@ static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba) if (vectors < 0) return -ENOENT; - hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW - hisi_hba->iopoll_q_cnt; shost->nr_hw_queues = hisi_hba->cq_nvecs + hisi_hba->iopoll_q_cnt; @@ -2575,7 +2628,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) struct pci_dev *pdev = hisi_hba->pci_dev; int rc, i; - rc = devm_request_irq(dev, pci_irq_vector(pdev, 1), + rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX), int_phy_up_down_bcast_v3_hw, 0, DRV_NAME " phy", hisi_hba); if (rc) { @@ -2583,7 +2636,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) return -ENOENT; } - rc = devm_request_irq(dev, pci_irq_vector(pdev, 2), + rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_CHL_INDEX), int_chnl_int_v3_hw, 0, DRV_NAME " channel", hisi_hba); if (rc) { @@ -2591,7 +2644,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) return -ENOENT; } - rc = devm_request_irq(dev, pci_irq_vector(pdev, 11), + rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_AXI_INDEX), fatal_axi_int_v3_hw, 0, DRV_NAME " fatal", hisi_hba); if (rc) { @@ -2604,7 +2657,8 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) for (i = 0; i < hisi_hba->cq_nvecs; i++) { struct hisi_sas_cq *cq = &hisi_hba->cq[i]; - int nr = hisi_sas_intr_conv ? 16 : 16 + i; + int nr = hisi_sas_intr_conv ? BASE_VECTORS_V3_HW : + BASE_VECTORS_V3_HW + i; unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : IRQF_ONESHOT; @@ -2662,14 +2716,14 @@ static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba) struct pci_dev *pdev = hisi_hba->pci_dev; int i; - synchronize_irq(pci_irq_vector(pdev, 1)); - synchronize_irq(pci_irq_vector(pdev, 2)); - synchronize_irq(pci_irq_vector(pdev, 11)); + synchronize_irq(pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX)); + synchronize_irq(pci_irq_vector(pdev, IRQ_CHL_INDEX)); + synchronize_irq(pci_irq_vector(pdev, IRQ_AXI_INDEX)); for (i = 0; i < hisi_hba->queue_count; i++) hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1); for (i = 0; i < hisi_hba->cq_nvecs; i++) - synchronize_irq(pci_irq_vector(pdev, i + 16)); + synchronize_irq(pci_irq_vector(pdev, i + BASE_VECTORS_V3_HW)); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff); @@ -2701,7 +2755,7 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_stop_phys(hisi_hba); - mdelay(10); + mdelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL); @@ -2793,7 +2847,7 @@ static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, static ssize_t intr_conv_v3_hw_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%u\n", hisi_sas_intr_conv); + return scnprintf(buf, PAGE_SIZE, "%d\n", hisi_sas_intr_conv); } static DEVICE_ATTR_RO(intr_conv_v3_hw); @@ -2838,13 +2892,13 @@ static ssize_t intr_coal_ticks_v3_hw_store(struct device *dev, u32 intr_coal_ticks; int ret; - ret = kstrtou32(buf, 10, &intr_coal_ticks); + ret = kstrtou32(buf, DECIMALISM_FLAG, &intr_coal_ticks); if (ret) { dev_err(dev, "Input data of interrupt coalesce unmatch\n"); return -EINVAL; } - if (intr_coal_ticks >= BIT(24)) { + if (intr_coal_ticks >= BIT(TICKS_BIT_INDEX)) { dev_err(dev, "intr_coal_ticks must be less than 2^24!\n"); return -EINVAL; } @@ -2877,13 +2931,13 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev, u32 intr_coal_count; int ret; - ret = kstrtou32(buf, 10, &intr_coal_count); + ret = kstrtou32(buf, DECIMALISM_FLAG, &intr_coal_count); if (ret) { dev_err(dev, "Input data of interrupt coalesce unmatch\n"); return -EINVAL; } - if (intr_coal_count >= BIT(8)) { + if (intr_coal_count >= BIT(COUNT_BIT_INDEX)) { dev_err(dev, "intr_coal_count must be less than 2^8!\n"); return -EINVAL; } @@ -3015,7 +3069,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = { static const struct hisi_sas_debugfs_reg debugfs_port_reg = { .lu = debugfs_port_reg_lu, - .count = 0x100, + .count = PORT_REG_LENGTH, .base_off = PORT_BASE, }; @@ -3089,7 +3143,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = { static const struct hisi_sas_debugfs_reg debugfs_global_reg = { .lu = debugfs_global_reg_lu, - .count = 0x800, + .count = GLOBAL_REG_LENGTH, }; static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { @@ -3102,7 +3156,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { static const struct hisi_sas_debugfs_reg debugfs_axi_reg = { .lu = debugfs_axi_reg_lu, - .count = 0x61, + .count = AXI_REG_LENGTH, .base_off = AXI_MASTER_CFG_BASE, }; @@ -3119,7 +3173,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = { static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { .lu = debugfs_ras_reg_lu, - .count = 0x10, + .count = RAS_REG_LENGTH, .base_off = RAS_BASE, }; @@ -3128,7 +3182,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) struct Scsi_Host *shost = hisi_hba->shost; scsi_block_requests(shost); - wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000); + wait_cmds_complete_timeout_v3_hw(hisi_hba, WAIT_RETRY, WAIT_TMROUT); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); hisi_sas_sync_cqs(hisi_hba); @@ -3169,7 +3223,7 @@ static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, return; } - memset(buf, 0, cache_dw_size * 4); + memset(buf, 0, cache_dw_size * BYTE_TO_DW); buf[0] = val; for (i = 1; i < cache_dw_size; i++) @@ -3216,7 +3270,7 @@ static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba) reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); /* init OOB link rate as 1.5 Gbits */ reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; - reg_val |= (0x8 << CFG_PROG_OOB_PHY_LINK_RATE_OFF); + reg_val |= (SAS_LINK_RATE_1_5_GBPS << CFG_PROG_OOB_PHY_LINK_RATE_OFF); hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, reg_val); /* enable PHY */ @@ -3225,6 +3279,9 @@ static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba) #define SAS_PHY_BIST_CODE_INIT 0x1 #define SAS_PHY_BIST_CODE1_INIT 0X80 +#define SAS_PHY_BIST_INIT_DELAY 100 +#define SAS_PHY_BIST_LOOP_TEST_0 1 +#define SAS_PHY_BIST_LOOP_TEST_1 2 static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) { u32 reg_val, mode_tmp; @@ -3236,19 +3293,20 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) u32 *fix_code = &hisi_hba->debugfs_bist_fixed_code[0]; struct device *dev = hisi_hba->dev; - dev_info(dev, "BIST info:phy%d link_rate=%d code_mode=%d path_mode=%d ffe={0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x} fixed_code={0x%x, 0x%x}\n", + dev_info(dev, "BIST info:phy%u link_rate=%u code_mode=%u path_mode=%u ffe={0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x} fixed_code={0x%x, 0x%x}\n", phy_no, linkrate, code_mode, path_mode, ffe[FFE_SAS_1_5_GBPS], ffe[FFE_SAS_3_0_GBPS], ffe[FFE_SAS_6_0_GBPS], ffe[FFE_SAS_12_0_GBPS], ffe[FFE_SATA_1_5_GBPS], ffe[FFE_SATA_3_0_GBPS], ffe[FFE_SATA_6_0_GBPS], fix_code[FIXED_CODE], fix_code[FIXED_CODE_1]); - mode_tmp = path_mode ? 2 : 1; + mode_tmp = path_mode ? SAS_PHY_BIST_LOOP_TEST_1 : + SAS_PHY_BIST_LOOP_TEST_0; if (enable) { /* some preparations before bist test */ hisi_sas_bist_test_prep_v3_hw(hisi_hba); - /* set linkrate of bit test*/ + /* set linkrate of bit test */ reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; @@ -3286,13 +3344,13 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) SAS_PHY_BIST_CODE1_INIT); } - mdelay(100); + mdelay(SAS_PHY_BIST_INIT_DELAY); reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, SAS_PHY_BIST_CTRL, reg_val); /* clear error bit */ - mdelay(100); + mdelay(SAS_PHY_BIST_INIT_DELAY); hisi_sas_phy_read32(hisi_hba, phy_no, SAS_BIST_ERR_CNT); } else { /* disable bist test and recover it */ @@ -3346,7 +3404,7 @@ static const struct scsi_host_template sht_v3_hw = { .shost_groups = host_v3_hw_groups, .sdev_groups = sdev_groups_v3_hw, .tag_alloc_policy_rr = true, - .host_reset = hisi_sas_host_reset, + .host_reset = hisi_sas_host_reset, .host_tagset = 1, .mq_poll = queue_complete_v3_hw, }; @@ -3488,7 +3546,7 @@ static void debugfs_snapshot_port_reg_v3_hw(struct hisi_hba *hisi_hba) for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; for (i = 0; i < port->count; i++, databuf++) { - offset = port->base_off + 4 * i; + offset = port->base_off + HISI_SAS_REG_MEM_SIZE * i; *databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt, offset); } @@ -3502,7 +3560,8 @@ static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba) int i; for (i = 0; i < debugfs_global_reg.count; i++, databuf++) - *databuf = hisi_sas_read32(hisi_hba, 4 * i); + *databuf = hisi_sas_read32(hisi_hba, + HISI_SAS_REG_MEM_SIZE * i); } static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) @@ -3513,7 +3572,9 @@ static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) int i; for (i = 0; i < axi->count; i++, databuf++) - *databuf = hisi_sas_read32(hisi_hba, 4 * i + axi->base_off); + *databuf = hisi_sas_read32(hisi_hba, + HISI_SAS_REG_MEM_SIZE * i + + axi->base_off); } static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) @@ -3524,7 +3585,9 @@ static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) int i; for (i = 0; i < ras->count; i++, databuf++) - *databuf = hisi_sas_read32(hisi_hba, 4 * i + ras->base_off); + *databuf = hisi_sas_read32(hisi_hba, + HISI_SAS_REG_MEM_SIZE * i + + ras->base_off); } static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba) @@ -3587,12 +3650,11 @@ static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s, int i; for (i = 0; i < reg->count; i++) { - int off = i * 4; + u32 off = i * HISI_SAS_REG_MEM_SIZE; const char *name; name = debugfs_to_reg_name_v3_hw(off, reg->base_off, reg->lu); - if (name) seq_printf(s, "0x%08x 0x%08x %s\n", off, regs_val[i], name); @@ -3665,9 +3727,9 @@ static void debugfs_show_row_64_v3_hw(struct seq_file *s, int index, /* completion header size not fixed per HW version */ seq_printf(s, "index %04d:\n\t", index); - for (i = 1; i <= sz / 8; i++, ptr++) { + for (i = 1; i <= sz / BYTE_TO_DDW; i++, ptr++) { seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); - if (!(i % 2)) + if (!(i % TWO_PARA_PER_LINE)) seq_puts(s, "\n\t"); } @@ -3681,9 +3743,9 @@ static void debugfs_show_row_32_v3_hw(struct seq_file *s, int index, /* completion header size not fixed per HW version */ seq_printf(s, "index %04d:\n\t", index); - for (i = 1; i <= sz / 4; i++, ptr++) { + for (i = 1; i <= sz / BYTE_TO_DW; i++, ptr++) { seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); - if (!(i % 4)) + if (!(i % FOUR_PARA_PER_LINE)) seq_puts(s, "\n\t"); } seq_puts(s, "\n"); @@ -3768,7 +3830,7 @@ static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache; - u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * BYTE_TO_DW; int i, tab_idx; __le64 *iost; @@ -3816,7 +3878,7 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache; - u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * BYTE_TO_DW; int i, tab_idx; __le64 *itct; @@ -3845,12 +3907,12 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) u64 *debugfs_timestamp; struct dentry *dump_dentry; struct dentry *dentry; - char name[256]; + char name[NAME_BUF_SIZE]; int p; int c; int d; - snprintf(name, 256, "%d", index); + snprintf(name, NAME_BUF_SIZE, "%d", index); dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); @@ -3866,7 +3928,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) /* Create port dir and files */ dentry = debugfs_create_dir("port", dump_dentry); for (p = 0; p < hisi_hba->n_phy; p++) { - snprintf(name, 256, "%d", p); + snprintf(name, NAME_BUF_SIZE, "%d", p); debugfs_create_file(name, 0400, dentry, &hisi_hba->debugfs_port_reg[index][p], @@ -3876,7 +3938,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) /* Create CQ dir and files */ dentry = debugfs_create_dir("cq", dump_dentry); for (c = 0; c < hisi_hba->queue_count; c++) { - snprintf(name, 256, "%d", c); + snprintf(name, NAME_BUF_SIZE, "%d", c); debugfs_create_file(name, 0400, dentry, &hisi_hba->debugfs_cq[index][c], @@ -3886,7 +3948,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) /* Create DQ dir and files */ dentry = debugfs_create_dir("dq", dump_dentry); for (d = 0; d < hisi_hba->queue_count; d++) { - snprintf(name, 256, "%d", d); + snprintf(name, NAME_BUF_SIZE, "%d", d); debugfs_create_file(name, 0400, dentry, &hisi_hba->debugfs_dq[index][d], @@ -3923,9 +3985,9 @@ static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file, size_t count, loff_t *ppos) { struct hisi_hba *hisi_hba = file->f_inode->i_private; - char buf[8]; + char buf[DUMP_BUF_SIZE]; - if (count > 8) + if (count > DUMP_BUF_SIZE) return -EFAULT; if (copy_from_user(buf, user_buf, count)) @@ -3989,7 +4051,7 @@ static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp, { struct seq_file *m = filp->private_data; struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; + char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; bool found = false; int i; @@ -4006,7 +4068,7 @@ static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp, for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) { if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name, - pkbuf, 16)) { + pkbuf, BIST_BUF_SIZE)) { hisi_hba->debugfs_bist_linkrate = debugfs_loop_linkrate_v3_hw[i].value; found = true; @@ -4064,7 +4126,7 @@ static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp, { struct seq_file *m = filp->private_data; struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; + char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; bool found = false; int i; @@ -4081,7 +4143,7 @@ static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp, for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) { if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name, - pkbuf, 16)) { + pkbuf, BIST_BUF_SIZE)) { hisi_hba->debugfs_bist_code_mode = debugfs_loop_code_mode_v3_hw[i].value; found = true; @@ -4196,7 +4258,7 @@ static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp, { struct seq_file *m = filp->private_data; struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; + char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; bool found = false; int i; @@ -4212,7 +4274,8 @@ static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp, pkbuf = strstrip(kbuf); for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) { - if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, 16)) { + if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, + BIST_BUF_SIZE)) { hisi_hba->debugfs_bist_mode = debugfs_loop_modes_v3_hw[i].value; found = true; @@ -4491,8 +4554,9 @@ static int debugfs_fifo_data_v3_hw_show(struct seq_file *s, void *p) debugfs_read_fifo_data_v3_hw(phy); - debugfs_show_row_32_v3_hw(s, 0, HISI_SAS_FIFO_DATA_DW_SIZE * 4, - (__le32 *)phy->fifo.rd_data); + debugfs_show_row_32_v3_hw(s, 0, + HISI_SAS_FIFO_DATA_DW_SIZE * HISI_SAS_REG_MEM_SIZE, + (__le32 *)phy->fifo.rd_data); return 0; } @@ -4624,14 +4688,14 @@ static int debugfs_alloc_v3_hw(struct hisi_hba *hisi_hba, int dump_index) struct hisi_sas_debugfs_regs *regs = &hisi_hba->debugfs_regs[dump_index][r]; - sz = debugfs_reg_array_v3_hw[r]->count * 4; + sz = debugfs_reg_array_v3_hw[r]->count * HISI_SAS_REG_MEM_SIZE; regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); if (!regs->data) goto fail; regs->hisi_hba = hisi_hba; } - sz = debugfs_port_reg.count * 4; + sz = debugfs_port_reg.count * HISI_SAS_REG_MEM_SIZE; for (p = 0; p < hisi_hba->n_phy; p++) { struct hisi_sas_debugfs_port *port = &hisi_hba->debugfs_port_reg[dump_index][p]; @@ -4741,11 +4805,11 @@ static void debugfs_phy_down_cnt_init_v3_hw(struct hisi_hba *hisi_hba) { struct dentry *dir = debugfs_create_dir("phy_down_cnt", hisi_hba->debugfs_dir); - char name[16]; + char name[NAME_BUF_SIZE]; int phy_no; for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { - snprintf(name, 16, "%d", phy_no); + snprintf(name, NAME_BUF_SIZE, "%d", phy_no); debugfs_create_file(name, 0600, dir, &hisi_hba->phy[phy_no], &debugfs_phy_down_cnt_v3_hw_fops); @@ -4929,8 +4993,8 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->transportt = hisi_sas_stt; shost->max_id = HISI_SAS_MAX_DEVICES; shost->max_lun = ~0; - shost->max_channel = 1; - shost->max_cmd_len = 16; + shost->max_channel = 0; + shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN; shost->can_queue = HISI_SAS_UNRESERVED_IPTT; shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; if (hisi_hba->iopoll_q_cnt) @@ -5008,12 +5072,13 @@ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba) { int i; - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 1), hisi_hba); - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 2), hisi_hba); - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 11), hisi_hba); + devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX), hisi_hba); + devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_CHL_INDEX), hisi_hba); + devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_AXI_INDEX), hisi_hba); for (i = 0; i < hisi_hba->cq_nvecs; i++) { struct hisi_sas_cq *cq = &hisi_hba->cq[i]; - int nr = hisi_sas_intr_conv ? 16 : 16 + i; + int nr = hisi_sas_intr_conv ? BASE_VECTORS_V3_HW : + BASE_VECTORS_V3_HW + i; devm_free_irq(&pdev->dev, pci_irq_vector(pdev, nr), cq); } @@ -5043,9 +5108,11 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) { struct sas_ha_struct *sha = pci_get_drvdata(pdev); struct hisi_hba *hisi_hba = sha->lldd_ha; + struct Scsi_Host *shost = hisi_hba->shost; struct device *dev = hisi_hba->dev; int rc; + wait_event(shost->host_wait, !scsi_host_in_recovery(shost)); dev_info(dev, "FLR prepare\n"); down(&hisi_hba->sem); set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index e021f1106bea..e047747d4ecf 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -231,6 +231,12 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, goto fail; } + if (shost->nr_reserved_cmds && !sht->queue_reserved_command) { + shost_printk(KERN_ERR, shost, + "nr_reserved_cmds set but no method to queue\n"); + goto fail; + } + /* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */ shost->cmd_per_lun = min_t(int, shost->cmd_per_lun, shost->can_queue); @@ -307,6 +313,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, if (error) goto out_del_dev; + if (shost->nr_reserved_cmds) { + shost->pseudo_sdev = scsi_get_pseudo_sdev(shost); + if (!shost->pseudo_sdev) { + error = -ENOMEM; + goto out_del_dev; + } + } + scsi_proc_host_add(shost); scsi_autopm_put_host(shost); return error; @@ -436,6 +450,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv shost->hostt = sht; shost->this_id = sht->this_id; shost->can_queue = sht->can_queue; + shost->nr_reserved_cmds = sht->nr_reserved_cmds; shost->sg_tablesize = sht->sg_tablesize; shost->sg_prot_tablesize = sht->sg_prot_tablesize; shost->cmd_per_lun = sht->cmd_per_lun; @@ -473,10 +488,17 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv else shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; - if (sht->max_segment_size) - shost->max_segment_size = sht->max_segment_size; - else - shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; + shost->virt_boundary_mask = sht->virt_boundary_mask; + if (shost->virt_boundary_mask) { + WARN_ON_ONCE(sht->max_segment_size && + sht->max_segment_size != UINT_MAX); + shost->max_segment_size = UINT_MAX; + } else { + if (sht->max_segment_size) + shost->max_segment_size = sht->max_segment_size; + else + shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; + } /* 32-byte (dword) is a common minimum for HBAs. */ if (sht->dma_alignment) @@ -492,9 +514,6 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv else shost->dma_boundary = 0xffffffff; - if (sht->virt_boundary_mask) - shost->virt_boundary_mask = sht->virt_boundary_mask; - device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); shost->shost_gendev.bus = &scsi_bus_type; @@ -600,8 +619,8 @@ static bool scsi_host_check_in_flight(struct request *rq, void *data) } /** - * scsi_host_busy - Return the host busy counter - * @shost: Pointer to Scsi_Host to inc. + * scsi_host_busy - Return the count of in-flight commands + * @shost: Pointer to Scsi_Host **/ int scsi_host_busy(struct Scsi_Host *shost) { diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 84d8de07b7ae..a1b116cd4723 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -276,7 +276,8 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) #define HPSA_SIMPLE_ERROR_BITS 0x03 -static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); @@ -453,17 +454,13 @@ static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int status, len; + int status; struct ctlr_info *h; struct Scsi_Host *shost = class_to_shost(dev); - char tmpbuf[10]; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; - strncpy(tmpbuf, buf, len); - tmpbuf[len] = '\0'; - if (sscanf(tmpbuf, "%d", &status) != 1) + if (kstrtoint(buf, 10, &status)) return -EINVAL; h = shost_to_hba(shost); h->acciopath_status = !!status; @@ -477,17 +474,13 @@ static ssize_t host_store_raid_offload_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int debug_level, len; + int debug_level; struct ctlr_info *h; struct Scsi_Host *shost = class_to_shost(dev); - char tmpbuf[10]; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; - strncpy(tmpbuf, buf, len); - tmpbuf[len] = '\0'; - if (sscanf(tmpbuf, "%d", &debug_level) != 1) + if (kstrtoint(buf, 10, &debug_level)) return -EINVAL; if (debug_level < 0) debug_level = 0; @@ -1604,7 +1597,7 @@ static void hpsa_monitor_offline_device(struct ctlr_info *h, spin_unlock_irqrestore(&h->offline_device_lock, flags); /* Device is not on the list, add it. */ - device = kmalloc(sizeof(*device), GFP_KERNEL); + device = kmalloc_obj(*device); if (!device) return; @@ -1943,8 +1936,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, } spin_unlock_irqrestore(&h->reset_lock, flags); - added = kcalloc(HPSA_MAX_DEVICES, sizeof(*added), GFP_KERNEL); - removed = kcalloc(HPSA_MAX_DEVICES, sizeof(*removed), GFP_KERNEL); + added = kzalloc_objs(*added, HPSA_MAX_DEVICES); + removed = kzalloc_objs(*removed, HPSA_MAX_DEVICES); if (!added || !removed) { dev_warn(&h->pdev->dev, "out of memory in " @@ -2207,15 +2200,13 @@ static int hpsa_allocate_ioaccel2_sg_chain_blocks(struct ctlr_info *h) return 0; h->ioaccel2_cmd_sg_list = - kcalloc(h->nr_cmds, sizeof(*h->ioaccel2_cmd_sg_list), - GFP_KERNEL); + kzalloc_objs(*h->ioaccel2_cmd_sg_list, h->nr_cmds); if (!h->ioaccel2_cmd_sg_list) return -ENOMEM; for (i = 0; i < h->nr_cmds; i++) { h->ioaccel2_cmd_sg_list[i] = - kmalloc_array(h->maxsgentries, - sizeof(*h->ioaccel2_cmd_sg_list[i]), - GFP_KERNEL); + kmalloc_objs(*h->ioaccel2_cmd_sg_list[i], + h->maxsgentries); if (!h->ioaccel2_cmd_sg_list[i]) goto clean; } @@ -2247,15 +2238,13 @@ static int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h) if (h->chainsize <= 0) return 0; - h->cmd_sg_list = kcalloc(h->nr_cmds, sizeof(*h->cmd_sg_list), - GFP_KERNEL); + h->cmd_sg_list = kzalloc_objs(*h->cmd_sg_list, h->nr_cmds); if (!h->cmd_sg_list) return -ENOMEM; for (i = 0; i < h->nr_cmds; i++) { - h->cmd_sg_list[i] = kmalloc_array(h->chainsize, - sizeof(*h->cmd_sg_list[i]), - GFP_KERNEL); + h->cmd_sg_list[i] = kmalloc_objs(*h->cmd_sg_list[i], + h->chainsize); if (!h->cmd_sg_list[i]) goto clean; @@ -2670,10 +2659,8 @@ static void complete_scsi_command(struct CommandList *cp) case CMD_TARGET_STATUS: cmd->result |= ei->ScsiStatus; /* copy the sense data */ - if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) - sense_data_size = SCSI_SENSE_BUFFERSIZE; - else - sense_data_size = sizeof(ei->SenseInfo); + sense_data_size = min_t(unsigned long, SCSI_SENSE_BUFFERSIZE, + sizeof(ei->SenseInfo)); if (ei->SenseLen < sense_data_size) sense_data_size = ei->SenseLen; memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); @@ -3478,11 +3465,11 @@ static void hpsa_get_enclosure_info(struct ctlr_info *h, goto out; } - bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL); + bssbp = kzalloc_obj(*bssbp); if (!bssbp) goto out; - id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); + id_phys = kzalloc_obj(*id_phys); if (!id_phys) goto out; @@ -3543,7 +3530,7 @@ static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, u64 sa = 0; int i; - physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); + physdev = kzalloc_obj(*physdev); if (!physdev) return 0; @@ -3574,7 +3561,7 @@ static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, if (is_hba_lunid(scsi3addr)) { struct bmic_sense_subsystem_info *ssi; - ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + ssi = kzalloc_obj(*ssi); if (!ssi) return; @@ -3636,10 +3623,7 @@ static bool hpsa_vpd_page_supported(struct ctlr_info *h, if (rc != 0) goto exit_unsupported; pages = buf[3]; - if ((pages + HPSA_VPD_HEADER_SZ) <= 255) - bufsize = pages + HPSA_VPD_HEADER_SZ; - else - bufsize = 255; + bufsize = min(pages + HPSA_VPD_HEADER_SZ, 255); /* Get the whole VPD page list */ rc = hpsa_scsi_do_inquiry(h, scsi3addr, @@ -3801,7 +3785,7 @@ static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, return rc; /* REPORT PHYS EXTENDED is not supported */ - lbuf = kzalloc(sizeof(*lbuf), GFP_KERNEL); + lbuf = kzalloc_obj(*lbuf); if (!lbuf) return -ENOMEM; @@ -4272,7 +4256,7 @@ static bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes) bool is_spare = false; int rc; - id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); + id_phys = kzalloc_obj(*id_phys); if (!id_phys) return false; @@ -4357,12 +4341,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) int raid_ctlr_position; bool physical_device; - currentsd = kcalloc(HPSA_MAX_DEVICES, sizeof(*currentsd), GFP_KERNEL); - physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); - logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); - tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); - id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); - id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL); + currentsd = kzalloc_objs(*currentsd, HPSA_MAX_DEVICES); + physdev_list = kzalloc_obj(*physdev_list); + logdev_list = kzalloc_obj(*logdev_list); + tmpdevice = kzalloc_obj(*tmpdevice); + id_phys = kzalloc_obj(*id_phys); + id_ctlr = kzalloc_obj(*id_ctlr); if (!currentsd || !physdev_list || !logdev_list || !tmpdevice || !id_phys || !id_ctlr) { @@ -4402,7 +4386,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) break; } - currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL); + currentsd[i] = kzalloc_obj(*currentsd[i]); if (!currentsd[i]) { h->drv_req_rescan = 1; goto out; @@ -5680,7 +5664,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) } /* Running in struct Scsi_Host->host_lock less mode */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; @@ -6415,18 +6400,14 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, return -EINVAL; } if (iocommand->buf_size > 0) { - buff = kmalloc(iocommand->buf_size, GFP_KERNEL); - if (buff == NULL) - return -ENOMEM; if (iocommand->Request.Type.Direction & XFER_WRITE) { - /* Copy the data into the buffer we created */ - if (copy_from_user(buff, iocommand->buf, - iocommand->buf_size)) { - rc = -EFAULT; - goto out_kfree; - } + buff = memdup_user(iocommand->buf, iocommand->buf_size); + if (IS_ERR(buff)) + return PTR_ERR(buff); } else { - memset(buff, 0, iocommand->buf_size); + buff = kzalloc(iocommand->buf_size, GFP_KERNEL); + if (!buff) + return -ENOMEM; } } c = cmd_alloc(h); @@ -6486,7 +6467,6 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, } out: cmd_free(h, c); -out_kfree: kfree(buff); return rc; } @@ -6520,7 +6500,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, status = -ENOMEM; goto cleanup1; } - buff_size = kmalloc_array(SG_ENTRIES_IN_CMD, sizeof(int), GFP_KERNEL); + buff_size = kmalloc_objs(int, SG_ENTRIES_IN_CMD); if (!buff_size) { status = -ENOMEM; goto cleanup1; @@ -6530,18 +6510,21 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, while (left) { sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; buff_size[sg_used] = sz; - buff[sg_used] = kmalloc(sz, GFP_KERNEL); - if (buff[sg_used] == NULL) { - status = -ENOMEM; - goto cleanup1; - } + if (ioc->Request.Type.Direction & XFER_WRITE) { - if (copy_from_user(buff[sg_used], data_ptr, sz)) { - status = -EFAULT; + buff[sg_used] = memdup_user(data_ptr, sz); + if (IS_ERR(buff[sg_used])) { + status = PTR_ERR(buff[sg_used]); goto cleanup1; } - } else - memset(buff[sg_used], 0, sz); + } else { + buff[sg_used] = kzalloc(sz, GFP_KERNEL); + if (!buff[sg_used]) { + status = -ENOMEM; + goto cleanup1; + } + } + left -= sz; data_ptr += sz; sg_used++; @@ -7238,8 +7221,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, static void init_driver_version(char *driver_version, int len) { - memset(driver_version, 0, len); - strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1); + strscpy_pad(driver_version, HPSA " " HPSA_DRIVER_VERSION, len); } static int write_driver_ver_to_cfgtable(struct CfgTable __iomem *cfgtable) @@ -7641,8 +7623,8 @@ static void hpsa_free_cfgtables(struct ctlr_info *h) } /* Find and map CISS config table and transfer table -+ * several items must be unmapped (freed) later -+ * */ + * several items must be unmapped (freed) later + */ static int hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; @@ -8508,7 +8490,7 @@ static int hpsa_luns_changed(struct ctlr_info *h) if (!h->lastlogicals) return rc; - logdev = kzalloc(sizeof(*logdev), GFP_KERNEL); + logdev = kzalloc_obj(*logdev); if (!logdev) return rc; @@ -8649,7 +8631,7 @@ static struct ctlr_info *hpda_alloc_ctlr_info(void) { struct ctlr_info *h; - h = kzalloc(sizeof(*h), GFP_KERNEL); + h = kzalloc_obj(*h); if (!h) return NULL; @@ -8870,7 +8852,7 @@ reinit_after_soft_reset: hpsa_hba_inquiry(h); - h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL); + h->lastlogicals = kzalloc_obj(*(h->lastlogicals)); if (!h->lastlogicals) dev_info(&h->pdev->dev, "Can't track change to report lun data\n"); @@ -8974,7 +8956,7 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) if (unlikely(h->lockup_detected)) return; - options = kzalloc(sizeof(*options), GFP_KERNEL); + options = kzalloc_obj(*options); if (!options) return; @@ -9571,7 +9553,7 @@ static struct hpsa_sas_phy *hpsa_alloc_sas_phy( struct hpsa_sas_phy *hpsa_sas_phy; struct sas_phy *phy; - hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL); + hpsa_sas_phy = kzalloc_obj(*hpsa_sas_phy); if (!hpsa_sas_phy) return NULL; @@ -9656,7 +9638,7 @@ static struct hpsa_sas_port struct hpsa_sas_port *hpsa_sas_port; struct sas_port *port; - hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL); + hpsa_sas_port = kzalloc_obj(*hpsa_sas_port); if (!hpsa_sas_port) return NULL; @@ -9704,7 +9686,7 @@ static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev) { struct hpsa_sas_node *hpsa_sas_node; - hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL); + hpsa_sas_node = kzalloc_obj(*hpsa_sas_node); if (hpsa_sas_node) { hpsa_sas_node->parent_dev = parent_dev; INIT_LIST_HEAD(&hpsa_sas_node->port_list_head); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 99b0750850b2..f6bfe75dd696 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -164,7 +164,7 @@ struct bmic_controller_parameters { struct ctlr_info { unsigned int *reply_map; int ctlr; - char devname[8]; + char devname[16]; char *product_name; struct pci_dev *pdev; u32 board_id; @@ -255,7 +255,7 @@ struct ctlr_info { int remove_in_progress; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; - char intrname[MAX_REPLY_QUEUES][16]; /* "hpsa0-msix00" names */ + char intrname[MAX_REPLY_QUEUES][32]; /* controller and IRQ names */ u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ #define HPSATMF_BITS_SUPPORTED (1 << 0) #define HPSATMF_PHYS_LUN_RESET (1 << 1) diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 21f1d9871a33..7083c14c5302 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -993,7 +993,7 @@ static int hptiop_reset_comm_mvfrey(struct hptiop_hba *hba) return 0; } -static int hptiop_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status hptiop_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *host = scp->device->host; struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 773ec2f31bc4..3dd2adda195e 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -797,7 +797,7 @@ static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost, return 0; pool->size = queue->total_depth; - pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); + pool->events = kzalloc_objs(*pool->events, pool->size); if (!pool->events) return -ENOMEM; @@ -1110,7 +1110,7 @@ static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code) } else evt->xfer_iu->mad_common.status = cpu_to_be16(IBMVFC_MAD_DRIVER_FAILED); - del_timer(&evt->timer); + timer_delete(&evt->timer); } /** @@ -1697,7 +1697,7 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, **/ static void ibmvfc_timeout(struct timer_list *t) { - struct ibmvfc_event *evt = from_timer(evt, t, timer); + struct ibmvfc_event *evt = timer_container_of(evt, t, timer); struct ibmvfc_host *vhost = evt->vhost; dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); ibmvfc_reset_host(vhost); @@ -1754,7 +1754,7 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt, atomic_set(&evt->active, 0); list_del(&evt->queue_list); spin_unlock_irqrestore(&evt->queue->l_lock, flags); - del_timer(&evt->timer); + timer_delete(&evt->timer); /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. * Firmware will send a CRQ with a transport event (0xFF) to @@ -1960,7 +1960,8 @@ static struct ibmvfc_cmd *ibmvfc_init_vfc_cmd(struct ibmvfc_event *evt, struct s * Returns: * 0 on success / other on failure **/ -static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct ibmvfc_host *vhost = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); @@ -3670,7 +3671,7 @@ static const struct bin_attribute ibmvfc_trace_attr = { .mode = S_IRUGO, }, .size = 0, - .read_new = ibmvfc_read_trace, + .read = ibmvfc_read_trace, }; #endif @@ -3832,7 +3833,7 @@ static void ibmvfc_tasklet(void *data) spin_unlock_irqrestore(vhost->host->host_lock, flags); list_for_each_entry_safe(evt, temp, &evt_doneq, queue_list) { - del_timer(&evt->timer); + timer_delete(&evt->timer); list_del(&evt->queue_list); ibmvfc_trc_end(evt); evt->done(evt); @@ -3938,7 +3939,7 @@ static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq) spin_unlock_irqrestore(scrq->q_lock, flags); list_for_each_entry_safe(evt, temp, &evt_doneq, queue_list) { - del_timer(&evt->timer); + timer_delete(&evt->timer); list_del(&evt->queue_list); ibmvfc_trc_end(evt); evt->done(evt); @@ -4542,7 +4543,7 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - del_timer(&tgt->timer); + timer_delete(&tgt->timer); switch (status) { case IBMVFC_MAD_SUCCESS: @@ -4630,7 +4631,7 @@ static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt) **/ static void ibmvfc_adisc_timeout(struct timer_list *t) { - struct ibmvfc_target *tgt = from_timer(tgt, t, timer); + struct ibmvfc_target *tgt = timer_container_of(tgt, t, timer); struct ibmvfc_host *vhost = tgt->vhost; struct ibmvfc_event *evt; struct ibmvfc_tmf *tmf; @@ -4741,7 +4742,7 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); if (ibmvfc_send_event(evt, vhost, IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT)) { vhost->discovery_threads--; - del_timer(&tgt->timer); + timer_delete(&tgt->timer); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); kref_put(&tgt->kref, ibmvfc_release_tgt); } else @@ -4965,7 +4966,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) switch (mad_status) { case IBMVFC_MAD_SUCCESS: ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); - vhost->num_targets = be32_to_cpu(rsp->num_written); + vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written), + max_targets); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); break; case IBMVFC_MAD_FAILED: @@ -5519,7 +5521,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); spin_unlock_irqrestore(vhost->host->host_lock, flags); fc_remote_port_delete(rport); - del_timer_sync(&tgt->timer); + timer_delete_sync(&tgt->timer); kref_put(&tgt->kref, ibmvfc_release_tgt); return; } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) { @@ -5672,7 +5674,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) spin_unlock_irqrestore(vhost->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); - del_timer_sync(&tgt->timer); + timer_delete_sync(&tgt->timer); kref_put(&tgt->kref, ibmvfc_release_tgt); return; } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) { @@ -6056,9 +6058,7 @@ static int ibmvfc_alloc_channels(struct ibmvfc_host *vhost, int i, j; int rc = 0; - channels->scrqs = kcalloc(channels->max_queues, - sizeof(*channels->scrqs), - GFP_KERNEL); + channels->scrqs = kzalloc_objs(*channels->scrqs, channels->max_queues); if (!channels->scrqs) return -ENOMEM; @@ -6210,8 +6210,8 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) if (ibmvfc_alloc_disc_buf(dev, &vhost->scsi_scrqs)) goto free_login_buffer; - vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, - sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); + vhost->trace = kzalloc_objs(struct ibmvfc_trace_entry, + IBMVFC_NUM_TRACE_ENTRIES); atomic_set(&vhost->trace_index, -1); if (!vhost->trace) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 16a1aac11911..609bda730b3a 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -447,7 +447,7 @@ static int initialize_event_pool(struct event_pool *pool, pool->size = size; pool->next = 0; - pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); + pool->events = kzalloc_objs(*pool->events, pool->size); if (!pool->events) return -ENOMEM; @@ -789,7 +789,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code) while (!list_empty(&hostdata->sent)) { evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list); list_del(&evt->list); - del_timer(&evt->timer); + timer_delete(&evt->timer); spin_unlock_irqrestore(hostdata->host->host_lock, flags); if (evt->cmnd) { @@ -845,7 +845,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) */ static void ibmvscsi_timeout(struct timer_list *t) { - struct srp_event_struct *evt_struct = from_timer(evt_struct, t, timer); + struct srp_event_struct *evt_struct = timer_container_of(evt_struct, + t, timer); struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n", @@ -867,9 +868,10 @@ static void ibmvscsi_timeout(struct timer_list *t) * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) * Note that this routine assumes that host_lock is held for synchronization */ -static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, - struct ibmvscsi_host_data *hostdata, - unsigned long timeout) +static enum scsi_qc_status +ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, + struct ibmvscsi_host_data *hostdata, + unsigned long timeout) { __be64 *crq_as_u64 = (__be64 *)&evt_struct->crq; int request_status = 0; @@ -944,7 +946,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, be64_to_cpu(crq_as_u64[1])); if (rc != 0) { list_del(&evt_struct->list); - del_timer(&evt_struct->timer); + timer_delete(&evt_struct->timer); /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. * Firmware will send a CRQ with a transport event (0xFF) to @@ -1039,7 +1041,7 @@ static inline u16 lun_from_dev(struct scsi_device *dev) * @cmnd: struct scsi_cmnd to be executed * @done: Callback function to be called when cmd is completed */ -static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct srp_cmd *srp_cmd; @@ -1840,7 +1842,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, atomic_add(be32_to_cpu(evt_struct->xfer_iu->srp.rsp.req_lim_delta), &hostdata->request_limit); - del_timer(&evt_struct->timer); + timer_delete(&evt_struct->timer); if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd) evt_struct->cmnd->result = DID_ERROR << 16; diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 16d085d56e9d..61f682800765 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -425,7 +425,7 @@ static void ibmvscsis_disconnect(struct work_struct *work) /* * check which state we are in and see if we - * should transitition to the new state + * should transition to the new state */ switch (vscsi->state) { /* Should never be called while in this state. */ @@ -2214,7 +2214,7 @@ static int ibmvscsis_make_nexus(struct ibmvscsis_tport *tport) return 0; } - nexus = kzalloc(sizeof(*nexus), GFP_KERNEL); + nexus = kzalloc_obj(*nexus); if (!nexus) { dev_err(&vscsi->dev, "Unable to allocate struct ibmvscsis_nexus\n"); return -ENOMEM; @@ -2922,9 +2922,7 @@ static long ibmvscsis_alloctimer(struct scsi_info *vscsi) struct timer_cb *p_timer; p_timer = &vscsi->rsp_q_timer; - hrtimer_init(&p_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - - p_timer->timer.function = ibmvscsis_service_wait_q; + hrtimer_setup(&p_timer->timer, ibmvscsis_service_wait_q, CLOCK_MONOTONIC, HRTIMER_MODE_REL); p_timer->started = false; p_timer->timer_pops = 0; @@ -3426,7 +3424,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev, int rc = 0; long hrc = 0; - vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL); + vscsi = kzalloc_obj(*vscsi); if (!vscsi) { rc = -ENOMEM; dev_err(&vdev->dev, "probe: allocation of adapter failed\n"); @@ -3535,7 +3533,8 @@ static int ibmvscsis_probe(struct vio_dev *vdev, init_completion(&vscsi->wait_idle); init_completion(&vscsi->unconfig); - vscsi->work_q = alloc_workqueue("ibmvscsis%s", WQ_MEM_RECLAIM, 1, + vscsi->work_q = alloc_workqueue("ibmvscsis%s", + WQ_MEM_RECLAIM | WQ_PERCPU, 1, dev_name(&vdev->dev)); if (!vscsi->work_q) { rc = -ENOMEM; @@ -3969,6 +3968,7 @@ static const struct target_core_fabric_ops ibmvscsis_ops = { .tfc_wwn_attrs = ibmvscsis_wwn_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.c b/drivers/scsi/ibmvscsi_tgt/libsrp.c index 8a0e28aec928..eef9e452ece5 100644 --- a/drivers/scsi/ibmvscsi_tgt/libsrp.c +++ b/drivers/scsi/ibmvscsi_tgt/libsrp.c @@ -27,10 +27,10 @@ static int srp_iu_pool_alloc(struct srp_queue *q, size_t max, struct iu_entry *iue; int i; - q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL); + q->pool = kzalloc_objs(struct iu_entry *, max); if (!q->pool) return -ENOMEM; - q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL); + q->items = kzalloc_objs(struct iu_entry, max); if (!q->items) goto free_pool; @@ -61,12 +61,12 @@ static struct srp_buf **srp_ring_alloc(struct device *dev, struct srp_buf **ring; int i; - ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL); + ring = kzalloc_objs(struct srp_buf *, max); if (!ring) return NULL; for (i = 0; i < max; i++) { - ring[i] = kzalloc(sizeof(*ring[i]), GFP_KERNEL); + ring[i] = kzalloc_obj(*ring[i]); if (!ring[i]) goto out; ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma, @@ -184,7 +184,8 @@ static int srp_direct_data(struct ibmvscsis_cmd *cmd, struct srp_direct_buf *md, err = rdma_io(cmd, sg, nsg, md, 1, dir, len); if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + dma_unmap_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents, + DMA_BIDIRECTIONAL); return err; } @@ -256,7 +257,8 @@ rdma: err = rdma_io(cmd, sg, nsg, md, nmd, dir, len); if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + dma_unmap_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents, + DMA_BIDIRECTIONAL); free_mem: if (token && dma_map) { diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 1d4c7310f1a6..0535252e77e3 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -925,7 +925,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *const cmd) return 0; } -static int imm_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status imm_queuecommand_lck(struct scsi_cmnd *cmd) { imm_struct *dev = imm_dev(cmd->device->host); @@ -954,7 +954,7 @@ static DEF_SCSI_QCMD(imm_queuecommand) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -static int imm_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int imm_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { ip[0] = 0x40; @@ -1158,7 +1158,7 @@ static int __imm_attach(struct parport *pb) init_waitqueue_head(&waiting); - dev = kzalloc(sizeof(imm_struct), GFP_KERNEL); + dev = kzalloc_obj(imm_struct); if (!dev) return -ENOMEM; @@ -1224,7 +1224,6 @@ static int __imm_attach(struct parport *pb) host = scsi_host_alloc(&imm_template, sizeof(imm_struct *)); if (!host) goto out1; - host->no_highmem = true; host->io_port = pb->base; host->n_io_port = ports; host->dma_channel = -1; @@ -1261,6 +1260,7 @@ static void imm_detach(struct parport *pb) imm_struct *dev; list_for_each_entry(dev, &imm_hosts, list) { if (dev->dev->port == pb) { + disable_delayed_work_sync(&dev->imm_tq); list_del_init(&dev->list); scsi_remove_host(dev->host); scsi_host_put(dev->host); diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 8648bd965287..06fbe85dccfa 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2606,7 +2606,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c * zero if successful or indicate a host busy condition if not (which * will cause the mid layer to call us again later with the command) */ -static int i91u_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status i91u_queuecommand_lck(struct scsi_cmnd *cmd) { struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata; struct scsi_ctrl_blk *cmnd; @@ -2645,7 +2645,7 @@ static int i91u_bus_reset(struct scsi_cmnd * cmnd) /** * i91u_biosparam - return the "logical geometry * @sdev: SCSI device - * @dev: Matching block device + * @unused: Matching gendisk * @capacity: Sector size of drive * @info_array: Return space for BIOS geometry * @@ -2655,7 +2655,7 @@ static int i91u_bus_reset(struct scsi_cmnd * cmnd) * FIXME: limited to 2^32 sector devices. */ -static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int i91u_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int *info_array) { struct initio_host *host; /* Point to Host adapter control block */ diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 3bfafd43e42a..d207e5e81afe 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -61,8 +61,8 @@ #include <linux/hdreg.h> #include <linux/reboot.h> #include <linux/stringify.h> +#include <linux/irq.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/processor.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -873,7 +873,7 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); - del_timer(&ipr_cmd->timer); + timer_delete(&ipr_cmd->timer); ipr_cmd->done(ipr_cmd); } spin_unlock(&hrrq->_lock); @@ -2589,7 +2589,7 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) **/ static void ipr_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); unsigned long lock_flags = 0; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; @@ -2622,7 +2622,7 @@ static void ipr_timeout(struct timer_list *t) **/ static void ipr_oper_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); unsigned long lock_flags = 0; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; @@ -3389,7 +3389,7 @@ static const struct bin_attribute ipr_trace_attr = { .mode = S_IRUGO, }, .size = 0, - .read_new = ipr_read_trace, + .read = ipr_read_trace, }; #endif @@ -3776,7 +3776,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) order = get_order(sg_size); /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct ipr_sglist), GFP_KERNEL); + sglist = kzalloc_obj(struct ipr_sglist); if (sglist == NULL) { ipr_trace; return NULL; @@ -4140,8 +4140,8 @@ static const struct bin_attribute ipr_ioa_async_err_log = { .mode = S_IRUGO | S_IWUSR, }, .size = 0, - .read_new = ipr_read_async_err_log, - .write_new = ipr_next_async_err_log + .read = ipr_read_async_err_log, + .write = ipr_next_async_err_log }; static struct attribute *ipr_ioa_attrs[] = { @@ -4273,7 +4273,7 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) __be32 **ioa_data; unsigned long lock_flags = 0; - dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); + dump = kzalloc_obj(struct ipr_dump); if (!dump) { ipr_err("Dump memory allocation failed\n"); @@ -4281,11 +4281,11 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } if (ioa_cfg->sis64) - ioa_data = vmalloc(array_size(IPR_FMT3_MAX_NUM_DUMP_PAGES, - sizeof(__be32 *))); + ioa_data = vmalloc_array(IPR_FMT3_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *)); else - ioa_data = vmalloc(array_size(IPR_FMT2_MAX_NUM_DUMP_PAGES, - sizeof(__be32 *))); + ioa_data = vmalloc_array(IPR_FMT2_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *)); if (!ioa_data) { ipr_err("Dump memory allocation failed\n"); @@ -4391,8 +4391,8 @@ static const struct bin_attribute ipr_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = ipr_read_dump, - .write_new = ipr_write_dump + .read = ipr_read_dump, + .write = ipr_write_dump }; #else static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; @@ -4644,10 +4644,10 @@ ATTRIBUTE_GROUPS(ipr_dev); /** * ipr_biosparam - Return the HSC mapping - * @sdev: scsi device struct - * @block_device: block device pointer + * @sdev: scsi device struct + * @unused: gendisk pointer * @capacity: capacity of the device - * @parm: Array containing returned HSC values. + * @parm: Array containing returned HSC values. * * This function generates the HSC parms that fdisk uses. * We want to make sure we return something that places partitions @@ -4657,7 +4657,7 @@ ATTRIBUTE_GROUPS(ipr_dev); * 0 on success **/ static int ipr_biosparam(struct scsi_device *sdev, - struct block_device *block_device, + struct gendisk *unused, sector_t capacity, int *parm) { int heads, sectors; @@ -5151,7 +5151,7 @@ static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd) **/ static void ipr_abort_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); struct ipr_cmnd *reset_cmd; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ipr_cmd_pkt *cmd_pkt; @@ -5347,7 +5347,7 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); + timer_delete(&ioa_cfg->reset_cmd->timer); ipr_reset_ioa_job(ioa_cfg->reset_cmd); return IRQ_HANDLED; } @@ -5362,7 +5362,7 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); + timer_delete(&ioa_cfg->reset_cmd->timer); ipr_reset_ioa_job(ioa_cfg->reset_cmd); } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) { if (ioa_cfg->clear_isr) { @@ -5481,7 +5481,7 @@ static int ipr_iopoll(struct irq_poll *iop, int budget) list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) { list_del(&ipr_cmd->queue); - del_timer(&ipr_cmd->timer); + timer_delete(&ipr_cmd->timer); ipr_cmd->fast_done(ipr_cmd); } @@ -5550,7 +5550,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) spin_unlock_irqrestore(hrrq->lock, hrrq_flags); list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) { list_del(&ipr_cmd->queue); - del_timer(&ipr_cmd->timer); + timer_delete(&ipr_cmd->timer); ipr_cmd->fast_done(ipr_cmd); } return rc; @@ -5600,7 +5600,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp) list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) { list_del(&ipr_cmd->queue); - del_timer(&ipr_cmd->timer); + timer_delete(&ipr_cmd->timer); ipr_cmd->fast_done(ipr_cmd); } return rc; @@ -6242,8 +6242,8 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy **/ -static int ipr_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status ipr_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scsi_cmd) { struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; @@ -7476,7 +7476,7 @@ static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd) **/ static void ipr_reset_timer_done(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; unsigned long lock_flags = 0; @@ -7844,6 +7844,30 @@ static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) } /** + * ipr_set_affinity_nobalance + * @ioa_cfg: ipr_ioa_cfg struct for an ipr device + * @flag: bool + * true: ensable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ +static void ipr_set_affinity_nobalance(struct ipr_ioa_cfg *ioa_cfg, bool flag) +{ + int irq, i; + + for (i = 0; i < ioa_cfg->nvectors; i++) { + irq = pci_irq_vector(ioa_cfg->pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + +/** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct * @@ -7859,7 +7883,6 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; ENTER; - ioa_cfg->pdev->state_saved = true; pci_restore_state(ioa_cfg->pdev); if (ipr_set_pcix_cmd_reg(ioa_cfg)) { @@ -7867,6 +7890,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_CONTINUE; } + ipr_set_affinity_nobalance(ioa_cfg, false); ipr_fail_all_ops(ioa_cfg); if (ioa_cfg->sis64) { @@ -7946,6 +7970,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc == PCIBIOS_SUCCESSFUL) { + ipr_set_affinity_nobalance(ioa_cfg, true); ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; @@ -8834,8 +8859,9 @@ static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) if (!ioa_cfg->ipr_cmd_pool) return -ENOMEM; - ioa_cfg->ipr_cmnd_list = kcalloc(IPR_NUM_CMD_BLKS, sizeof(struct ipr_cmnd *), GFP_KERNEL); - ioa_cfg->ipr_cmnd_list_dma = kcalloc(IPR_NUM_CMD_BLKS, sizeof(dma_addr_t), GFP_KERNEL); + ioa_cfg->ipr_cmnd_list = kzalloc_objs(struct ipr_cmnd *, + IPR_NUM_CMD_BLKS); + ioa_cfg->ipr_cmnd_list_dma = kzalloc_objs(dma_addr_t, IPR_NUM_CMD_BLKS); if (!ioa_cfg->ipr_cmnd_list || !ioa_cfg->ipr_cmnd_list_dma) { ipr_free_cmd_blks(ioa_cfg); @@ -8938,9 +8964,8 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) int i, rc = -ENOMEM; ENTER; - ioa_cfg->res_entries = kcalloc(ioa_cfg->max_devs_supported, - sizeof(struct ipr_resource_entry), - GFP_KERNEL); + ioa_cfg->res_entries = kzalloc_objs(struct ipr_resource_entry, + ioa_cfg->max_devs_supported); if (!ioa_cfg->res_entries) goto out; @@ -9001,9 +9026,8 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); } - ioa_cfg->trace = kcalloc(IPR_NUM_TRACE_ENTRIES, - sizeof(struct ipr_trace_entry), - GFP_KERNEL); + ioa_cfg->trace = kzalloc_objs(struct ipr_trace_entry, + IPR_NUM_TRACE_ENTRIES); if (!ioa_cfg->trace) goto out_free_hostrcb_dma; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index cce6c6b409ad..41ed73966a48 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -167,6 +167,7 @@ #include <linux/stddef.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/hex.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/slab.h> @@ -230,7 +231,7 @@ module_param(ips, charp, 0); */ static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); -static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status ips_queue(struct Scsi_Host *, struct scsi_cmnd *); static const char *ips_info(struct Scsi_Host *); static irqreturn_t do_ipsintr(int, void *); static int ips_hainit(ips_ha_t *); @@ -1017,7 +1018,7 @@ static int ips_eh_reset(struct scsi_cmnd *SC) /* Linux obtains io_request_lock before calling this function */ /* */ /****************************************************************************/ -static int ips_queue_lck(struct scsi_cmnd *SC) +static enum scsi_qc_status ips_queue_lck(struct scsi_cmnd *SC) { void (*done)(struct scsi_cmnd *) = scsi_done; ips_ha_t *ha; @@ -1085,7 +1086,7 @@ static int ips_queue_lck(struct scsi_cmnd *SC) } /* allocate space for the scribble */ - scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); + scratch = kmalloc_obj(ips_copp_wait_item_t, GFP_ATOMIC); if (!scratch) { SC->result = DID_ERROR << 16; @@ -1123,7 +1124,7 @@ static DEF_SCSI_QCMD(ips_queue) /* Set bios geometry for the controller */ /* */ /****************************************************************************/ -static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int ips_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; @@ -3631,8 +3632,8 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) break; - case RESERVE: - case RELEASE: + case RESERVE_6: + case RELEASE_6: scb->scsi_cmd->result = DID_OK << 16; break; @@ -3899,8 +3900,8 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) case WRITE_6: case READ_10: case WRITE_10: - case RESERVE: - case RELEASE: + case RESERVE_6: + case RELEASE_6: break; case MODE_SENSE: @@ -6873,7 +6874,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) } /* found a controller */ - ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); + ha = kzalloc_obj(ips_ha_t); if (ha == NULL) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate temporary ha struct\n"); @@ -6946,7 +6947,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) ha->logical_drive_info_dma_addr = dma_address; - ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); + ha->conf = kmalloc_obj(IPS_CONF); if (!ha->conf) { IPS_PRINTK(KERN_WARNING, pci_dev, @@ -6954,7 +6955,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) return ips_abort_init(ha, index); } - ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); + ha->nvram = kmalloc_obj(IPS_NVRAM_P5); if (!ha->nvram) { IPS_PRINTK(KERN_WARNING, pci_dev, @@ -6962,7 +6963,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) return ips_abort_init(ha, index); } - ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); + ha->subsys = kmalloc_obj(IPS_SUBSYS); if (!ha->subsys) { IPS_PRINTK(KERN_WARNING, pci_dev, diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 8ac932ec4444..30a4d4a580e9 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -398,7 +398,7 @@ /* * Scsi_Host Template */ - static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, + static int ips_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]); static int ips_sdev_configure(struct scsi_device *SDptr, struct queue_limits *lim); diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 35589b6af90d..ff199bab5d1a 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -958,7 +958,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) static void phy_startup_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), phy_timer); unsigned long flags; enum sci_status status; @@ -1252,6 +1252,9 @@ void isci_host_deinit(struct isci_host *ihost) wait_for_stop(ihost); + /* No further IRQ-driven scheduling can happen past wait_for_stop(). */ + tasklet_kill(&ihost->completion_tasklet); + /* phy stop is after controller stop to allow port and device to * go idle before shutting down the phys, but the expectation is * that i/o has been shut off well before we reach this @@ -1271,22 +1274,22 @@ void isci_host_deinit(struct isci_host *ihost) /* Cancel any/all outstanding port timers */ for (i = 0; i < ihost->logical_port_entries; i++) { struct isci_port *iport = &ihost->ports[i]; - del_timer_sync(&iport->timer.timer); + timer_delete_sync(&iport->timer.timer); } /* Cancel any/all outstanding phy timers */ for (i = 0; i < SCI_MAX_PHYS; i++) { struct isci_phy *iphy = &ihost->phys[i]; - del_timer_sync(&iphy->sata_timer.timer); + timer_delete_sync(&iphy->sata_timer.timer); } - del_timer_sync(&ihost->port_agent.timer.timer); + timer_delete_sync(&ihost->port_agent.timer.timer); - del_timer_sync(&ihost->power_control.timer.timer); + timer_delete_sync(&ihost->power_control.timer.timer); - del_timer_sync(&ihost->timer.timer); + timer_delete_sync(&ihost->timer.timer); - del_timer_sync(&ihost->phy_timer.timer); + timer_delete_sync(&ihost->phy_timer.timer); } static void __iomem *scu_base(struct isci_host *isci_host) @@ -1592,7 +1595,7 @@ static const struct sci_base_state sci_controller_state_table[] = { static void controller_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), timer); struct sci_base_state_machine *sm = &ihost->sm; unsigned long flags; @@ -1737,7 +1740,7 @@ static u8 max_spin_up(struct isci_host *ihost) static void power_control_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), power_control.timer); struct isci_phy *iphy; unsigned long flags; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 73085d2f5c43..acf0c2038d20 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -91,31 +91,31 @@ MODULE_DEVICE_TABLE(pci, isci_id_table); /* linux isci specific settings */ -unsigned char no_outbound_task_to = 2; +static unsigned char no_outbound_task_to = 2; module_param(no_outbound_task_to, byte, 0); MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)"); -u16 ssp_max_occ_to = 20; +static u16 ssp_max_occ_to = 20; module_param(ssp_max_occ_to, ushort, 0); MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)"); -u16 stp_max_occ_to = 5; +static u16 stp_max_occ_to = 5; module_param(stp_max_occ_to, ushort, 0); MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)"); -u16 ssp_inactive_to = 5; +static u16 ssp_inactive_to = 5; module_param(ssp_inactive_to, ushort, 0); MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)"); -u16 stp_inactive_to = 5; +static u16 stp_inactive_to = 5; module_param(stp_inactive_to, ushort, 0); MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)"); -unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; +static unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; module_param(phy_gen, byte, 0); MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); -unsigned char max_concurr_spinup; +static unsigned char max_concurr_spinup; module_param(max_concurr_spinup, byte, 0); MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 4e6b1decbca7..d827e49c1d55 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -473,13 +473,6 @@ static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt) dest[word_cnt] = swab32(src[word_cnt]); } -extern unsigned char no_outbound_task_to; -extern u16 ssp_max_occ_to; -extern u16 stp_max_occ_to; -extern u16 ssp_inactive_to; -extern u16 stp_inactive_to; -extern unsigned char phy_gen; -extern unsigned char max_concurr_spinup; extern uint cable_selection_override; irqreturn_t isci_msix_isr(int vec, void *data); @@ -488,9 +481,9 @@ irqreturn_t isci_error_isr(int vec, void *data); /* * Each timer is associated with a cancellation flag that is set when - * del_timer() is called and checked in the timer callback function. This - * is needed since del_timer_sync() cannot be called with sci_lock held. - * For deinit however, del_timer_sync() is used without holding the lock. + * timer_delete() is called and checked in the timer callback function. This + * is needed since timer_delete_sync() cannot be called with sci_lock held. + * For deinit however, timer_delete_sync() is used without holding the lock. */ struct sci_timer { struct timer_list timer; @@ -513,7 +506,7 @@ static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec) static inline void sci_del_timer(struct sci_timer *tmr) { tmr->cancel = true; - del_timer(&tmr->timer); + timer_delete(&tmr->timer); } struct sci_base_state_machine { diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 743a3c64b0da..88237ec8b15f 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -317,7 +317,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, static void phy_sata_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer); struct isci_host *ihost = iphy->owning_port->owning_controller; unsigned long flags; diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 1609aba1c9c1..10bd2aac2cb4 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -775,7 +775,7 @@ bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy) static void port_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_port *iport = container_of(tmr, typeof(*iport), timer); struct isci_host *ihost = iport->owning_controller; unsigned long flags; diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index c382a257b51b..3b4820defe63 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -321,7 +321,7 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, static void mpc_agent_timeout(struct timer_list *t) { u8 index; - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct sci_port_configuration_agent *port_agent; struct isci_host *ihost; unsigned long flags; @@ -659,7 +659,7 @@ static void sci_apc_agent_link_down( static void apc_agent_timeout(struct timer_list *t) { u32 index; - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct sci_port_configuration_agent *port_agent; struct isci_host *ihost; unsigned long flags; diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 287e1ba8ddd7..4c7462965ea1 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -392,36 +392,6 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, } } -enum sci_status sci_remote_device_reset(struct isci_remote_device *idev) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_SMP_DEV_IDLE: - case SCI_SMP_DEV_CMD: - case SCI_DEV_STOPPING: - case SCI_DEV_FAILED: - case SCI_DEV_RESETTING: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_READY: - case SCI_STP_DEV_IDLE: - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - sci_change_state(sm, SCI_DEV_RESETTING); - return SCI_SUCCESS; - } -} - enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, u32 frame_index) { @@ -1464,7 +1434,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, struct domain_device *dev = idev->domain_dev; enum sci_status status; - if (dev->parent && dev_is_expander(dev->parent->dev_type)) + if (dev_parent_is_expander(dev)) status = sci_remote_device_ea_construct(iport, idev); else status = sci_remote_device_da_construct(iport, idev); diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index 27ae45332704..c1fdf45751cd 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h @@ -160,21 +160,6 @@ enum sci_status sci_remote_device_stop( u32 timeout); /** - * sci_remote_device_reset() - This method will reset the device making it - * ready for operation. This method must be called anytime the device is - * reset either through a SMP phy control or a port hard reset request. - * @remote_device: This parameter specifies the device to be reset. - * - * This method does not actually cause the device hardware to be reset. This - * method resets the software object so that it will be operational after a - * device hardware reset completes. An indication of whether the device reset - * was accepted. SCI_SUCCESS This value is returned if the device reset is - * started. - */ -enum sci_status sci_remote_device_reset( - struct isci_remote_device *idev); - -/** * enum sci_remote_device_states - This enumeration depicts all the states * for the common remote device state machine. * @SCI_DEV_INITIAL: Simply the initial state for the base remote device @@ -198,7 +183,7 @@ enum sci_status sci_remote_device_reset( * device. When there are no active IO for the device it is is in this * state. * - * @SCI_STP_DEV_CMD: This is the command state for for the STP remote + * @SCI_STP_DEV_CMD: This is the command state for the STP remote * device. This state is entered when the device is processing a * non-NCQ command. The device object will fail any new start IO * requests until this command is complete. diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 355a0bc0828e..bb89a2e33eb4 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -2904,7 +2904,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost, task->total_xfer_len, task->data_dir); else /* unmap the sgl dma addresses */ dma_unmap_sg(&ihost->pdev->dev, task->scatter, - request->num_sg_entries, task->data_dir); + task->num_scatter, task->data_dir); break; case SAS_PROTOCOL_SMP: { struct scatterlist *sg = &task->smp_task.smp_req; diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index f96633fa6939..d05d09c1263d 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -85,15 +85,17 @@ struct isci_tmf { struct completion *complete; enum sas_protocol proto; + unsigned char lun[8]; + u16 io_tag; + enum isci_tmf_function_codes tmf_code; + int status; + + /* Must be last --ends in a flexible-array member. */ union { struct ssp_response_iu resp_iu; struct dev_to_host_fis d2h_fis; u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; } resp; - unsigned char lun[8]; - u16 io_tag; - enum isci_tmf_function_codes tmf_code; - int status; }; static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index a64abe38db2d..0b22197bf8f5 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -344,7 +344,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, { struct iscsi_boot_kobj *boot_kobj; - boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); + boot_kobj = kzalloc_obj(*boot_kobj); if (!boot_kobj) return NULL; INIT_LIST_HEAD(&boot_kobj->list); @@ -497,7 +497,7 @@ struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) { struct iscsi_boot_kset *boot_kset; - boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); + boot_kset = kzalloc_obj(*boot_kset); if (!boot_kset) return NULL; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index e81f60985193..9260b1c9b0e0 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -17,7 +17,6 @@ * Zhenyu Wang */ -#include <crypto/hash.h> #include <linux/types.h> #include <linux/inet.h> #include <linux/slab.h> @@ -268,7 +267,7 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn) struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct sock *sk = tcp_sw_conn->sock->sk; - /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ + /* restore socket callbacks, see also: iscsi_sw_tcp_conn_set_callbacks() */ write_lock_bh(&sk->sk_callback_lock); sk->sk_user_data = NULL; sk->sk_data_ready = tcp_sw_conn->old_data_ready; @@ -468,8 +467,7 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, * sufficient room. */ if (conn->hdrdgst_en) { - iscsi_tcp_dgst_header(tcp_sw_conn->tx_hash, hdr, hdrlen, - hdr + hdrlen); + iscsi_tcp_dgst_header(hdr, hdrlen, hdr + hdrlen); hdrlen += ISCSI_DIGEST_SIZE; } @@ -494,7 +492,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct ahash_request *tx_hash = NULL; + u32 *tx_crcp = NULL; unsigned int hdr_spec_len; ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len, @@ -507,11 +505,10 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); if (conn->datadgst_en) - tx_hash = tcp_sw_conn->tx_hash; + tx_crcp = &tcp_sw_conn->tx_crc; return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment, - sg, count, offset, len, - NULL, tx_hash); + sg, count, offset, len, NULL, tx_crcp); } static void @@ -520,7 +517,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct ahash_request *tx_hash = NULL; + u32 *tx_crcp = NULL; unsigned int hdr_spec_len; ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ? @@ -532,10 +529,10 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); if (conn->datadgst_en) - tx_hash = tcp_sw_conn->tx_hash; + tx_crcp = &tcp_sw_conn->tx_crc; iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment, - data, len, NULL, tx_hash); + data, len, NULL, tx_crcp); } static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task, @@ -583,7 +580,6 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_sw_tcp_conn *tcp_sw_conn; - struct crypto_ahash *tfm; cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn), conn_idx); @@ -596,37 +592,9 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, tcp_sw_conn->queue_recv = iscsi_recv_from_iscsi_q; mutex_init(&tcp_sw_conn->sock_lock); - - tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) - goto free_conn; - - tcp_sw_conn->tx_hash = ahash_request_alloc(tfm, GFP_KERNEL); - if (!tcp_sw_conn->tx_hash) - goto free_tfm; - ahash_request_set_callback(tcp_sw_conn->tx_hash, 0, NULL, NULL); - - tcp_sw_conn->rx_hash = ahash_request_alloc(tfm, GFP_KERNEL); - if (!tcp_sw_conn->rx_hash) - goto free_tx_hash; - ahash_request_set_callback(tcp_sw_conn->rx_hash, 0, NULL, NULL); - - tcp_conn->rx_hash = tcp_sw_conn->rx_hash; + tcp_conn->rx_crcp = &tcp_sw_conn->rx_crc; return cls_conn; - -free_tx_hash: - ahash_request_free(tcp_sw_conn->tx_hash); -free_tfm: - crypto_free_ahash(tfm); -free_conn: - iscsi_conn_printk(KERN_ERR, conn, - "Could not create connection due to crc32c " - "loading error. Make sure the crc32c " - "module is built as a module or into the " - "kernel\n"); - iscsi_tcp_conn_teardown(cls_conn); - return NULL; } static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) @@ -664,20 +632,8 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) { struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; iscsi_sw_tcp_release_conn(conn); - - ahash_request_free(tcp_sw_conn->rx_hash); - if (tcp_sw_conn->tx_hash) { - struct crypto_ahash *tfm; - - tfm = crypto_ahash_reqtfm(tcp_sw_conn->tx_hash); - ahash_request_free(tcp_sw_conn->tx_hash); - crypto_free_ahash(tfm); - } - iscsi_tcp_conn_teardown(cls_conn); } diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 89a6fc552f0b..c3e5d9fa6add 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -41,8 +41,8 @@ struct iscsi_sw_tcp_conn { void (*old_write_space)(struct sock *); /* data and header digests */ - struct ahash_request *tx_hash; /* CRC32C (Tx) */ - struct ahash_request *rx_hash; /* CRC32C (Rx) */ + u32 tx_crc; /* CRC32C (Tx) */ + u32 rx_crc; /* CRC32C (Rx) */ /* MIB custom statistics */ uint32_t sendpage_failures_cnt; diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 86fe19e0468d..6d1fb55cc3ad 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -88,7 +88,7 @@ lasi700_probe(struct parisc_device *dev) struct NCR_700_Host_Parameters *hostdata; struct Scsi_Host *host; - hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); + hostdata = kzalloc_obj(*hostdata); if (!hostdata) { dev_printk(KERN_ERR, &dev->dev, "Failed to allocate host data\n"); return -ENOMEM; diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 60d621ad0024..7792724d5b97 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -116,7 +116,7 @@ static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) case ELS_ADDR_FMT_PORT: FC_DISC_DBG(disc, "Port address format for port " "(%6.6x)\n", ntoh24(pp->rscn_fid)); - dp = kzalloc(sizeof(*dp), GFP_KERNEL); + dp = kzalloc_obj(*dp); if (!dp) { redisc = 1; break; diff --git a/drivers/scsi/libfc/fc_encode.h b/drivers/scsi/libfc/fc_encode.h index 02e31db31d68..e046091a549a 100644 --- a/drivers/scsi/libfc/fc_encode.h +++ b/drivers/scsi/libfc/fc_encode.h @@ -356,7 +356,7 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport, put_unaligned_be16(len, &entry->len); snprintf((char *)&entry->value, FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN, - "%s v%s", + "%.62s v%.62s", init_utsname()->sysname, init_utsname()->release); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index f84a7e6ae379..9183a0e9568a 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2391,7 +2391,7 @@ struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, { struct fc_exch_mgr_anchor *ema; - ema = kmalloc(sizeof(*ema), GFP_ATOMIC); + ema = kmalloc_obj(*ema, GFP_ATOMIC); if (!ema) return ema; @@ -2480,7 +2480,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport, /* * allocate memory for EM */ - mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC); + mp = kzalloc_obj(struct fc_exch_mgr, GFP_ATOMIC); if (!mp) return NULL; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index fd1ef06655cb..a5139e43ca4c 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -503,7 +503,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) host_bcode = FC_ERROR; goto err; } - if (offset + len > fsp->data_len) { + if (size_add(offset, len) > fsp->data_len) { /* this should never happen */ if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && fc_frame_crc_check(fp)) @@ -1283,7 +1283,7 @@ static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp) */ static void fc_lun_reset_send(struct timer_list *t) { - struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer); + struct fc_fcp_pkt *fsp = timer_container_of(fsp, t, timer); struct fc_lport *lport = fsp->lp; if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) { @@ -1329,7 +1329,7 @@ static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp, fsp->state |= FC_SRB_COMPL; spin_unlock_bh(&fsp->scsi_pkt_lock); - del_timer_sync(&fsp->timer); + timer_delete_sync(&fsp->timer); spin_lock_bh(&fsp->scsi_pkt_lock); if (fsp->seq_ptr) { @@ -1416,7 +1416,7 @@ static void fc_fcp_cleanup(struct fc_lport *lport) */ static void fc_fcp_timeout(struct timer_list *t) { - struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer); + struct fc_fcp_pkt *fsp = timer_container_of(fsp, t, timer); struct fc_rport *rport = fsp->rport; struct fc_rport_libfc_priv *rpriv = rport->dd_data; @@ -1854,7 +1854,8 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport) * * This is the i/o strategy routine, called by the SCSI layer. */ -int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status fc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); @@ -1961,7 +1962,7 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) fsp->state |= FC_SRB_COMPL; if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { spin_unlock_bh(&fsp->scsi_pkt_lock); - del_timer_sync(&fsp->timer); + timer_delete_sync(&fsp->timer); spin_lock_bh(&fsp->scsi_pkt_lock); } @@ -2297,7 +2298,7 @@ int fc_fcp_init(struct fc_lport *lport) if (!lport->tt.fcp_abort_io) lport->tt.fcp_abort_io = fc_fcp_abort_io; - si = kzalloc(sizeof(struct fc_fcp_internal), GFP_KERNEL); + si = kzalloc_obj(struct fc_fcp_internal); if (!si) return -ENOMEM; lport->scsi_priv = si; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 310fa5add5f0..32683ea6953c 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -2049,7 +2049,7 @@ static int fc_lport_els_request(struct bsg_job *job, fh->fh_df_ctl = 0; fh->fh_parm_offset = 0; - info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); + info = kzalloc_obj(struct fc_bsg_info); if (!info) { fc_frame_free(fp); return -ENOMEM; @@ -2109,7 +2109,7 @@ static int fc_lport_ct_request(struct bsg_job *job, fh->fh_df_ctl = 0; fh->fh_parm_offset = 0; - info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); + info = kzalloc_obj(struct fc_bsg_info); if (!info) { fc_frame_free(fp); return -ENOMEM; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2b1bf990a9dc..25857d6ed6e8 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1747,7 +1747,8 @@ enum { FAILURE_SESSION_NOT_READY, }; -int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) +enum scsi_qc_status iscsi_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc) { struct iscsi_cls_session *cls_session; struct iscsi_host *ihost; @@ -1898,7 +1899,8 @@ EXPORT_SYMBOL_GPL(iscsi_target_alloc); static void iscsi_tmf_timedout(struct timer_list *t) { - struct iscsi_session *session = from_timer(session, t, tmf_timer); + struct iscsi_session *session = timer_container_of(session, t, + tmf_timer); spin_lock(&session->frwd_lock); if (session->tmf_state == TMF_QUEUED) { @@ -1945,7 +1947,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, session->tmf_state != TMF_QUEUED); if (signal_pending(current)) flush_signals(current); - del_timer_sync(&session->tmf_timer); + timer_delete_sync(&session->tmf_timer); mutex_lock(&session->eh_mutex); spin_lock_bh(&session->frwd_lock); @@ -2240,7 +2242,7 @@ EXPORT_SYMBOL_GPL(iscsi_eh_cmd_timed_out); static void iscsi_check_transport_timeouts(struct timer_list *t) { - struct iscsi_conn *conn = from_timer(conn, t, transport_timer); + struct iscsi_conn *conn = timer_container_of(conn, t, transport_timer); struct iscsi_session *session = conn->session; unsigned long recv_timeout, next_timeout = 0, last_recv; @@ -3184,7 +3186,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, return NULL; conn = cls_conn->dd_data; - conn->dd_data = cls_conn->dd_data + sizeof(*conn); + if (dd_size) + conn->dd_data = cls_conn->dd_data + sizeof(*conn); conn->session = session; conn->cls_conn = cls_conn; conn->c_stage = ISCSI_CONN_INITIAL_STAGE; @@ -3247,7 +3250,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) iscsi_remove_conn(cls_conn); - del_timer_sync(&conn->transport_timer); + timer_delete_sync(&conn->transport_timer); mutex_lock(&session->eh_mutex); spin_lock_bh(&session->frwd_lock); @@ -3411,7 +3414,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) conn->stop_stage = flag; spin_unlock_bh(&session->frwd_lock); - del_timer_sync(&conn->transport_timer); + timer_delete_sync(&conn->transport_timer); iscsi_suspend_tx(conn); spin_lock_bh(&session->frwd_lock); diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index c182aa83f2c9..e90805ba868f 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -15,7 +15,7 @@ * Zhenyu Wang */ -#include <crypto/hash.h> +#include <linux/crc32c.h> #include <linux/types.h> #include <linux/list.h> #include <linux/inet.h> @@ -168,7 +168,7 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) segment->size = ISCSI_DIGEST_SIZE; segment->copied = 0; segment->sg = NULL; - segment->hash = NULL; + segment->crcp = NULL; } /** @@ -191,29 +191,27 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment, int recv, unsigned copied) { - struct scatterlist sg; unsigned int pad; ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", segment->copied, copied, segment->size, recv ? "recv" : "xmit"); - if (segment->hash && copied) { - /* - * If a segment is kmapd we must unmap it before sending - * to the crypto layer since that will try to kmap it again. - */ - iscsi_tcp_segment_unmap(segment); - - if (!segment->data) { - sg_init_table(&sg, 1); - sg_set_page(&sg, sg_page(segment->sg), copied, - segment->copied + segment->sg_offset + - segment->sg->offset); - } else - sg_init_one(&sg, segment->data + segment->copied, - copied); - ahash_request_set_crypt(segment->hash, &sg, NULL, copied); - crypto_ahash_update(segment->hash); + if (segment->crcp && copied) { + if (segment->data) { + *segment->crcp = crc32c(*segment->crcp, + segment->data + segment->copied, + copied); + } else { + const void *data; + + data = kmap_local_page(sg_page(segment->sg)); + *segment->crcp = crc32c(*segment->crcp, + data + segment->copied + + segment->sg_offset + + segment->sg->offset, + copied); + kunmap_local(data); + } } segment->copied += copied; @@ -258,10 +256,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, * Set us up for transferring the data digest. hdr digest * is completely handled in hdr done function. */ - if (segment->hash) { - ahash_request_set_crypt(segment->hash, NULL, - segment->digest, 0); - crypto_ahash_final(segment->hash); + if (segment->crcp) { + put_unaligned_le32(~*segment->crcp, segment->digest); iscsi_tcp_segment_splice_digest(segment, recv ? segment->recv_digest : segment->digest); return 0; @@ -282,8 +278,7 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_segment_done); * given buffer, and returns the number of bytes * consumed, which can actually be less than @len. * - * If hash digest is enabled, the function will update the - * hash while copying. + * If CRC is enabled, the function will update the CRC while copying. * Combining these two operations doesn't buy us a lot (yet), * but in the future we could implement combined copy+crc, * just way we do for network layer checksums. @@ -311,14 +306,10 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, } inline void -iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr, - size_t hdrlen, unsigned char digest[ISCSI_DIGEST_SIZE]) +iscsi_tcp_dgst_header(const void *hdr, size_t hdrlen, + unsigned char digest[ISCSI_DIGEST_SIZE]) { - struct scatterlist sg; - - sg_init_one(&sg, hdr, hdrlen); - ahash_request_set_crypt(hash, &sg, digest, hdrlen); - crypto_ahash_digest(hash); + put_unaligned_le32(~crc32c(~0, hdr, hdrlen), digest); } EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header); @@ -343,24 +334,23 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, */ static inline void __iscsi_segment_init(struct iscsi_segment *segment, size_t size, - iscsi_segment_done_fn_t *done, struct ahash_request *hash) + iscsi_segment_done_fn_t *done, u32 *crcp) { memset(segment, 0, sizeof(*segment)); segment->total_size = size; segment->done = done; - if (hash) { - segment->hash = hash; - crypto_ahash_init(hash); + if (crcp) { + segment->crcp = crcp; + *crcp = ~0; } } inline void iscsi_segment_init_linear(struct iscsi_segment *segment, void *data, - size_t size, iscsi_segment_done_fn_t *done, - struct ahash_request *hash) + size_t size, iscsi_segment_done_fn_t *done, u32 *crcp) { - __iscsi_segment_init(segment, size, done, hash); + __iscsi_segment_init(segment, size, done, crcp); segment->data = data; segment->size = size; } @@ -370,13 +360,12 @@ inline int iscsi_segment_seek_sg(struct iscsi_segment *segment, struct scatterlist *sg_list, unsigned int sg_count, unsigned int offset, size_t size, - iscsi_segment_done_fn_t *done, - struct ahash_request *hash) + iscsi_segment_done_fn_t *done, u32 *crcp) { struct scatterlist *sg; unsigned int i; - __iscsi_segment_init(segment, size, done, hash); + __iscsi_segment_init(segment, size, done, crcp); for_each_sg(sg_list, sg, sg_count, i) { if (offset < sg->length) { iscsi_tcp_segment_init_sg(segment, sg, offset); @@ -393,7 +382,7 @@ EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg); * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception * @tcp_conn: iscsi connection to prep for * - * This function always passes NULL for the hash argument, because when this + * This function always passes NULL for the crcp argument, because when this * function is called we do not yet know the final size of the header and want * to delay the digest processing until we know that. */ @@ -434,15 +423,15 @@ static void iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) { struct iscsi_conn *conn = tcp_conn->iscsi_conn; - struct ahash_request *rx_hash = NULL; + u32 *rx_crcp = NULL; if (conn->datadgst_en && !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) - rx_hash = tcp_conn->rx_hash; + rx_crcp = tcp_conn->rx_crcp; iscsi_segment_init_linear(&tcp_conn->in.segment, conn->data, tcp_conn->in.datalen, - iscsi_tcp_data_recv_done, rx_hash); + iscsi_tcp_data_recv_done, rx_crcp); } /** @@ -730,7 +719,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) if (tcp_conn->in.datalen) { struct iscsi_tcp_task *tcp_task = task->dd_data; - struct ahash_request *rx_hash = NULL; + u32 *rx_crcp = NULL; struct scsi_data_buffer *sdb = &task->sc->sdb; /* @@ -743,7 +732,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) */ if (conn->datadgst_en && !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) - rx_hash = tcp_conn->rx_hash; + rx_crcp = tcp_conn->rx_crcp; ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " "offset=%d, datalen=%d)\n", @@ -756,7 +745,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) tcp_task->data_offset, tcp_conn->in.datalen, iscsi_tcp_process_data_in, - rx_hash); + rx_crcp); spin_unlock(&conn->session->back_lock); return rc; } @@ -878,7 +867,7 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, return 0; } - iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, + iscsi_tcp_dgst_header(hdr, segment->total_copied - ISCSI_DIGEST_SIZE, segment->digest); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 7b4e7a61965a..61368e55bf86 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -252,7 +252,7 @@ static int sas_get_ata_command_set(struct domain_device *dev) return ata_dev_classify(&tf); } -int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) +static int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) { if (phy->attached_tproto & SAS_PROTOCOL_STP) dev->tproto = phy->attached_tproto; @@ -559,8 +559,8 @@ static int sas_ata_prereset(struct ata_link *link, unsigned long deadline) } static struct ata_port_operations sas_sata_ops = { - .prereset = sas_ata_prereset, - .hardreset = sas_ata_hard_reset, + .reset.prereset = sas_ata_prereset, + .reset.hardreset = sas_ata_hard_reset, .error_handler = ata_std_error_handler, .post_internal_cmd = sas_ata_post_internal, .qc_defer = ata_std_qc_defer, @@ -579,7 +579,7 @@ int sas_ata_init(struct domain_device *found_dev) struct ata_port *ap; int rc; - ata_host = kzalloc(sizeof(*ata_host), GFP_KERNEL); + ata_host = kzalloc_obj(*ata_host); if (!ata_host) { pr_err("ata host alloc failed.\n"); return -ENOMEM; @@ -927,13 +927,7 @@ EXPORT_SYMBOL_GPL(sas_ata_schedule_reset); void sas_ata_wait_eh(struct domain_device *dev) { - struct ata_port *ap; - - if (!dev_is_sata(dev)) - return; - - ap = dev->sata_dev.ap; - ata_port_wait_eh(ap); + ata_port_wait_eh(dev->sata_dev.ap); } void sas_ata_device_link_abort(struct domain_device *device, bool force_reset) diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 951bdc554a10..b07062db50b2 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -406,7 +406,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) } } -void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) +void sas_unregister_domain_devices(struct asd_sas_port *port, bool gone) { struct domain_device *dev, *n; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 2b8004eb6f1b..f471ab464a78 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -89,7 +89,7 @@ static int smp_execute_task_sg(struct domain_device *dev, res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { - del_timer_sync(&task->slow_task->timer); + timer_delete_sync(&task->slow_task->timer); pr_notice("executing SMP task failed:%d\n", res); break; } @@ -433,7 +433,7 @@ static int sas_expander_discover(struct domain_device *dev) struct expander_device *ex = &dev->ex_dev; int res; - ex->ex_phy = kcalloc(ex->num_phys, sizeof(*ex->ex_phy), GFP_KERNEL); + ex->ex_phy = kzalloc_objs(*ex->ex_phy, ex->num_phys); if (!ex->ex_phy) return -ENOMEM; @@ -1313,10 +1313,7 @@ static int sas_check_parent_topology(struct domain_device *child) int i; int res = 0; - if (!child->parent) - return 0; - - if (!dev_is_expander(child->parent->dev_type)) + if (!dev_parent_is_expander(child)) return 0; parent_ex = &child->parent->ex_dev; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 8566bb1208a0..0bec236f0fb5 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -39,7 +39,7 @@ struct sas_task *sas_alloc_task(gfp_t flags) struct sas_task *sas_alloc_slow_task(gfp_t flags) { struct sas_task *task = sas_alloc_task(flags); - struct sas_task_slow *slow = kmalloc(sizeof(*slow), flags); + struct sas_task_slow *slow = kmalloc_obj(*slow, flags); if (!task || !slow) { if (task) @@ -141,6 +141,7 @@ Undo_event_q: Undo_ports: sas_unregister_ports(sas_ha); Undo_phys: + sas_unregister_phys(sas_ha); return error; } @@ -504,7 +505,7 @@ static void phy_enable_work(struct work_struct *work) static int sas_phy_setup(struct sas_phy *phy) { - struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL); + struct sas_phy_data *d = kzalloc_obj(*d); if (!d) return -ENOMEM; diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 03d6ec1eb970..7dce0f587149 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -44,7 +44,7 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr); int sas_discover_root_expander(struct domain_device *dev); int sas_ex_revalidate_domain(struct domain_device *dev); -void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); +void sas_unregister_domain_devices(struct asd_sas_port *port, bool gone); void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port); void sas_discover_event(struct asd_sas_port *port, enum discover_event ev); @@ -54,6 +54,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev); void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_register_phys(struct sas_ha_struct *sas_ha); +void sas_unregister_phys(struct sas_ha_struct *sas_ha); struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); void sas_free_event(struct asd_sas_event *event); @@ -70,7 +71,7 @@ void sas_enable_revalidation(struct sas_ha_struct *ha); void sas_queue_deferred_work(struct sas_ha_struct *ha); void __sas_drain_work(struct sas_ha_struct *ha); -void sas_deform_port(struct asd_sas_phy *phy, int gone); +void sas_deform_port(struct asd_sas_phy *phy, bool gone); void sas_porte_bytes_dmaed(struct work_struct *work); void sas_porte_broadcast_rcvd(struct work_struct *work); @@ -145,20 +146,6 @@ static inline void sas_fail_probe(struct domain_device *dev, const char *func, i func, dev->parent ? "exp-attached" : "direct-attached", SAS_ADDR(dev->sas_addr), err); - - /* - * If the device probe failed, the expander phy attached address - * needs to be reset so that the phy will not be treated as flutter - * in the next revalidation - */ - if (dev->parent && !dev_is_expander(dev->dev_type)) { - struct sas_phy *phy = dev->phy; - struct domain_device *parent = dev->parent; - struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number]; - - memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - } - sas_unregister_dev(dev->port, dev); } @@ -205,7 +192,7 @@ static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_devic static inline struct domain_device *sas_alloc_device(void) { - struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + struct domain_device *dev = kzalloc_obj(*dev); if (dev) { INIT_LIST_HEAD(&dev->siblings); @@ -222,4 +209,78 @@ static inline void sas_put_device(struct domain_device *dev) kref_put(&dev->kref, sas_free_device); } +#ifdef CONFIG_SCSI_SAS_ATA + +int sas_ata_init(struct domain_device *dev); +void sas_ata_task_abort(struct sas_task *task); +int sas_discover_sata(struct domain_device *dev); +int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, + struct domain_device *child, int phy_id); +void sas_ata_strategy_handler(struct Scsi_Host *shost); +void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q); +void sas_ata_end_eh(struct ata_port *ap); +void sas_ata_wait_eh(struct domain_device *dev); +void sas_probe_sata(struct asd_sas_port *port); +void sas_suspend_sata(struct asd_sas_port *port); +void sas_resume_sata(struct asd_sas_port *port); + +#else + +static inline int sas_ata_init(struct domain_device *dev) +{ + return 0; +} + +static inline void sas_ata_task_abort(struct sas_task *task) +{ +} + +static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) +{ +} + +static inline void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q) +{ +} + +static inline void sas_ata_end_eh(struct ata_port *ap) +{ +} + +static inline void sas_ata_wait_eh(struct domain_device *dev) +{ +} + +static inline void sas_probe_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_suspend_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_resume_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_ata_disabled_notice(void) +{ + pr_notice_once("ATA device seen but CONFIG_SCSI_SAS_ATA=N\n"); +} + +static inline int sas_discover_sata(struct domain_device *dev) +{ + sas_ata_disabled_notice(); + return -ENXIO; +} + +static inline int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, + struct domain_device *child, int phy_id) +{ + sas_ata_disabled_notice(); + return -ENODEV; +} + +#endif + #endif /* _SAS_INTERNAL_H_ */ diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 57494ac97076..58f08dc2c187 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -20,7 +20,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work) struct asd_sas_phy *phy = ev->phy; phy->error = 0; - sas_deform_port(phy, 1); + sas_deform_port(phy, true); } static void sas_phye_oob_done(struct work_struct *work) @@ -40,7 +40,7 @@ static void sas_phye_oob_error(struct work_struct *work) struct sas_internal *i = to_sas_internal(sas_ha->shost->transportt); - sas_deform_port(phy, 1); + sas_deform_port(phy, true); if (!port && phy->enabled && i->dft->lldd_control_phy) { phy->error++; @@ -85,7 +85,7 @@ static void sas_phye_resume_timeout(struct work_struct *work) phy->error = 0; phy->suspended = 0; - sas_deform_port(phy, 1); + sas_deform_port(phy, true); } @@ -116,6 +116,7 @@ static void sas_phye_shutdown(struct work_struct *work) int sas_register_phys(struct sas_ha_struct *sas_ha) { int i; + int err; /* Now register the phys. */ for (i = 0; i < sas_ha->num_phys; i++) { @@ -132,8 +133,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->frame_rcvd_size = 0; phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i); - if (!phy->phy) - return -ENOMEM; + if (!phy->phy) { + err = -ENOMEM; + goto rollback; + } phy->phy->identify.initiator_port_protocols = phy->iproto; @@ -146,10 +149,34 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; - sas_phy_add(phy->phy); + err = sas_phy_add(phy->phy); + if (err) { + sas_phy_free(phy->phy); + goto rollback; + } } return 0; +rollback: + for (i-- ; i >= 0 ; i--) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } + return err; +} + +void sas_unregister_phys(struct sas_ha_struct *sas_ha) +{ + int i; + + for (i = 0 ; i < sas_ha->num_phys ; i++) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } } const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index e3f2ed913419..de7556070048 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -113,7 +113,7 @@ static void sas_form_port(struct asd_sas_phy *phy) if (port) { if (!phy_is_wideport_member(port, phy)) - sas_deform_port(phy, 0); + sas_deform_port(phy, false); else if (phy->suspended) { phy->suspended = 0; sas_resume_port(phy); @@ -206,7 +206,7 @@ static void sas_form_port(struct asd_sas_phy *phy) * This is called when the physical link to the other phy has been * lost (on this phy), in Event thread context. We cannot delay here. */ -void sas_deform_port(struct asd_sas_phy *phy, int gone) +void sas_deform_port(struct asd_sas_phy *phy, bool gone) { struct sas_ha_struct *sas_ha = phy->ha; struct asd_sas_port *port = phy->port; @@ -301,7 +301,7 @@ void sas_porte_link_reset_err(struct work_struct *work) struct asd_sas_event *ev = to_asd_sas_event(work); struct asd_sas_phy *phy = ev->phy; - sas_deform_port(phy, 1); + sas_deform_port(phy, true); } void sas_porte_timer_event(struct work_struct *work) @@ -309,7 +309,7 @@ void sas_porte_timer_event(struct work_struct *work) struct asd_sas_event *ev = to_asd_sas_event(work); struct asd_sas_phy *phy = ev->phy; - sas_deform_port(phy, 1); + sas_deform_port(phy, true); } void sas_porte_hard_reset(struct work_struct *work) @@ -317,7 +317,7 @@ void sas_porte_hard_reset(struct work_struct *work) struct asd_sas_event *ev = to_asd_sas_event(work); struct asd_sas_phy *phy = ev->phy; - sas_deform_port(phy, 1); + sas_deform_port(phy, true); } /* ---------- SAS port registration ---------- */ @@ -358,8 +358,7 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha) for (i = 0; i < sas_ha->num_phys; i++) if (sas_ha->sas_phy[i]->port) - sas_deform_port(sas_ha->sas_phy[i], 0); - + sas_deform_port(sas_ha->sas_phy[i], false); } const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 55ce7892f217..c83282733ec4 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -10,6 +10,7 @@ #include <linux/firmware.h> #include <linux/export.h> #include <linux/ctype.h> +#include <linux/hex.h> #include <linux/kernel.h> #include "sas_internal.h" @@ -157,7 +158,8 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, return task; } -int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status sas_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct sas_internal *i = to_sas_internal(host->transportt); struct domain_device *dev = cmd_to_domain_dev(cmd); @@ -845,7 +847,7 @@ int sas_change_queue_depth(struct scsi_device *sdev, int depth) EXPORT_SYMBOL_GPL(sas_change_queue_depth); int sas_bios_param(struct scsi_device *scsi_dev, - struct block_device *bdev, + struct gendisk *unused, sector_t capacity, int *hsc) { hsc[0] = 255; @@ -859,13 +861,13 @@ EXPORT_SYMBOL_GPL(sas_bios_param); void sas_task_internal_done(struct sas_task *task) { - del_timer(&task->slow_task->timer); + timer_delete(&task->slow_task->timer); complete(&task->slow_task->completion); } void sas_task_internal_timedout(struct timer_list *t) { - struct sas_task_slow *slow = from_timer(slow, t, timer); + struct sas_task_slow *slow = timer_container_of(slow, t, timer); struct sas_task *task = slow->task; bool is_completed = true; unsigned long flags; @@ -911,7 +913,7 @@ static int sas_execute_internal_abort(struct domain_device *device, res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { - del_timer_sync(&task->slow_task->timer); + timer_delete_sync(&task->slow_task->timer); pr_err("Executing internal abort failed %016llx (%d)\n", SAS_ADDR(device->sas_addr), res); break; @@ -1010,7 +1012,7 @@ int sas_execute_tmf(struct domain_device *device, void *parameter, res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { - del_timer_sync(&task->slow_task->timer); + timer_delete_sync(&task->slow_task->timer); pr_err("executing TMF task failed %016llx (%d)\n", SAS_ADDR(device->sas_addr), res); break; @@ -1180,7 +1182,7 @@ void sas_task_abort(struct sas_task *task) if (!slow) return; - if (!del_timer(&slow->timer)) + if (!timer_delete(&slow->timer)) return; slow->timer.function(&slow->timer); return; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e5a9c5a323f8..b67ea1730dcf 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -74,8 +74,7 @@ struct lpfc_sli2_slim; * queue depths when there are driver resource error or Firmware * resource error. */ -/* 1 Second */ -#define QUEUE_RAMP_DOWN_INTERVAL (msecs_to_jiffies(1000 * 1)) +#define QUEUE_RAMP_DOWN_INTERVAL (secs_to_jiffies(1)) /* Number of exchanges reserved for discovery to complete */ #define LPFC_DISC_IOCB_BUFF_COUNT 20 @@ -312,7 +311,6 @@ struct lpfc_defer_flogi_acc { u16 rx_id; u16 ox_id; struct lpfc_nodelist *ndlp; - }; #define LPFC_VMID_TIMER 300 /* timer interval in seconds */ @@ -554,8 +552,6 @@ struct lpfc_cgn_info { ); __le32 cgn_info_crc; -#define LPFC_CGN_CRC32_MAGIC_NUMBER 0x1EDC6F41 -#define LPFC_CGN_CRC32_SEED 0xFFFFFFFF }; #define LPFC_CGN_INFO_SZ (sizeof(struct lpfc_cgn_info) - \ @@ -635,6 +631,7 @@ struct lpfc_vport { #define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ #define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ #define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */ +#define FC_CT_RSPNI_PNI 0x40 /* RSPNI_PNI accepted by switch */ struct list_head fc_nodes; spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */ @@ -662,15 +659,12 @@ struct lpfc_vport { uint32_t num_disc_nodes; /* in addition to hba_state */ uint32_t gidft_inp; /* cnt of outstanding GID_FTs */ - uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */ uint32_t fc_rscn_flush; /* flag use of fc_rscn_id_list */ struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN]; struct lpfc_name fc_nodename; /* fc nodename */ struct lpfc_name fc_portname; /* fc portname */ - struct lpfc_work_evt disc_timeout_evt; - struct timer_list fc_disctmo; /* Discovery rescue timer */ uint8_t fc_ns_retry; /* retries for fabric nameserver */ uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */ @@ -745,12 +739,6 @@ struct lpfc_vport { struct lpfc_vmid_priority_info vmid_priority; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct dentry *debug_disc_trc; - struct dentry *debug_nodelist; - struct dentry *debug_nvmestat; - struct dentry *debug_scsistat; - struct dentry *debug_ioktime; - struct dentry *debug_hdwqstat; struct dentry *vport_debugfs_root; struct lpfc_debugfs_trc *disc_trc; atomic_t disc_trc_cnt; @@ -768,7 +756,6 @@ struct lpfc_vport { /* There is a single nvme instance per vport. */ struct nvme_fc_local_port *localport; uint8_t nvmei_support; /* driver supports NVME Initiator */ - uint32_t last_fcp_wqidx; uint32_t rcv_flogi_cnt; /* How many unsol FLOGIs ACK'd. */ }; @@ -823,9 +810,10 @@ struct unsol_rcv_ct_ctx { #define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */ #define LPFC_USER_LINK_SPEED_32G 32 /* 32 Gigabaud */ #define LPFC_USER_LINK_SPEED_64G 64 /* 64 Gigabaud */ -#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_64G +#define LPFC_USER_LINK_SPEED_128G 128 /* 128 Gigabaud */ +#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_128G -#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32, 64" +#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32, 64, 128" enum nemb_type { nemb_mse = 1, @@ -1028,7 +1016,6 @@ struct lpfc_hba { #define LPFC_SLI3_CRP_ENABLED 0x08 #define LPFC_SLI3_BG_ENABLED 0x20 #define LPFC_SLI3_DSS_ENABLED 0x40 -#define LPFC_SLI4_PERFH_ENABLED 0x80 #define LPFC_SLI4_PHWQ_ENABLED 0x100 uint32_t iocb_cmd_size; uint32_t iocb_rsp_size; @@ -1061,8 +1048,6 @@ struct lpfc_hba { struct lpfc_dmabuf hbqslimp; - uint16_t pci_cfg_value; - uint8_t fc_linkspeed; /* Link speed after last READ_LA */ uint32_t fc_eventTag; /* event tag for link attention */ @@ -1089,9 +1074,10 @@ struct lpfc_hba { struct lpfc_stats fc_stat; - struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */ uint32_t nport_event_cnt; /* timestamp for nlplist entry */ + unsigned long pni; /* 64-bit Platform Name Identifier */ + uint8_t wwnn[8]; uint8_t wwpn[8]; uint32_t RandomData[7]; @@ -1202,7 +1188,6 @@ struct lpfc_hba { uint32_t cfg_ras_fwlog_func; uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */ uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */ - uint32_t cfg_enable_pbde; uint32_t cfg_enable_mi; struct nvmet_fc_target_port *targetport; lpfc_vpd_t vpd; /* vital product data */ @@ -1230,9 +1215,6 @@ struct lpfc_hba { uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ - atomic_t fcp_qidx; /* next FCP WQ (RR Policy) */ - atomic_t nvme_qidx; /* next NVME WQ (RR Policy) */ - phys_addr_t pci_bar0_map; /* Physical address for PCI BAR0 */ phys_addr_t pci_bar1_map; /* Physical address for PCI BAR1 */ phys_addr_t pci_bar2_map; /* Physical address for PCI BAR2 */ @@ -1349,30 +1331,9 @@ struct lpfc_hba { unsigned long last_ramp_down_time; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS struct dentry *hba_debugfs_root; - atomic_t debugfs_vport_count; - struct dentry *debug_multixri_pools; - struct dentry *debug_hbqinfo; - struct dentry *debug_dumpHostSlim; - struct dentry *debug_dumpHBASlim; - struct dentry *debug_InjErrLBA; /* LBA to inject errors at */ - struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */ - struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */ - struct dentry *debug_writeGuard; /* inject write guard_tag errors */ - struct dentry *debug_writeApp; /* inject write app_tag errors */ - struct dentry *debug_writeRef; /* inject write ref_tag errors */ - struct dentry *debug_readGuard; /* inject read guard_tag errors */ - struct dentry *debug_readApp; /* inject read app_tag errors */ - struct dentry *debug_readRef; /* inject read ref_tag errors */ - - struct dentry *debug_nvmeio_trc; + unsigned int debugfs_vport_count; + struct lpfc_debugfs_nvmeio_trc *nvmeio_trc; - struct dentry *debug_hdwqinfo; -#ifdef LPFC_HDWQ_LOCK_STAT - struct dentry *debug_lockstat; -#endif - struct dentry *debug_cgn_buffer; - struct dentry *debug_rx_monitor; - struct dentry *debug_ras_log; atomic_t nvmeio_trc_cnt; uint32_t nvmeio_trc_size; uint32_t nvmeio_trc_output_idx; @@ -1389,19 +1350,10 @@ struct lpfc_hba { sector_t lpfc_injerr_lba; #define LPFC_INJERR_LBA_OFF (sector_t)(-1) - struct dentry *debug_slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc; atomic_t slow_ring_trc_cnt; /* iDiag debugfs sub-directory */ struct dentry *idiag_root; - struct dentry *idiag_pci_cfg; - struct dentry *idiag_bar_acc; - struct dentry *idiag_que_info; - struct dentry *idiag_que_acc; - struct dentry *idiag_drb_acc; - struct dentry *idiag_ctl_acc; - struct dentry *idiag_mbx_acc; - struct dentry *idiag_ext_acc; uint8_t lpfc_idiag_last_eq; #endif uint16_t nvmeio_trc_on; @@ -1712,44 +1664,33 @@ lpfc_phba_elsring(struct lpfc_hba *phba) * @mask: Pointer to phba's cpumask member. * @start: starting cpu index * - * Note: If no valid cpu found, then nr_cpu_ids is returned. + * Returns: next online CPU in @mask on success * + * Note: If no valid cpu found, then nr_cpu_ids is returned. **/ -static inline unsigned int +static __always_inline unsigned int lpfc_next_online_cpu(const struct cpumask *mask, unsigned int start) { - unsigned int cpu_it; - - for_each_cpu_wrap(cpu_it, mask, start) { - if (cpu_online(cpu_it)) - break; - } - - return cpu_it; + return cpumask_next_and_wrap(start, mask, cpu_online_mask); } + /** * lpfc_next_present_cpu - Finds next present CPU after n * @n: the cpu prior to search * - * Note: If no next present cpu, then fallback to first present cpu. + * Returns: next present CPU after CPU @n * + * Note: If no next present cpu, then fallback to first present cpu. **/ -static inline unsigned int lpfc_next_present_cpu(int n) +static __always_inline unsigned int lpfc_next_present_cpu(int n) { - unsigned int cpu; - - cpu = cpumask_next(n, cpu_present_mask); - - if (cpu >= nr_cpu_ids) - cpu = cpumask_first(cpu_present_mask); - - return cpu; + return cpumask_next_wrap(n, cpu_present_mask); } /** * lpfc_sli4_mod_hba_eq_delay - update EQ delay * @phba: Pointer to HBA context object. - * @q: The Event Queue to update. + * @eq: The Event Queue to update. * @delay: The delay value (in us) to be written. * **/ @@ -1811,8 +1752,9 @@ static const char *routine(enum enum_name table_key) \ * Pr Tag 1 0 N * Pr Tag 1 1 Y * Pr Tag 2 * Y - --------------------------------------------------- + * --------------------------------------------------- * + * Returns: whether VMID is enabled **/ static inline int lpfc_is_vmid_enabled(struct lpfc_hba *phba) { diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 0d0213bba35d..c91fa44b12d4 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2026 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. * * www.broadcom.com * @@ -291,6 +291,138 @@ buffer_done: return len; } +static ssize_t +lpfc_vmid_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_vmid *vmp; + int len = 0, i, j, k, cpu; + char hxstr[LPFC_MAX_VMID_SIZE * 3] = {0}; + struct timespec64 curr_tm; + struct lpfc_vmid_priority_range *vr; + u64 *lta, rct_acc = 0, max_lta = 0; + struct tm tm_val; + + ktime_get_ts64(&curr_tm); + + len += scnprintf(buf + len, PAGE_SIZE - len, "Key 'vmid':\n"); + + /* if enabled continue, else return */ + if (lpfc_is_vmid_enabled(phba)) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "lpfc VMID Page: ON\n\n"); + } else { + len += scnprintf(buf + len, PAGE_SIZE - len, + "lpfc VMID Page: OFF\n\n"); + return len; + } + + /* if using priority tagging */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "VMID priority ranges:\n"); + vr = vport->vmid_priority.vmid_range; + for (i = 0; i < vport->vmid_priority.num_descriptors; ++i) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "\t[x%x - x%x], qos: x%x\n", + vr->low, vr->high, vr->qos); + vr++; + } + } + + for (i = 0; i < phba->cfg_max_vmid; i++) { + vmp = &vport->vmid[i]; + max_lta = 0; + + /* only if the slot is used */ + if (!(vmp->flag & LPFC_VMID_SLOT_USED) || + !(vmp->flag & LPFC_VMID_REGISTERED)) + continue; + + /* if using priority tagging */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "VEM ID: %02x:%02x:%02x:%02x:" + "%02x:%02x:%02x:%02x:%02x:%02x:" + "%02x:%02x:%02x:%02x:%02x:%02x\n", + vport->lpfc_vmid_host_uuid[0], + vport->lpfc_vmid_host_uuid[1], + vport->lpfc_vmid_host_uuid[2], + vport->lpfc_vmid_host_uuid[3], + vport->lpfc_vmid_host_uuid[4], + vport->lpfc_vmid_host_uuid[5], + vport->lpfc_vmid_host_uuid[6], + vport->lpfc_vmid_host_uuid[7], + vport->lpfc_vmid_host_uuid[8], + vport->lpfc_vmid_host_uuid[9], + vport->lpfc_vmid_host_uuid[10], + vport->lpfc_vmid_host_uuid[11], + vport->lpfc_vmid_host_uuid[12], + vport->lpfc_vmid_host_uuid[13], + vport->lpfc_vmid_host_uuid[14], + vport->lpfc_vmid_host_uuid[15]); + } + + /* IO stats */ + len += scnprintf(buf + len, PAGE_SIZE - len, + "ID00 READs:%llx WRITEs:%llx\n", + vmp->io_rd_cnt, + vmp->io_wr_cnt); + for (j = 0, k = 0; j < strlen(vmp->host_vmid); j++, k += 3) + sprintf((char *)(hxstr + k), "%2x ", vmp->host_vmid[j]); + /* UUIDs */ + len += scnprintf(buf + len, PAGE_SIZE - len, "UUID:\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", hxstr); + + len += scnprintf(buf + len, PAGE_SIZE - len, "String (%s)\n", + vmp->host_vmid); + + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + len += scnprintf(buf + len, PAGE_SIZE - len, + "CS_CTL VMID: 0x%x\n", + vmp->un.cs_ctl_vmid); + else + len += scnprintf(buf + len, PAGE_SIZE - len, + "Application id: 0x%x\n", + vmp->un.app_id); + + /* calculate the last access time */ + for_each_possible_cpu(cpu) { + lta = per_cpu_ptr(vmp->last_io_time, cpu); + if (!lta) + continue; + + /* if last access time is less than timeout */ + if (time_after((unsigned long)*lta, jiffies)) + continue; + + if (*lta > max_lta) + max_lta = *lta; + } + + rct_acc = jiffies_to_msecs(jiffies - max_lta) / 1000; + /* current time */ + time64_to_tm(ktime_get_real_seconds(), + -(sys_tz.tz_minuteswest * 60) - rct_acc, &tm_val); + + len += scnprintf(buf + len, PAGE_SIZE - len, + "Last Access Time :" + "%ld-%d-%dT%02d:%02d:%02d\n\n", + 1900 + tm_val.tm_year, tm_val.tm_mon + 1, + tm_val.tm_mday, tm_val.tm_hour, + tm_val.tm_min, tm_val.tm_sec); + + if (len >= PAGE_SIZE) + return len; + + memset(hxstr, 0, LPFC_MAX_VMID_SIZE * 3); + } + return len; +} + /** * lpfc_drvr_version_show - Return the Emulex driver string with version number * @dev: class unused variable. @@ -1909,7 +2041,7 @@ lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr, struct sff_trasnceiver_codes_byte7 *trasn_code_byte7; /* Get transceiver information */ - rdp_context = kmalloc(sizeof(*rdp_context), GFP_KERNEL); + rdp_context = kmalloc_obj(*rdp_context); if (!rdp_context) { len = scnprintf(buf, PAGE_SIZE - len, "SPF info NA: alloc failure\n"); @@ -2578,7 +2710,7 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, (old_val & DISABLE_FCP_RING_INT)) { spin_unlock_irq(&phba->hbalock); - del_timer(&phba->fcp_poll_timer); + timer_delete(&phba->fcp_poll_timer); spin_lock_irq(&phba->hbalock); if (lpfc_readl(phba->HCregaddr, &creg_val)) { spin_unlock_irq(&phba->hbalock); @@ -3011,6 +3143,7 @@ static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, NULL); static DEVICE_ATTR(cmf_info, 0444, lpfc_cmf_info_show, NULL); +static DEVICE_ATTR_RO(lpfc_vmid_info); #define WWN_SZ 8 /** @@ -4282,7 +4415,7 @@ static DEVICE_ATTR_RO(lpfc_static_vport); /* # lpfc_link_speed: Link speed selection for initializing the Fibre Channel # connection. -# Value range is [0,16]. Default value is 0. +# Value range is [0,128]. Default value is 0. */ /** * lpfc_link_speed_store - Set the adapters link speed @@ -4335,14 +4468,15 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, "3055 lpfc_link_speed changed from %d to %d %s\n", phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)"); - if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) || - ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) || - ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || - ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || - ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || - ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) || - ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb)) || - ((val == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) { + if ((val == LPFC_USER_LINK_SPEED_1G && !(phba->lmt & LMT_1Gb)) || + (val == LPFC_USER_LINK_SPEED_2G && !(phba->lmt & LMT_2Gb)) || + (val == LPFC_USER_LINK_SPEED_4G && !(phba->lmt & LMT_4Gb)) || + (val == LPFC_USER_LINK_SPEED_8G && !(phba->lmt & LMT_8Gb)) || + (val == LPFC_USER_LINK_SPEED_10G && !(phba->lmt & LMT_10Gb)) || + (val == LPFC_USER_LINK_SPEED_16G && !(phba->lmt & LMT_16Gb)) || + (val == LPFC_USER_LINK_SPEED_32G && !(phba->lmt & LMT_32Gb)) || + (val == LPFC_USER_LINK_SPEED_64G && !(phba->lmt & LMT_64Gb)) || + (val == LPFC_USER_LINK_SPEED_128G && !(phba->lmt & LMT_128Gb))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2879 lpfc_link_speed attribute cannot be set " "to %d. Speed is not supported by this port.\n", @@ -4367,6 +4501,7 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, case LPFC_USER_LINK_SPEED_16G: case LPFC_USER_LINK_SPEED_32G: case LPFC_USER_LINK_SPEED_64G: + case LPFC_USER_LINK_SPEED_128G: prev_val = phba->cfg_link_speed; phba->cfg_link_speed = val; if (nolip) @@ -4431,6 +4566,7 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val) case LPFC_USER_LINK_SPEED_16G: case LPFC_USER_LINK_SPEED_32G: case LPFC_USER_LINK_SPEED_64G: + case LPFC_USER_LINK_SPEED_128G: phba->cfg_link_speed = val; return 0; default: @@ -6117,6 +6253,7 @@ static struct attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_vmid_inactivity_timeout.attr, &dev_attr_lpfc_vmid_app_header.attr, &dev_attr_lpfc_vmid_priority_tagging.attr, + &dev_attr_lpfc_vmid_info.attr, NULL, }; @@ -6286,8 +6423,8 @@ static const struct bin_attribute sysfs_ctlreg_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 256, - .read_new = sysfs_ctlreg_read, - .write_new = sysfs_ctlreg_write, + .read = sysfs_ctlreg_read, + .write = sysfs_ctlreg_write, }; /** @@ -6344,8 +6481,8 @@ static const struct bin_attribute sysfs_mbox_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = MAILBOX_SYSFS_MAX, - .read_new = sysfs_mbox_read, - .write_new = sysfs_mbox_write, + .read = sysfs_mbox_read, + .write = sysfs_mbox_write, }; /** @@ -6845,6 +6982,42 @@ lpfc_reset_stats(struct Scsi_Host *shost) return; } +/** + * lpfc_get_enc_info - Return encryption information about the session for + * a given remote port. + * @rport: ptr to fc_rport from scsi transport fc + * + * Given an rport object, iterate through the fc_nodes list to find node + * corresponding with rport. Pass the encryption information from the node to + * rport's encryption attribute for reporting to upper layers. Information is + * passed through nlp_enc_info struct which contains encryption status. + * + * Returns: + * - Address of rport's fc_encryption_info struct + * - NULL when not found + **/ +static struct fc_encryption_info * +lpfc_get_enc_info(struct fc_rport *rport) +{ + struct Scsi_Host *shost = rport_to_shost(rport); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct fc_encryption_info *ef = NULL; + struct lpfc_nodelist *ndlp, *next_ndlp; + unsigned long iflags; + + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->rport && ndlp->rport == rport) { + ef = &rport->enc_info; + ef->status = ndlp->nlp_enc_info.status; + break; + } + } + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); + return ef; +} + + /* * The LPFC driver treats linkdown handling as target loss events so there * are no sysfs handlers for link_down_tmo. @@ -7062,6 +7235,8 @@ struct fc_function_template lpfc_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, @@ -7131,6 +7306,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, @@ -7293,8 +7470,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_auto_imax = (phba->cfg_fcp_imax) ? 0 : 1; - phba->cfg_enable_pbde = 0; - /* A value of 0 means use the number of CPUs found in the system */ if (phba->cfg_hdw_queue == 0) phba->cfg_hdw_queue = phba->sli4_hba.num_present_cpu; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index c8f8496bbdf8..7406dfa60016 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -174,7 +174,7 @@ lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size, /* Allocate dma buffer and place in BPL passed */ while (bytes_left) { /* Allocate dma buffer */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + mp = kmalloc_obj(struct lpfc_dmabuf); if (!mp) { if (mlist) lpfc_free_bsg_buffers(phba, mlist); @@ -416,7 +416,7 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) return -ENODEV; /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2733 Failed allocation of dd_data\n"); @@ -430,7 +430,7 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) goto free_dd; } - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + bmp = kmalloc_obj(struct lpfc_dmabuf); if (!bmp) { rc = -ENOMEM; goto free_cmdiocbq; @@ -683,7 +683,7 @@ lpfc_bsg_rport_els(struct bsg_job *job) } /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2735 Failed allocation of dd_data\n"); @@ -843,7 +843,7 @@ lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) static struct lpfc_bsg_event * lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) { - struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); + struct lpfc_bsg_event *evt = kzalloc_obj(*evt); if (!evt) return NULL; @@ -939,7 +939,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_bsg_event_ref(evt); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); + evt_dat = kzalloc_obj(*evt_dat); if (evt_dat == NULL) { spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_bsg_event_unref(evt); @@ -1215,7 +1215,7 @@ lpfc_bsg_hba_set_event(struct bsg_job *job) if (&evt->node == &phba->ct_ev_waiters) { /* no event waiting struct yet - first call */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (dd_data == NULL) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2734 Failed allocation of dd_data\n"); @@ -1477,7 +1477,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, } /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2736 Failed allocation of dd_data\n"); @@ -1605,7 +1605,7 @@ lpfc_bsg_send_mgmt_rsp(struct bsg_job *job) goto send_mgmt_rsp_exit; } - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + bmp = kmalloc_obj(struct lpfc_dmabuf); if (!bmp) { rc = -ENOMEM; goto send_mgmt_rsp_exit; @@ -2628,7 +2628,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, cmdiocbq = lpfc_sli_get_iocbq(phba); rspiocbq = lpfc_sli_get_iocbq(phba); - dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + dmabuf = kmalloc_obj(struct lpfc_dmabuf); if (dmabuf) { dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); if (dmabuf->virt) { @@ -2687,8 +2687,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, evt->wait_time_stamp = jiffies; time_left = wait_event_interruptible_timeout( evt->wq, !list_empty(&evt->events_to_see), - msecs_to_jiffies(1000 * - ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); + secs_to_jiffies(phba->fc_ratov * 2 + LPFC_DRVR_TIMEOUT)); if (list_empty(&evt->events_to_see)) ret_val = (time_left) ? -EINTR : -ETIMEDOUT; else { @@ -2734,7 +2733,7 @@ lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) struct pci_dev *pcidev = phba->pcidev; /* allocate dma buffer struct */ - dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + dmabuf = kmalloc_obj(struct lpfc_dmabuf); if (!dmabuf) return NULL; @@ -2830,7 +2829,7 @@ diag_cmd_data_alloc(struct lpfc_hba *phba, cnt = size; /* allocate struct lpfc_dmabufext buffer header */ - dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); + dmp = kmalloc_obj(struct lpfc_dmabufext); if (!dmp) goto out; @@ -2910,7 +2909,7 @@ static int lpfcdiag_sli3_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, pring = lpfc_phba_elsring(phba); cmdiocbq = lpfc_sli_get_iocbq(phba); - rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + rxbmp = kmalloc_obj(struct lpfc_dmabuf); if (rxbmp != NULL) { rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); if (rxbmp->virt) { @@ -3161,7 +3160,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) cmdiocbq = lpfc_sli_get_iocbq(phba); if (phba->sli_rev < LPFC_SLI_REV4) rspiocbq = lpfc_sli_get_iocbq(phba); - txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + txbmp = kmalloc_obj(struct lpfc_dmabuf); if (txbmp) { txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); @@ -3258,8 +3257,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) evt->waiting = 1; time_left = wait_event_interruptible_timeout( evt->wq, !list_empty(&evt->events_to_see), - msecs_to_jiffies(1000 * - ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); + secs_to_jiffies(phba->fc_ratov * 2 + LPFC_DRVR_TIMEOUT)); evt->waiting = 0; if (list_empty(&evt->events_to_see)) { rc = (time_left) ? -EINTR : -ETIMEDOUT; @@ -4076,7 +4074,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, } /* bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { rc = -ENOMEM; goto job_error; @@ -4277,7 +4275,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, if (ext_buf_cnt == 1) { /* bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { rc = -ENOMEM; goto job_error; @@ -4626,7 +4624,7 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, "ebuffers received\n", phba->mbox_ext_buf_ctx.numBuf); - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { rc = -ENOMEM; goto job_error; @@ -4898,7 +4896,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, goto job_done; /* must be negative */ /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + dd_data = kmalloc_obj(struct bsg_job_data); if (!dd_data) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2727 Failed allocation of dd_data\n"); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index efeb61b15a5b..8a5b76bdea06 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -86,7 +86,7 @@ void lpfc_cmf_stop(struct lpfc_hba *phba); void lpfc_init_congestion_stat(struct lpfc_hba *phba); void lpfc_init_congestion_buf(struct lpfc_hba *phba); int lpfc_sli4_cgn_params_read(struct lpfc_hba *phba); -uint32_t lpfc_cgn_calc_crc32(void *bufp, uint32_t sz, uint32_t seed); +uint32_t lpfc_cgn_calc_crc32(const void *data, size_t size); int lpfc_config_cgn_signal(struct lpfc_hba *phba); int lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total); void lpfc_cgn_dump_rxmonitor(struct lpfc_hba *phba); @@ -660,6 +660,7 @@ void lpfc_wqe_cmd_template(void); void lpfc_nvmet_cmd_template(void); void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, uint32_t stat, uint32_t param); +void lpfc_nvme_flush_abts_list(struct lpfc_hba *phba); void lpfc_nvmels_flush_cmd(struct lpfc_hba *phba); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 12c67cdd7c19..c7853e7fe071 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -165,7 +165,7 @@ lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, u32 tmo; /* fill in BDEs for command */ - mp = kmalloc(sizeof(*mp), GFP_KERNEL); + mp = kmalloc_obj(*mp); if (!mp) { rc = 1; goto ct_exit; @@ -178,7 +178,7 @@ lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, } /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + bmp = kmalloc_obj(*bmp); if (!bmp) { rc = 3; goto ct_free_mpvirt; @@ -264,9 +264,9 @@ ct_free_mpvirt: ct_free_mp: kfree(mp); ct_exit: - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "6440 Unsol CT: Rsp err %d Data: x%lx\n", - rc, vport->fc_flag); + lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, + "6440 Unsol CT: Rsp err %d Data: x%lx\n", + rc, vport->fc_flag); } /** @@ -313,7 +313,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) mi_cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp); lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, - "6442 MI Cmd : x%x Not Supported\n", mi_cmd); + "6442 MI Cmd: x%x Not Supported\n", mi_cmd); lpfc_ct_reject_event(ndlp, ct_req, bf_get(wqe_ctxt_tag, &ctiocbq->wqe.xmit_els_rsp.wqe_com), @@ -498,7 +498,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, __be16 cmdcode, struct ulp_bde64 *bpl, while (size) { /* Allocate buffer for rsp payload */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + mp = kmalloc_obj(struct lpfc_dmabuf); if (!mp) { if (mlist) lpfc_free_ct_rsp(phba, mlist); @@ -1743,6 +1743,28 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } static void +lpfc_cmpl_ct_cmd_rspni_pni(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport; + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *ctrsp; + u32 ulp_status; + + vport = cmdiocb->vport; + ulp_status = get_job_ulpstatus(phba, rspiocb); + + if (ulp_status == IOSTAT_SUCCESS) { + outp = cmdiocb->rsp_dmabuf; + ctrsp = (struct lpfc_sli_ct_request *)outp->virt; + if (be16_to_cpu(ctrsp->CommandResponse.bits.CmdRsp) == + SLI_CT_RESPONSE_FS_ACC) + vport->ct_flags |= FC_CT_RSPNI_PNI; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); +} + +static void lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { @@ -1902,7 +1924,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, /* fill in BDEs for command */ /* Allocate buffer for command payload */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + mp = kmalloc_obj(struct lpfc_dmabuf); if (!mp) { rc=2; goto ns_cmd_exit; @@ -1916,7 +1938,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, } /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + bmp = kmalloc_obj(struct lpfc_dmabuf); if (!bmp) { rc=4; goto ns_cmd_free_mpvirt; @@ -1956,6 +1978,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_RSPNI_PNI) + bpl->tus.f.bdeSize = RSPNI_REQUEST_SZ; else if (cmdcode == SLI_CTNS_DA_ID) bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) @@ -2077,6 +2101,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, CtReq->un.rsnn.symbname, size); cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; break; + case SLI_CTNS_RSPNI_PNI: + vport->ct_flags &= ~FC_CT_RSPNI_PNI; + CtReq->CommandResponse.bits.CmdRsp = + cpu_to_be16(SLI_CTNS_RSPNI_PNI); + CtReq->un.rspni.pni = cpu_to_be64(phba->pni); + scnprintf(CtReq->un.rspni.symbname, + sizeof(CtReq->un.rspni.symbname), "OS Host Name::%s", + phba->os_host_name); + CtReq->un.rspni.len = strnlen(CtReq->un.rspni.symbname, + sizeof(CtReq->un.rspni.symbname)); + cmpl = lpfc_cmpl_ct_cmd_rspni_pni; + break; case SLI_CTNS_DA_ID: /* Implement DA_ID Nameserver request */ CtReq->CommandResponse.bits.CmdRsp = @@ -2229,21 +2265,6 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Look for a retryable error */ if (ulp_status == IOSTAT_LOCAL_REJECT) { switch ((ulp_word4 & IOERR_PARAM_MASK)) { - case IOERR_SLI_ABORTED: - case IOERR_SLI_DOWN: - /* Driver aborted this IO. No retry as error - * is likely Offline->Online or some adapter - * error. Recovery will try again, but if port - * is not active there's no point to continue - * issuing follow up FDMI commands. - */ - if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { - free_ndlp = cmdiocb->ndlp; - lpfc_ct_free_iocb(phba, cmdiocb); - lpfc_nlp_put(free_ndlp); - return; - } - break; case IOERR_ABORT_IN_PROGRESS: case IOERR_SEQUENCE_TIMEOUT: case IOERR_ILLEGAL_FRAME: @@ -2269,6 +2290,9 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_ct_free_iocb(phba, cmdiocb); lpfc_nlp_put(free_ndlp); + if (ulp_status != IOSTAT_SUCCESS) + return; + ndlp = lpfc_findnode_did(vport, FDMI_DID); if (!ndlp) return; @@ -2403,13 +2427,14 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* CGN is only for the physical port, no vports */ if (lpfc_fdmi_cmd(vport, ndlp, cmd, - LPFC_FDMI_VENDOR_ATTR_mi) == 0) + LPFC_FDMI_VENDOR_ATTR_mi) == 0) { phba->link_flag |= LS_CT_VEN_RPA; - lpfc_printf_log(phba, KERN_INFO, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY | LOG_ELS, "6458 Send MI FDMI:%x Flag x%x\n", phba->sli4_hba.pc_sli4_params.mi_ver, phba->link_flag); + } } else { lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY | LOG_ELS, @@ -3190,13 +3215,13 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *rspiocb); if (!ndlp) - return 0; + goto fdmi_cmd_exit; cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */ /* fill in BDEs for command */ /* Allocate buffer for command payload */ - rq = kmalloc(sizeof(*rq), GFP_KERNEL); + rq = kmalloc_obj(*rq); if (!rq) goto fdmi_cmd_exit; @@ -3205,7 +3230,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, goto fdmi_cmd_free_rq; /* Allocate buffer for Buffer ptr list */ - rsp = kmalloc(sizeof(*rsp), GFP_KERNEL); + rsp = kmalloc_obj(*rsp); if (!rsp) goto fdmi_cmd_free_rqvirt; @@ -3296,7 +3321,7 @@ hba_out: if (vport->port_type != LPFC_PHYSICAL_PORT) { ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); if (!ndlp) - return 0; + goto fdmi_cmd_free_rspvirt; } fallthrough; case SLI_MGMT_RPA: @@ -3372,7 +3397,7 @@ port_out: if (vport->port_type != LPFC_PHYSICAL_PORT) { ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); if (!ndlp) - return 0; + goto fdmi_cmd_free_rspvirt; } fallthrough; case SLI_MGMT_DPA: @@ -3433,7 +3458,8 @@ fdmi_cmd_exit: void lpfc_delayed_disc_tmo(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, delayed_disc_tmo); + struct lpfc_vport *vport = timer_container_of(vport, t, + delayed_disc_tmo); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; @@ -3691,7 +3717,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport, /* fill in BDEs for command */ /* Allocate buffer for command payload */ - mp = kmalloc(sizeof(*mp), GFP_KERNEL); + mp = kmalloc_obj(*mp); if (!mp) goto vmid_free_mp_exit; @@ -3700,7 +3726,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport, goto vmid_free_mp_virt_exit; /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + bmp = kmalloc_obj(*bmp); if (!bmp) goto vmid_free_bmp_exit; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3fd1aa5cc78c..052023fc1733 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -872,6 +872,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_rpi); len += scnprintf(buf+len, size-len, "flag:x%08lx ", ndlp->nlp_flag); + if (ndlp->nlp_enc_info.status) { + len += scnprintf(buf + len, + size - len, "ENCRYPTED"); + len += scnprintf(buf + len, size - len, + ndlp->nlp_enc_info.level + ? "(CNSA2.0) " : "(CNSA1.0) "); + } if (!ndlp->nlp_type) len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) @@ -1944,7 +1951,7 @@ lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file) goto out; } - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -1994,7 +2001,7 @@ lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file) goto out; } - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2038,7 +2045,7 @@ lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2080,7 +2087,7 @@ lpfc_debugfs_multixripools_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2125,7 +2132,7 @@ lpfc_debugfs_lockstat_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2262,7 +2269,7 @@ lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file) phba->cfg_ras_fwlog_buffsize, &size)) goto out; - debug = kzalloc(sizeof(*debug), GFP_KERNEL); + debug = kzalloc_obj(*debug); if (!debug) goto out; @@ -2309,7 +2316,7 @@ lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2351,7 +2358,7 @@ lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2373,93 +2380,117 @@ out: static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { - struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; - char cbuf[32]; - uint64_t tmp = 0; + int kind = debugfs_get_aux_num(file); + char cbuf[32] = {0}; int cnt = 0; - if (dent == phba->debug_writeGuard) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); - else if (dent == phba->debug_writeApp) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); - else if (dent == phba->debug_writeRef) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); - else if (dent == phba->debug_readGuard) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); - else if (dent == phba->debug_readApp) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); - else if (dent == phba->debug_readRef) - cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); - else if (dent == phba->debug_InjErrNPortID) - cnt = scnprintf(cbuf, 32, "0x%06x\n", + switch (kind) { + case writeGuard: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_wgrd_cnt); + break; + case writeApp: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_wapp_cnt); + break; + case writeRef: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_wref_cnt); + break; + case readGuard: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_rgrd_cnt); + break; + case readApp: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_rapp_cnt); + break; + case readRef: + cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", + phba->lpfc_injerr_rref_cnt); + break; + case InjErrNPortID: + cnt = scnprintf(cbuf, sizeof(cbuf), "0x%06x\n", phba->lpfc_injerr_nportid); - else if (dent == phba->debug_InjErrWWPN) { - memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); - tmp = cpu_to_be64(tmp); - cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp); - } else if (dent == phba->debug_InjErrLBA) { - if (phba->lpfc_injerr_lba == (sector_t)(-1)) - cnt = scnprintf(cbuf, 32, "off\n"); + break; + case InjErrWWPN: + cnt = scnprintf(cbuf, sizeof(cbuf), "0x%016llx\n", + be64_to_cpu(phba->lpfc_injerr_wwpn.u.wwn_be)); + break; + case InjErrLBA: + if (phba->lpfc_injerr_lba == LPFC_INJERR_LBA_OFF) + cnt = scnprintf(cbuf, sizeof(cbuf), "off\n"); else - cnt = scnprintf(cbuf, 32, "0x%llx\n", - (uint64_t) phba->lpfc_injerr_lba); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0547 Unknown debugfs error injection entry\n"); + cnt = scnprintf(cbuf, sizeof(cbuf), "0x%llx\n", + (uint64_t)phba->lpfc_injerr_lba); + break; + default: + lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, + "0547 Unknown debugfs error injection entry\n"); + break; + } return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt); } static ssize_t lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { - struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; - char dstbuf[33]; - uint64_t tmp = 0; - int size; + int kind = debugfs_get_aux_num(file); + char dstbuf[33] = {0}; + unsigned long long tmp; + unsigned long size; - memset(dstbuf, 0, 33); - size = (nbytes < 32) ? nbytes : 32; + size = (nbytes < (sizeof(dstbuf) - 1)) ? nbytes : (sizeof(dstbuf) - 1); if (copy_from_user(dstbuf, buf, size)) return -EFAULT; - if (dent == phba->debug_InjErrLBA) { - if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && - (dstbuf[2] == 'f')) - tmp = (uint64_t)(-1); + if (kstrtoull(dstbuf, 0, &tmp)) { + if (kind != InjErrLBA || !strstr(dstbuf, "off")) + return -EINVAL; } - if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) - return -EINVAL; - - if (dent == phba->debug_writeGuard) + switch (kind) { + case writeGuard: phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeApp) + break; + case writeApp: phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeRef) + break; + case writeRef: phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readGuard) + break; + case readGuard: phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readApp) + break; + case readApp: phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readRef) + break; + case readRef: phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_InjErrLBA) - phba->lpfc_injerr_lba = (sector_t)tmp; - else if (dent == phba->debug_InjErrNPortID) + break; + case InjErrLBA: + if (strstr(dstbuf, "off")) + phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + else + phba->lpfc_injerr_lba = (sector_t)tmp; + break; + case InjErrNPortID: phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); - else if (dent == phba->debug_InjErrWWPN) { - tmp = cpu_to_be64(tmp); - memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0548 Unknown debugfs error injection entry\n"); - + break; + case InjErrWWPN: + phba->lpfc_injerr_wwpn.u.wwn_be = cpu_to_be64(tmp); + break; + default: + lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, + "0548 Unknown debugfs error injection entry\n"); + break; + } return nbytes; } @@ -2491,7 +2522,7 @@ lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2657,7 +2688,7 @@ lpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2745,7 +2776,7 @@ lpfc_debugfs_scsistat_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2799,7 +2830,7 @@ lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -2926,7 +2957,7 @@ lpfc_debugfs_nvmeio_trc_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -3031,7 +3062,7 @@ lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -3195,7 +3226,7 @@ lpfc_idiag_open(struct inode *inode, struct file *file) { struct lpfc_debug *debug; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) return -ENOMEM; @@ -5440,7 +5471,7 @@ lpfc_cgn_buffer_open(struct inode *inode, struct file *file) struct lpfc_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -5532,7 +5563,7 @@ lpfc_rx_monitor_open(struct inode *inode, struct file *file) struct lpfc_rx_monitor_debug *debug; int rc = -ENOMEM; - debug = kmalloc(sizeof(*debug), GFP_KERNEL); + debug = kmalloc_obj(*debug); if (!debug) goto out; @@ -5728,7 +5759,7 @@ static const struct file_operations lpfc_debugfs_op_slow_ring_trc = { }; static struct dentry *lpfc_debugfs_root = NULL; -static atomic_t lpfc_debugfs_hba_count; +static unsigned int lpfc_debugfs_hba_count; /* * File operations for the iDiag debugfs @@ -6050,7 +6081,12 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) /* Setup lpfc root directory */ if (!lpfc_debugfs_root) { lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL); - atomic_set(&lpfc_debugfs_hba_count, 0); + lpfc_debugfs_hba_count = 0; + if (IS_ERR(lpfc_debugfs_root)) { + lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, + "0527 Cannot create debugfs lpfc\n"); + return; + } } if (!lpfc_debugfs_start_time) lpfc_debugfs_start_time = jiffies; @@ -6061,159 +6097,96 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) pport_setup = true; phba->hba_debugfs_root = debugfs_create_dir(name, lpfc_debugfs_root); - atomic_inc(&lpfc_debugfs_hba_count); - atomic_set(&phba->debugfs_vport_count, 0); + phba->debugfs_vport_count = 0; + if (IS_ERR(phba->hba_debugfs_root)) { + lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, + "0528 Cannot create debugfs %s\n", name); + return; + } + lpfc_debugfs_hba_count++; /* Multi-XRI pools */ - snprintf(name, sizeof(name), "multixripools"); - phba->debug_multixri_pools = - debugfs_create_file(name, S_IFREG | 0644, - phba->hba_debugfs_root, - phba, - &lpfc_debugfs_op_multixripools); - if (IS_ERR(phba->debug_multixri_pools)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0527 Cannot create debugfs multixripools\n"); - goto debug_failed; - } + debugfs_create_file("multixripools", 0644, + phba->hba_debugfs_root, phba, + &lpfc_debugfs_op_multixripools); /* Congestion Info Buffer */ - scnprintf(name, sizeof(name), "cgn_buffer"); - phba->debug_cgn_buffer = - debugfs_create_file(name, S_IFREG | 0644, - phba->hba_debugfs_root, - phba, &lpfc_cgn_buffer_op); - if (IS_ERR(phba->debug_cgn_buffer)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "6527 Cannot create debugfs " - "cgn_buffer\n"); - goto debug_failed; - } + debugfs_create_file("cgn_buffer", 0644, phba->hba_debugfs_root, + phba, &lpfc_cgn_buffer_op); /* RX Monitor */ - scnprintf(name, sizeof(name), "rx_monitor"); - phba->debug_rx_monitor = - debugfs_create_file(name, S_IFREG | 0644, - phba->hba_debugfs_root, - phba, &lpfc_rx_monitor_op); - if (IS_ERR(phba->debug_rx_monitor)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "6528 Cannot create debugfs " - "rx_monitor\n"); - goto debug_failed; - } + debugfs_create_file("rx_monitor", 0644, phba->hba_debugfs_root, + phba, &lpfc_rx_monitor_op); /* RAS log */ - snprintf(name, sizeof(name), "ras_log"); - phba->debug_ras_log = - debugfs_create_file(name, 0644, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_ras_log); - if (IS_ERR(phba->debug_ras_log)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "6148 Cannot create debugfs" - " ras_log\n"); - goto debug_failed; - } + debugfs_create_file("ras_log", 0644, phba->hba_debugfs_root, + phba, &lpfc_debugfs_ras_log); /* Setup hbqinfo */ - snprintf(name, sizeof(name), "hbqinfo"); - phba->debug_hbqinfo = - debugfs_create_file(name, S_IFREG | 0644, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_hbqinfo); + debugfs_create_file("hbqinfo", 0644, phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_hbqinfo); #ifdef LPFC_HDWQ_LOCK_STAT /* Setup lockstat */ - snprintf(name, sizeof(name), "lockstat"); - phba->debug_lockstat = - debugfs_create_file(name, S_IFREG | 0644, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_lockstat); - if (IS_ERR(phba->debug_lockstat)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "4610 Can't create debugfs lockstat\n"); - goto debug_failed; - } + debugfs_create_file("lockstat", 0644, phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_lockstat); #endif - - /* Setup dumpHBASlim */ if (phba->sli_rev < LPFC_SLI_REV4) { - snprintf(name, sizeof(name), "dumpHBASlim"); - phba->debug_dumpHBASlim = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpHBASlim); - } else - phba->debug_dumpHBASlim = NULL; + /* Setup dumpHBASlim */ + debugfs_create_file("dumpHBASlim", 0644, + phba->hba_debugfs_root, phba, + &lpfc_debugfs_op_dumpHBASlim); + } - /* Setup dumpHostSlim */ if (phba->sli_rev < LPFC_SLI_REV4) { - snprintf(name, sizeof(name), "dumpHostSlim"); - phba->debug_dumpHostSlim = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpHostSlim); - } else - phba->debug_dumpHostSlim = NULL; + /* Setup dumpHostSlim */ + debugfs_create_file("dumpHostSlim", 0644, + phba->hba_debugfs_root, phba, + &lpfc_debugfs_op_dumpHostSlim); + } /* Setup DIF Error Injections */ - snprintf(name, sizeof(name), "InjErrLBA"); - phba->debug_InjErrLBA = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + debugfs_create_file_aux_num("InjErrLBA", 0644, + phba->hba_debugfs_root, phba, + InjErrLBA, + &lpfc_debugfs_op_dif_err); phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - snprintf(name, sizeof(name), "InjErrNPortID"); - phba->debug_InjErrNPortID = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "InjErrWWPN"); - phba->debug_InjErrWWPN = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "writeGuardInjErr"); - phba->debug_writeGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "writeAppInjErr"); - phba->debug_writeApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "writeRefInjErr"); - phba->debug_writeRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "readGuardInjErr"); - phba->debug_readGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "readAppInjErr"); - phba->debug_readApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - - snprintf(name, sizeof(name), "readRefInjErr"); - phba->debug_readRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + debugfs_create_file_aux_num("InjErrNPortID", 0644, + phba->hba_debugfs_root, phba, + InjErrNPortID, + &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("InjErrWWPN", 0644, + phba->hba_debugfs_root, phba, + InjErrWWPN, + &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("writeGuardInjErr", 0644, + phba->hba_debugfs_root, phba, + writeGuard, + &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("writeAppInjErr", 0644, + phba->hba_debugfs_root, phba, + writeApp, &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("writeRefInjErr", 0644, + phba->hba_debugfs_root, phba, + writeRef, &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("readGuardInjErr", 0644, + phba->hba_debugfs_root, phba, + readGuard, + &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("readAppInjErr", 0644, + phba->hba_debugfs_root, phba, + readApp, &lpfc_debugfs_op_dif_err); + + debugfs_create_file_aux_num("readRefInjErr", 0644, + phba->hba_debugfs_root, phba, + readRef, &lpfc_debugfs_op_dif_err); /* Setup slow ring trace */ if (lpfc_debugfs_max_slow_ring_trc) { @@ -6227,40 +6200,34 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) i++; } lpfc_debugfs_max_slow_ring_trc = (1 << i); - pr_err("lpfc_debugfs_max_disc_trc changed to " - "%d\n", lpfc_debugfs_max_disc_trc); + pr_info("lpfc_debugfs_max_slow_ring_trc " + "changed to %d\n", + lpfc_debugfs_max_slow_ring_trc); } } - snprintf(name, sizeof(name), "slow_ring_trace"); - phba->debug_slow_ring_trc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_slow_ring_trc); + debugfs_create_file("slow_ring_trace", 0644, + phba->hba_debugfs_root, phba, + &lpfc_debugfs_op_slow_ring_trc); if (!phba->slow_ring_trc) { - phba->slow_ring_trc = kcalloc( - lpfc_debugfs_max_slow_ring_trc, - sizeof(struct lpfc_debugfs_trc), - GFP_KERNEL); + phba->slow_ring_trc = kzalloc_objs(struct lpfc_debugfs_trc, + lpfc_debugfs_max_slow_ring_trc); if (!phba->slow_ring_trc) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0416 Cannot create debugfs " "slow_ring buffer\n"); - goto debug_failed; + goto out; } atomic_set(&phba->slow_ring_trc_cnt, 0); } - snprintf(name, sizeof(name), "nvmeio_trc"); - phba->debug_nvmeio_trc = - debugfs_create_file(name, 0644, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_nvmeio_trc); + debugfs_create_file("nvmeio_trc", 0644, phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_nvmeio_trc); atomic_set(&phba->nvmeio_trc_cnt, 0); if (lpfc_debugfs_max_nvmeio_trc) { num = lpfc_debugfs_max_nvmeio_trc - 1; - if (num & lpfc_debugfs_max_disc_trc) { + if (num & lpfc_debugfs_max_nvmeio_trc) { /* Change to be a power of 2 */ num = lpfc_debugfs_max_nvmeio_trc; i = 0; @@ -6269,10 +6236,9 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) i++; } lpfc_debugfs_max_nvmeio_trc = (1 << i); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0575 lpfc_debugfs_max_nvmeio_trc " - "changed to %d\n", - lpfc_debugfs_max_nvmeio_trc); + pr_info("lpfc_debugfs_max_nvmeio_trc changed " + "to %d\n", + lpfc_debugfs_max_nvmeio_trc); } phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc; @@ -6289,7 +6255,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } phba->nvmeio_trc_on = 1; phba->nvmeio_trc_output_idx = 0; - phba->nvmeio_trc = NULL; } else { nvmeio_off: phba->nvmeio_trc_size = 0; @@ -6303,7 +6268,12 @@ nvmeio_off: if (!vport->vport_debugfs_root) { vport->vport_debugfs_root = debugfs_create_dir(name, phba->hba_debugfs_root); - atomic_inc(&phba->debugfs_vport_count); + if (IS_ERR(vport->vport_debugfs_root)) { + lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, + "0529 Cannot create debugfs %s\n", name); + return; + } + phba->debugfs_vport_count++; } if (lpfc_debugfs_max_disc_trc) { @@ -6317,8 +6287,8 @@ nvmeio_off: i++; } lpfc_debugfs_max_disc_trc = (1 << i); - pr_err("lpfc_debugfs_max_disc_trc changed to %d\n", - lpfc_debugfs_max_disc_trc); + pr_info("lpfc_debugfs_max_disc_trc changed to %d\n", + lpfc_debugfs_max_disc_trc); } } @@ -6330,54 +6300,27 @@ nvmeio_off: lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0418 Cannot create debugfs disc trace " "buffer\n"); - goto debug_failed; + goto out; } atomic_set(&vport->disc_trc_cnt, 0); - snprintf(name, sizeof(name), "discovery_trace"); - vport->debug_disc_trc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_disc_trc); - snprintf(name, sizeof(name), "nodelist"); - vport->debug_nodelist = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_nodelist); - - snprintf(name, sizeof(name), "nvmestat"); - vport->debug_nvmestat = - debugfs_create_file(name, 0644, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_nvmestat); - - snprintf(name, sizeof(name), "scsistat"); - vport->debug_scsistat = - debugfs_create_file(name, 0644, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_scsistat); - if (IS_ERR(vport->debug_scsistat)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "4611 Cannot create debugfs scsistat\n"); - goto debug_failed; - } + debugfs_create_file("discovery_trace", 0644, vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_disc_trc); - snprintf(name, sizeof(name), "ioktime"); - vport->debug_ioktime = - debugfs_create_file(name, 0644, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_ioktime); - if (IS_ERR(vport->debug_ioktime)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0815 Cannot create debugfs ioktime\n"); - goto debug_failed; - } + debugfs_create_file("nodelist", 0644, vport->vport_debugfs_root, vport, + &lpfc_debugfs_op_nodelist); + + debugfs_create_file("nvmestat", 0644, vport->vport_debugfs_root, vport, + &lpfc_debugfs_op_nvmestat); + + debugfs_create_file("scsistat", 0644, vport->vport_debugfs_root, vport, + &lpfc_debugfs_op_scsistat); + + debugfs_create_file("ioktime", 0644, vport->vport_debugfs_root, vport, + &lpfc_debugfs_op_ioktime); - snprintf(name, sizeof(name), "hdwqstat"); - vport->debug_hdwqstat = - debugfs_create_file(name, 0644, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_hdwqstat); + debugfs_create_file("hdwqstat", 0644, vport->vport_debugfs_root, vport, + &lpfc_debugfs_op_hdwqstat); /* * The following section is for additional directories/files for the @@ -6385,93 +6328,58 @@ nvmeio_off: */ if (!pport_setup) - goto debug_failed; + return; /* * iDiag debugfs root entry points for SLI4 device only */ if (phba->sli_rev < LPFC_SLI_REV4) - goto debug_failed; + return; - snprintf(name, sizeof(name), "iDiag"); if (!phba->idiag_root) { phba->idiag_root = - debugfs_create_dir(name, phba->hba_debugfs_root); + debugfs_create_dir("iDiag", phba->hba_debugfs_root); /* Initialize iDiag data structure */ memset(&idiag, 0, sizeof(idiag)); } /* iDiag read PCI config space */ - snprintf(name, sizeof(name), "pciCfg"); - if (!phba->idiag_pci_cfg) { - phba->idiag_pci_cfg = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_pciCfg); - idiag.offset.last_rd = 0; - } + debugfs_create_file("pciCfg", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_pciCfg); + idiag.offset.last_rd = 0; /* iDiag PCI BAR access */ - snprintf(name, sizeof(name), "barAcc"); - if (!phba->idiag_bar_acc) { - phba->idiag_bar_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_barAcc); - idiag.offset.last_rd = 0; - } + debugfs_create_file("barAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_barAcc); + idiag.offset.last_rd = 0; /* iDiag get PCI function queue information */ - snprintf(name, sizeof(name), "queInfo"); - if (!phba->idiag_que_info) { - phba->idiag_que_info = - debugfs_create_file(name, S_IFREG|S_IRUGO, - phba->idiag_root, phba, &lpfc_idiag_op_queInfo); - } + debugfs_create_file("queInfo", 0444, phba->idiag_root, phba, + &lpfc_idiag_op_queInfo); /* iDiag access PCI function queue */ - snprintf(name, sizeof(name), "queAcc"); - if (!phba->idiag_que_acc) { - phba->idiag_que_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_queAcc); - } + debugfs_create_file("queAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_queAcc); /* iDiag access PCI function doorbell registers */ - snprintf(name, sizeof(name), "drbAcc"); - if (!phba->idiag_drb_acc) { - phba->idiag_drb_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); - } + debugfs_create_file("drbAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_drbAcc); /* iDiag access PCI function control registers */ - snprintf(name, sizeof(name), "ctlAcc"); - if (!phba->idiag_ctl_acc) { - phba->idiag_ctl_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); - } + debugfs_create_file("ctlAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_ctlAcc); /* iDiag access mbox commands */ - snprintf(name, sizeof(name), "mbxAcc"); - if (!phba->idiag_mbx_acc) { - phba->idiag_mbx_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); - } + debugfs_create_file("mbxAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_mbxAcc); /* iDiag extents access commands */ if (phba->sli4_hba.extents_in_use) { - snprintf(name, sizeof(name), "extAcc"); - if (!phba->idiag_ext_acc) { - phba->idiag_ext_acc = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, - &lpfc_idiag_op_extAcc); - } + debugfs_create_file("extAcc", 0644, phba->idiag_root, phba, + &lpfc_idiag_op_extAcc); } - -debug_failed: +out: + /* alloc'ed items are kfree'd in lpfc_debugfs_terminate */ return; #endif } @@ -6496,145 +6404,26 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) kfree(vport->disc_trc); vport->disc_trc = NULL; - debugfs_remove(vport->debug_disc_trc); /* discovery_trace */ - vport->debug_disc_trc = NULL; - - debugfs_remove(vport->debug_nodelist); /* nodelist */ - vport->debug_nodelist = NULL; - - debugfs_remove(vport->debug_nvmestat); /* nvmestat */ - vport->debug_nvmestat = NULL; - - debugfs_remove(vport->debug_scsistat); /* scsistat */ - vport->debug_scsistat = NULL; - - debugfs_remove(vport->debug_ioktime); /* ioktime */ - vport->debug_ioktime = NULL; - - debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */ - vport->debug_hdwqstat = NULL; - if (vport->vport_debugfs_root) { debugfs_remove(vport->vport_debugfs_root); /* vportX */ vport->vport_debugfs_root = NULL; - atomic_dec(&phba->debugfs_vport_count); + phba->debugfs_vport_count--; } - if (atomic_read(&phba->debugfs_vport_count) == 0) { - - debugfs_remove(phba->debug_multixri_pools); /* multixripools*/ - phba->debug_multixri_pools = NULL; - - debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ - phba->debug_hbqinfo = NULL; - - debugfs_remove(phba->debug_cgn_buffer); - phba->debug_cgn_buffer = NULL; - - debugfs_remove(phba->debug_rx_monitor); - phba->debug_rx_monitor = NULL; - - debugfs_remove(phba->debug_ras_log); - phba->debug_ras_log = NULL; - -#ifdef LPFC_HDWQ_LOCK_STAT - debugfs_remove(phba->debug_lockstat); /* lockstat */ - phba->debug_lockstat = NULL; -#endif - debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ - phba->debug_dumpHBASlim = NULL; - - debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ - phba->debug_dumpHostSlim = NULL; - - debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ - phba->debug_InjErrLBA = NULL; - - debugfs_remove(phba->debug_InjErrNPortID); - phba->debug_InjErrNPortID = NULL; - - debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */ - phba->debug_InjErrWWPN = NULL; - - debugfs_remove(phba->debug_writeGuard); /* writeGuard */ - phba->debug_writeGuard = NULL; - - debugfs_remove(phba->debug_writeApp); /* writeApp */ - phba->debug_writeApp = NULL; - - debugfs_remove(phba->debug_writeRef); /* writeRef */ - phba->debug_writeRef = NULL; - - debugfs_remove(phba->debug_readGuard); /* readGuard */ - phba->debug_readGuard = NULL; - - debugfs_remove(phba->debug_readApp); /* readApp */ - phba->debug_readApp = NULL; - - debugfs_remove(phba->debug_readRef); /* readRef */ - phba->debug_readRef = NULL; - + if (!phba->debugfs_vport_count) { kfree(phba->slow_ring_trc); phba->slow_ring_trc = NULL; - /* slow_ring_trace */ - debugfs_remove(phba->debug_slow_ring_trc); - phba->debug_slow_ring_trc = NULL; - - debugfs_remove(phba->debug_nvmeio_trc); - phba->debug_nvmeio_trc = NULL; - kfree(phba->nvmeio_trc); phba->nvmeio_trc = NULL; - /* - * iDiag release - */ - if (phba->sli_rev == LPFC_SLI_REV4) { - /* iDiag extAcc */ - debugfs_remove(phba->idiag_ext_acc); - phba->idiag_ext_acc = NULL; - - /* iDiag mbxAcc */ - debugfs_remove(phba->idiag_mbx_acc); - phba->idiag_mbx_acc = NULL; - - /* iDiag ctlAcc */ - debugfs_remove(phba->idiag_ctl_acc); - phba->idiag_ctl_acc = NULL; - - /* iDiag drbAcc */ - debugfs_remove(phba->idiag_drb_acc); - phba->idiag_drb_acc = NULL; - - /* iDiag queAcc */ - debugfs_remove(phba->idiag_que_acc); - phba->idiag_que_acc = NULL; - - /* iDiag queInfo */ - debugfs_remove(phba->idiag_que_info); - phba->idiag_que_info = NULL; - - /* iDiag barAcc */ - debugfs_remove(phba->idiag_bar_acc); - phba->idiag_bar_acc = NULL; - - /* iDiag pciCfg */ - debugfs_remove(phba->idiag_pci_cfg); - phba->idiag_pci_cfg = NULL; - - /* Finally remove the iDiag debugfs root */ - debugfs_remove(phba->idiag_root); - phba->idiag_root = NULL; - } - if (phba->hba_debugfs_root) { debugfs_remove(phba->hba_debugfs_root); /* fnX */ phba->hba_debugfs_root = NULL; - atomic_dec(&lpfc_debugfs_hba_count); + lpfc_debugfs_hba_count--; } - if (atomic_read(&lpfc_debugfs_hba_count) == 0) { + if (!lpfc_debugfs_hba_count) { debugfs_remove(lpfc_debugfs_root); /* lpfc */ lpfc_debugfs_root = NULL; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 8d2e8d05bbc0..a1464f8ac331 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -44,6 +44,9 @@ /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 +/* hdwqinfo output buffer size */ +#define LPFC_HDWQINFO_SIZE 8192 + /* nvmestat output buffer size */ #define LPFC_NVMESTAT_SIZE 8192 #define LPFC_IOKTIME_SIZE 8192 @@ -322,6 +325,17 @@ enum { * discovery */ #endif /* H_LPFC_DEBUG_FS */ +enum { + writeGuard = 1, + writeApp, + writeRef, + readGuard, + readApp, + readRef, + InjErrLBA, + InjErrNPortID, + InjErrWWPN, +}; /* * Driver debug utility routines outside of debugfs. The debug utility diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 3d47dc7458d1..a377e97cbe65 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -77,6 +77,11 @@ struct lpfc_node_rrqs { unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; }; +struct lpfc_enc_info { + u8 status; /* encryption status for session */ + u8 level; /* CNSA encryption level */ +}; + enum lpfc_fc4_xpt_flags { NLP_XPT_REGD = 0x1, SCSI_XPT_REGD = 0x2, @@ -132,12 +137,15 @@ struct lpfc_nodelist { uint16_t nlp_maxframe; /* Max RCV frame size */ uint8_t nlp_class_sup; /* Supported Classes */ uint8_t nlp_retry; /* used for ELS retries */ - uint8_t nlp_fcp_info; /* class info, bits 0-3 */ + uint8_t nlp_fcp_info; /* class info, bits 0-2 */ +#define NLP_FCP_CLASS_MASK 0x07 /* class info bitmask */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ u8 nlp_nvme_info; /* NVME NSLER Support */ uint8_t vmid_support; /* destination VMID support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ + struct lpfc_enc_info nlp_enc_info; /* Encryption information struct */ + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct lpfc_hba *phba; struct fc_rport *rport; /* scsi_transport_fc port structure */ @@ -208,6 +216,7 @@ enum lpfc_nlp_flag { NPR list */ NLP_RM_DFLT_RPI = 26, /* need to remove leftover dflt RPI */ NLP_NODEV_REMOVE = 27, /* Defer removal till discovery ends */ + NLP_FLOGI_DFR_ACC = 28, /* FLOGI LS_ACC was Deferred */ NLP_SC_REQ = 29, /* Target requires authentication */ NLP_FIRSTBURST = 30, /* Target supports FirstBurst */ NLP_RPI_REGISTERED = 31 /* nlp_rpi is valid */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 1d7db49a8fe4..4e3fe89283e4 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -216,7 +216,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, /* fill in BDEs for command */ /* Allocate buffer for command payload */ - pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); + pcmd = kmalloc_obj(*pcmd); if (pcmd) pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); if (!pcmd || !pcmd->virt) @@ -226,7 +226,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, /* Allocate buffer for response payload */ if (expect_rsp) { - prsp = kmalloc(sizeof(*prsp), GFP_KERNEL); + prsp = kmalloc_obj(*prsp); if (prsp) prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); @@ -238,7 +238,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, } /* Allocate buffer for Buffer ptr list */ - pbuflist = kmalloc(sizeof(*pbuflist), GFP_KERNEL); + pbuflist = kmalloc_obj(*pbuflist); if (pbuflist) pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); @@ -650,8 +650,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; @@ -934,10 +932,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { /* One additional decrement on node reference count to - * trigger the release of the node + * trigger the release of the node. Make sure the ndlp + * is marked NLP_DROPPED. */ - if (!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } goto out; } @@ -995,9 +998,10 @@ stop_rr_fcf_flogi: IOERR_LOOP_OPEN_FAILURE))) lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, "2858 FLOGI Status:x%x/x%x TMO" - ":x%x Data x%lx x%x\n", + ":x%x Data x%lx x%x x%lx x%x\n", ulp_status, ulp_word4, tmo, - phba->hba_flag, phba->fcf.fcf_flag); + phba->hba_flag, phba->fcf.fcf_flag, + ndlp->nlp_flag, ndlp->fc4_xpt_flags); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { @@ -1015,14 +1019,17 @@ stop_rr_fcf_flogi: * reference to trigger node release. */ if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && - !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, "0150 FLOGI Status:x%x/x%x " - "xri x%x TMO:x%x refcnt %d\n", + "xri x%x iotag x%x TMO:x%x refcnt %d\n", ulp_status, ulp_word4, cmdiocb->sli4_xritag, - tmo, kref_read(&ndlp->kref)); + cmdiocb->iotag, tmo, kref_read(&ndlp->kref)); /* If this is not a loop open failure, bail out */ if (!(ulp_status == IOSTAT_LOCAL_REJECT && @@ -1100,7 +1107,7 @@ stop_rr_fcf_flogi: vport->vmid_flag = 0; } if (sp->cmn.priority_tagging) - vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | + vport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | LPFC_VMID_TYPE_PRIO); /* @@ -1279,12 +1286,29 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t tmo, did; int rc; + /* It's possible for lpfc to reissue a FLOGI on an ndlp that is marked + * NLP_DROPPED. This happens when the FLOGI completed with the XB bit + * set causing lpfc to reference the ndlp until the XRI_ABORTED CQE is + * issued. The time window for the XRI_ABORTED CQE can be as much as + * 2*2*RA_TOV allowing for ndlp reuse of this type when the link is + * cycling quickly. When true, restore the initial reference and remove + * the NLP_DROPPED flag as lpfc is retrying. + */ + if (test_and_clear_bit(NLP_DROPPED, &ndlp->nlp_flag)) { + if (!lpfc_nlp_get(ndlp)) + return 1; + } + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_FLOGI); - if (!elsiocb) + if (!elsiocb) { + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_DISCOVERY, + "4296 Unable to prepare FLOGI iocb\n"); return 1; + } wqe = &elsiocb->wqe; pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; @@ -1334,6 +1358,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Can't do SLI4 class2 without support sequence coalescing */ sp->cls2.classValid = 0; sp->cls2.seqDelivery = 0; + + /* Fill out Auxiliary Parameter Data */ + if (phba->pni) { + sp->aux.flags = + AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; + sp->aux.pni = cpu_to_be64(phba->pni); + sp->aux.npiv_cnt = cpu_to_be16(phba->max_vpi - 1); + } } else { /* Historical, setting sequential-delivery bit for SLI3 */ sp->cls2.seqDelivery = (sp->cls2.classValid) ? 1 : 0; @@ -1366,10 +1398,8 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->sli3_options, 0, 0); elsiocb->ndlp = lpfc_nlp_get(ndlp); - if (!elsiocb->ndlp) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (!elsiocb->ndlp) + goto err_out; /* Avoid race with FLOGI completion and hba_flags. */ set_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); @@ -1379,9 +1409,8 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (rc == IOCB_ERROR) { clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); clear_bit(HBA_FLOGI_OUTSTANDING, &phba->hba_flag); - lpfc_els_free_iocb(phba, elsiocb); lpfc_nlp_put(ndlp); - return 1; + goto err_out; } /* Clear external loopback plug detected flag */ @@ -1413,11 +1442,12 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ox_id; } - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3354 Xmit deferred FLOGI ACC: rx_id: x%x," - " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, phba->hba_flag); + /* The LS_ACC completion needs to drop the initial reference. + * This is a special case for Pt2Pt because both FLOGIs need + * to complete and lpfc defers the LS_ACC when the remote + * FLOGI arrives before the driver's FLOGI. + */ + set_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag); /* Send deferred FLOGI ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc, @@ -1433,10 +1463,25 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ndlp = NULL; } + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3354 Xmit deferred FLOGI ACC: rx_id: x%x," + " ox_id: x%x, ndlp x%px hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, + phba->defer_flogi_acc.ndlp, + phba->hba_flag); + vport->fc_myDID = did; } return 0; + + err_out: + lpfc_els_free_iocb(phba, elsiocb); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_DISCOVERY, + "4297 Issue FLOGI: Cannot send IOCB\n"); + return 1; } /** @@ -1977,6 +2022,58 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_nlp_put(ndlp); return; } + +/** + * lpfc_check_encryption - Reports an ndlp's encryption information + * @phba: pointer to lpfc hba data structure. + * @ndlp: pointer to a node-list data structure. + * @cmdiocb: pointer to lpfc command iocbq data structure. + * @rspiocb: pointer to lpfc response iocbq data structure. + * + * This routine is called in the completion callback function for issuing + * or receiving a Port Login (PLOGI) command. In a PLOGI completion, if FEDIF + * is supported, encryption information will be provided in completion status + * data. If @phba supports FEDIF, a log message containing encryption + * information will be logged. Encryption status is also saved for encryption + * reporting with upper layer through the rport encryption attribute. + **/ +static void +lpfc_check_encryption(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + u32 did = ndlp->nlp_DID; + struct lpfc_enc_info *nlp_enc_info = &ndlp->nlp_enc_info; + char enc_status[FC_RPORT_ENCRYPTION_STATUS_MAX_LEN] = {0}; + char enc_level[8] = "N/A"; + u8 encryption; + + if (phba->sli4_hba.encryption_support && + ((did & Fabric_DID_MASK) != Fabric_DID_MASK)) { + encryption = bf_get(lpfc_wcqe_c_enc, + &rspiocb->wcqe_cmpl); + nlp_enc_info->status = encryption; + + strscpy(enc_status, encryption ? "Encrypted" : "Unencrypted", + sizeof(enc_status)); + + if (encryption) { + nlp_enc_info->level = bf_get(lpfc_wcqe_c_enc_lvl, + &rspiocb->wcqe_cmpl); + strscpy(enc_level, nlp_enc_info->level ? "CNSA2.0" : + "CNSA1.0", + sizeof(enc_level)); + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ENCRYPTION, + "0924 DID:x%06x %s Session " + "Established, Encryption Level:%s " + "rpi:x%x\n", + ndlp->nlp_DID, enc_status, enc_level, + ndlp->nlp_rpi); + } +} + /** * lpfc_cmpl_els_plogi - Completion callback function for plogi * @phba: pointer to lpfc hba data structure. @@ -2116,6 +2213,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + sp = (struct serv_parm *)((u8 *)prsp->virt + sizeof(u32)); @@ -2248,7 +2347,8 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - sp->cmn.bbRcvSizeMsb &= 0xF; + if (!test_bit(FC_PT2PT, &vport->fc_flag)) + sp->cmn.bbRcvSizeMsb &= 0xF; /* Check if the destination port supports VMID */ ndlp->vmid_support = 0; @@ -2367,7 +2467,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mode = KERN_INFO; /* Warn PRLI status */ - lpfc_printf_vlog(vport, mode, LOG_ELS, + lpfc_vlog_msg(vport, mode, LOG_ELS, "2754 PRLI DID:%06X Status:x%x/x%x, " "data: x%x x%x x%lx\n", ndlp->nlp_DID, ulp_status, @@ -2549,7 +2649,9 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } npr->estabImagePair = 1; npr->readXferRdyDis = 1; - if (vport->cfg_first_burst_size) + if (phba->sli_rev == LPFC_SLI_REV4 && + !test_bit(HBA_FCOE_MODE, &phba->hba_flag) && + vport->cfg_first_burst_size) npr->writeXferRdyDis = 1; /* For FCP support */ @@ -3024,6 +3126,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, ulp_status, ulp_word4); + /* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */ if (lpfc_error_lost_link(vport, ulp_status, ulp_word4)) skip_recovery = 1; } @@ -3262,7 +3365,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) return -ENOMEM; } rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID, - (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi); + (u8 *)&ns_ndlp->fc_sparam, mbox, fc_ndlp->nlp_rpi); if (rc) { rc = -EACCES; goto out; @@ -3306,7 +3409,8 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) * * 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(). + * Request (SCR), lpfc_issue_els_scr(), Exchange Diagnostic Capabilities (EDC), + * lpfc_issue_els_edc() and the ELS RDF, lpfc_issue_els_rdf(). * These commands will be retried once only for ELS timeout errors. **/ static void @@ -3379,11 +3483,21 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb); return; } + if (ulp_status) { /* ELS discovery cmd completes with error */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, "4203 ELS cmd x%x error: x%x x%X\n", cmd, ulp_status, ulp_word4); + + /* In the case where the ELS cmd completes with an error and + * the node does not have RPI registered, the node is + * outstanding and should put its initial reference. + */ + if ((cmd == ELS_CMD_SCR || cmd == ELS_CMD_RDF) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) && + !test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); goto out; } @@ -3452,6 +3566,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; + bool node_created = false; cmdsize = (sizeof(uint32_t) + sizeof(SCR)); @@ -3461,21 +3576,21 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); + node_created = true; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); if (!elsiocb) - return 1; + goto out_node_created; if (phba->sli_rev == LPFC_SLI_REV4) { rc = lpfc_reg_fab_ctrl_node(vport, ndlp); if (rc) { - lpfc_els_free_iocb(phba, elsiocb); lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, "0937 %s: Failed to reg fc node, rc %d\n", __func__, rc); - return 1; + goto out_free_iocb; } } pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; @@ -3494,23 +3609,27 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) phba->fc_stat.elsXmitSCR++; elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; elsiocb->ndlp = lpfc_nlp_get(ndlp); - if (!elsiocb->ndlp) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (!elsiocb->ndlp) + goto out_free_iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue SCR: did:x%x refcnt %d", ndlp->nlp_DID, kref_read(&ndlp->kref), 0); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - lpfc_nlp_put(ndlp); - return 1; - } + if (rc == IOCB_ERROR) + goto out_iocb_error; return 0; + +out_iocb_error: + lpfc_nlp_put(ndlp); +out_free_iocb: + lpfc_els_free_iocb(phba, elsiocb); +out_node_created: + if (node_created) + lpfc_nlp_put(ndlp); + return 1; } /** @@ -3597,8 +3716,8 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue RSCN: did:x%x", - ndlp->nlp_DID, 0, 0); + "Issue RSCN: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { @@ -3705,10 +3824,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) lpfc_nlp_put(ndlp); return 1; } - /* 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; } @@ -3726,7 +3842,12 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) * * Return code * 0 - Successfully issued rdf command - * 1 - Failed to issue rdf command + * < 0 - Failed to issue rdf command + * -EACCES - RDF not required for NPIV_PORT + * -ENODEV - No fabric controller device available + * -ENOMEM - No available memory + * -EIO - The mailbox failed to complete successfully. + * **/ int lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) @@ -3737,32 +3858,37 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) struct lpfc_nodelist *ndlp; uint16_t cmdsize; int rc; + bool node_created = false; + int err; cmdsize = sizeof(*prdf); + /* RDF ELS is not required on an NPIV VN_Port. */ + if (vport->port_type == LPFC_NPIV_PORT) + return -EACCES; + 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); + node_created = true; } - /* RDF ELS is not required on an NPIV VN_Port. */ - if (vport->port_type == LPFC_NPIV_PORT) - return -EACCES; - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RDF); - if (!elsiocb) - return -ENOMEM; + if (!elsiocb) { + err = -ENOMEM; + goto out_node_created; + } /* Configure the payload for the supported FPIN events. */ prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->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)); + sizeof(struct fc_els_rdf_hdr)); 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)); @@ -3781,8 +3907,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) { - lpfc_els_free_iocb(phba, elsiocb); - return -EIO; + err = -EIO; + goto out_free_iocb; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -3791,11 +3917,19 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - lpfc_nlp_put(ndlp); - return -EIO; + err = -EIO; + goto out_iocb_error; } return 0; + +out_iocb_error: + lpfc_nlp_put(ndlp); +out_free_iocb: + lpfc_els_free_iocb(phba, elsiocb); +out_node_created: + if (node_created) + lpfc_nlp_put(ndlp); + return err; } /** @@ -3816,19 +3950,23 @@ static int lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { + int rc; + + rc = lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL); /* Send LS_ACC */ - if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) { + if (rc) { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, - "1623 Failed to RDF_ACC from x%x for x%x\n", - ndlp->nlp_DID, vport->fc_myDID); + "1623 Failed to RDF_ACC from x%x for x%x Data: %d\n", + ndlp->nlp_DID, vport->fc_myDID, rc); return -EIO; } + rc = lpfc_issue_els_rdf(vport, 0); /* Issue new RDF for reregistering */ - if (lpfc_issue_els_rdf(vport, 0)) { + if (rc) { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, - "2623 Failed to re register RDF for x%x\n", - vport->fc_myDID); + "2623 Failed to re register RDF for x%x Data: %d\n", + vport->fc_myDID, rc); return -EIO; } @@ -4191,18 +4329,28 @@ lpfc_format_edc_cgn_desc(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) static bool lpfc_link_is_lds_capable(struct lpfc_hba *phba) { - if (!(phba->lmt & LMT_64Gb)) + if (!(phba->lmt & (LMT_64Gb | LMT_128Gb))) return false; if (phba->sli_rev != LPFC_SLI_REV4) return false; if (phba->sli4_hba.conf_trunk) { - if (phba->trunk_link.phy_lnk_speed == LPFC_USER_LINK_SPEED_64G) + switch (phba->trunk_link.phy_lnk_speed) { + case LPFC_USER_LINK_SPEED_128G: + case LPFC_USER_LINK_SPEED_64G: return true; - } else if (phba->fc_linkspeed == LPFC_LINK_SPEED_64GHZ) { + default: + return false; + } + } + + switch (phba->fc_linkspeed) { + case LPFC_LINK_SPEED_128GHZ: + case LPFC_LINK_SPEED_64GHZ: return true; + default: + return false; } - return false; } /** @@ -4299,7 +4447,7 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry) rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of + * lpfc_els_free_iocb routine to trigger the release of * the node. */ lpfc_els_free_iocb(phba, elsiocb); @@ -4333,7 +4481,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) if (!test_and_clear_bit(NLP_DELAY_TMO, &nlp->nlp_flag)) return; - del_timer_sync(&nlp->nlp_delayfunc); + timer_delete_sync(&nlp->nlp_delayfunc); nlp->nlp_last_elscmd = 0; if (!list_empty(&nlp->els_retry_evt.evt_listp)) { list_del_init(&nlp->els_retry_evt.evt_listp); @@ -4378,7 +4526,8 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) void lpfc_els_retry_delay(struct timer_list *t) { - struct lpfc_nodelist *ndlp = from_timer(ndlp, t, nlp_delayfunc); + struct lpfc_nodelist *ndlp = timer_container_of(ndlp, t, + nlp_delayfunc); struct lpfc_vport *vport = ndlp->vport; struct lpfc_hba *phba = vport->phba; unsigned long flags; @@ -4431,7 +4580,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) * firing and before processing the timer, cancel the * nlp_delayfunc. */ - del_timer_sync(&ndlp->nlp_delayfunc); + timer_delete_sync(&ndlp->nlp_delayfunc); retry = ndlp->nlp_retry; ndlp->nlp_retry = 0; @@ -5126,7 +5275,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - /* The I/O iocb is complete. Clear the node and first dmbuf */ + /* The I/O iocb is complete. Clear the node and first dmabuf */ elsiocb->ndlp = NULL; /* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */ @@ -5159,14 +5308,12 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = elsiocb->cmd_dmabuf; lpfc_els_free_data(phba, buf_ptr1); - elsiocb->cmd_dmabuf = NULL; } } if (elsiocb->bpl_dmabuf) { buf_ptr = elsiocb->bpl_dmabuf; lpfc_els_free_bpl(phba, buf_ptr); - elsiocb->bpl_dmabuf = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -5304,11 +5451,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; LPFC_MBOXQ_t *mbox = NULL; u32 ulp_status, ulp_word4, tmo, did, iotag; + u32 cmd; if (!vport) { lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, "3177 null vport in ELS rsp\n"); - goto out; + goto release; } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -5333,17 +5481,20 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } + if (!ulp_status && test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)) + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "ELS rsp cmpl: status:x%x/x%x did:x%x", ulp_status, ulp_word4, did); /* ELS response tag <ulpIoTag> completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0110 ELS response tag x%x completes " + "0110 ELS response tag x%x completes fc_flag x%lx" "Data: x%x x%x x%x x%x x%lx x%x x%x x%x %p %p\n", - iotag, ulp_status, ulp_word4, tmo, + iotag, vport->fc_flag, ulp_status, ulp_word4, tmo, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox, ndlp); - if (mbox) { + if (mbox && !test_bit(FC_PT2PT, &vport->fc_flag)) { if (ulp_status == 0 && test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { if (!lpfc_unreg_rpi(vport, ndlp) && @@ -5402,6 +5553,10 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out_free_mbox: lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + } else if (mbox && test_bit(FC_PT2PT, &vport->fc_flag) && + test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { + lpfc_mbx_cmpl_reg_login(phba, mbox); + clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); } out: if (ndlp && shost) { @@ -5414,7 +5569,7 @@ out: * these conditions because it doesn't need the login. */ if (phba->sli_rev == LPFC_SLI_REV4 && - vport && vport->port_type == LPFC_NPIV_PORT && + vport->port_type == LPFC_NPIV_PORT && !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE && @@ -5430,6 +5585,27 @@ out: } } + /* The driver's unsolicited deferred FLOGI ACC in Pt2Pt needs to + * release the initial reference because the put after the free_iocb + * call removes only the reference from the defer logic. This FLOGI + * is never registered with the SCSI transport. + */ + if (test_bit(FC_PT2PT, &vport->fc_flag) && + test_and_clear_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag)) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, + "3357 Pt2Pt Defer FLOGI ACC ndlp x%px, " + "nflags x%lx, fc_flag x%lx\n", + ndlp, ndlp->nlp_flag, + vport->fc_flag); + cmd = *((u32 *)cmdiocb->cmd_dmabuf->virt); + if (cmd == ELS_CMD_ACC) { + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); + } + } + +release: /* Release the originating I/O reference. */ lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); @@ -5564,7 +5740,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cls1.classValid = 0; sp->cls2.classValid = 0; sp->cls3.classValid = 0; - sp->cls4.classValid = 0; /* Copy our worldwide names */ memcpy(&sp->portName, &vport->fc_sparam.portName, @@ -5578,7 +5753,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - sp->cmn.bbRcvSizeMsb &= 0xF; + if (!test_bit(FC_PT2PT, &vport->fc_flag)) + sp->cmn.bbRcvSizeMsb &= 0xF; /* If our firmware supports this feature, convey that * info to the target using the vendor specific field. @@ -7381,7 +7557,7 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (RDP_NPORT_ID_SIZE != be32_to_cpu(rdp_req->nport_id_desc.length)) goto rjt_logerr; - rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL); + rdp_context = kzalloc_obj(struct lpfc_rdp_context); if (!rdp_context) { rjt_err = LSRJT_UNABLE_TPC; goto error; @@ -7686,7 +7862,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, goto rjt; } - lcb_context = kmalloc(sizeof(*lcb_context), GFP_KERNEL); + lcb_context = kmalloc_obj(*lcb_context); if (!lcb_context) { rjt_err = LSRJT_UNABLE_TPC; goto rjt; @@ -7860,6 +8036,13 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) /* Move all affected nodes by pending RSCNs to NPR state. */ list_for_each_entry_safe(ndlp, n, &vport->fc_nodes, nlp_listp) { + if (test_bit(FC_UNLOADING, &vport->load_flag)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "1000 %s Unloading set\n", + __func__); + return 0; + } + if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) || !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) continue; @@ -8045,8 +8228,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { tmo = ((phba->fc_ratov * 3) + 3); mod_timer(&vport->fc_disctmo, - jiffies + - msecs_to_jiffies(1000 * tmo)); + jiffies + secs_to_jiffies(tmo)); } return 0; } @@ -8081,7 +8263,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { tmo = ((phba->fc_ratov * 3) + 3); mod_timer(&vport->fc_disctmo, - jiffies + msecs_to_jiffies(1000 * tmo)); + jiffies + secs_to_jiffies(tmo)); } if ((rscn_cnt < FC_MAX_HOLD_RSCN) && !test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) { @@ -8369,9 +8551,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3311 Rcv Flogi PS x%x new PS x%x " - "fc_flag x%lx new fc_flag x%lx\n", + "fc_flag x%lx new fc_flag x%lx, hba_flag x%lx\n", port_state, vport->port_state, - fc_flag, vport->fc_flag); + fc_flag, vport->fc_flag, phba->hba_flag); /* * We temporarily set fc_myDID to make it look like we are @@ -8391,13 +8573,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, &wqe->xmit_els_rsp.wqe_com); vport->fc_myDID = did; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3344 Deferring FLOGI ACC: rx_id: x%x," - " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, phba->hba_flag); - phba->defer_flogi_acc.flag = true; /* This nlp_get is paired with nlp_puts that reset the @@ -8406,6 +8581,14 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * processed or cancelled. */ phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3344 Deferring FLOGI ACC: rx_id: x%x," + " ox_id: x%x, ndlp x%px, hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, + phba->defer_flogi_acc.ndlp, + phba->hba_flag); return 0; } @@ -8723,7 +8906,7 @@ reject_out: * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Timout Value (RTV) IOCB received as an + * This routine processes Read Timeout Value (RTV) 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 @@ -9386,7 +9569,7 @@ out: void lpfc_els_timeout(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, els_tmofunc); + struct lpfc_vport *vport = timer_container_of(vport, t, els_tmofunc); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; @@ -9511,7 +9694,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) if (!list_empty(&pring->txcmplq)) if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) mod_timer(&vport->els_tmofunc, - jiffies + msecs_to_jiffies(1000 * timeout)); + jiffies + secs_to_jiffies(timeout)); } /** @@ -9569,18 +9752,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) mbx_tmo_err = test_bit(MBX_TMO_ERR, &phba->bit_flags); /* First we need to issue aborts to outstanding cmds on txcmpl */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { + if (piocb->vport != vport) + continue; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2243 iotag = 0x%x cmd_flag = 0x%x " - "ulp_command = 0x%x this_vport %x " - "sli_flag = 0x%x\n", + "ulp_command = 0x%x sli_flag = 0x%x\n", piocb->iotag, piocb->cmd_flag, get_job_cmnd(phba, piocb), - (piocb->vport == vport), phba->sli.sli_flag); - if (piocb->vport != vport) - continue; - if ((phba->sli.sli_flag & LPFC_SLI_ACTIVE) && !mbx_tmo_err) { if (piocb->cmd_flag & LPFC_IO_LIBDFC) continue; @@ -9804,7 +9985,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (*payload == ELS_CMD_LOGO) { - logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); + logo_data = kmalloc_obj(struct lpfc_logo_event); if (!logo_data) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0148 Failed to allocate memory " @@ -9813,8 +9994,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, } els_data = &logo_data->header; } else { - els_data = kmalloc(sizeof(struct lpfc_els_event_header), - GFP_KERNEL); + els_data = kmalloc_obj(struct lpfc_els_event_header); if (!els_data) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0149 Failed to allocate memory " @@ -10131,10 +10311,8 @@ cleanup: cpu_to_le16(value); cp->cgn_warn_freq = cpu_to_le16(value); - crc = lpfc_cgn_calc_crc32 - (cp, - LPFC_CGN_INFO_SZ, - LPFC_CGN_CRC32_SEED); + crc = lpfc_cgn_calc_crc32( + cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(crc); } @@ -10348,11 +10526,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) { - if (newnode) - lpfc_nlp_put(ndlp); + if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) goto dropit; - } elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) @@ -10834,7 +11009,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); /* * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting cmd_dmabuf to NULL. + * if they are done with "mp" by setting cmd_dmabuf/bpl_dmabuf to NULL. */ if (elsiocb->cmd_dmabuf) { lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf); @@ -10899,7 +11074,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) "3334 Delay fc port discovery for %d secs\n", phba->fc_ratov); mod_timer(&vport->delayed_disc_tmo, - jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); + jiffies + secs_to_jiffies(phba->fc_ratov)); return; } @@ -11156,7 +11331,7 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba) if (!ndlp) return; - mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); + mod_timer(&ndlp->nlp_delayfunc, jiffies + secs_to_jiffies(1)); set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; phba->pport->port_state = LPFC_FLOGI; @@ -11254,6 +11429,11 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, "0126 FDISC cmpl status: x%x/x%x)\n", ulp_status, ulp_word4); + + /* drop initial reference */ + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); + goto fdisc_failed; } @@ -11409,6 +11589,13 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; + /* Fill out Auxiliary Parameter Data */ + if (phba->pni) { + sp->aux.flags = + AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; + sp->aux.pni = cpu_to_be64(phba->pni); + } + pcmd += sizeof(uint32_t); /* CSP Word 2 */ pcmd += sizeof(uint32_t); /* CSP Word 3 */ pcmd += sizeof(uint32_t); /* CSP Word 4 */ @@ -11597,7 +11784,8 @@ err: void lpfc_fabric_block_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fabric_block_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, + fabric_block_timer); unsigned long iflags; uint32_t tmo_posted; @@ -12002,7 +12190,11 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, iflag); - + lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI | + LOG_DISCOVERY | LOG_NODE, + "0732 ELS XRI ABORT on Node: ndlp=x%px " + "xri=x%x\n", + ndlp, xri); if (ndlp) { lpfc_set_rrq_active(phba, ndlp, sglq_entry->sli4_lxritag, @@ -12150,8 +12342,7 @@ lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (!vport->qfpa_res) { max_desc = FCELSSIZE / sizeof(*vport->qfpa_res); - vport->qfpa_res = kcalloc(max_desc, sizeof(*vport->qfpa_res), - GFP_KERNEL); + vport->qfpa_res = kzalloc_objs(*vport->qfpa_res, max_desc); if (!vport->qfpa_res) goto out; } @@ -12164,8 +12355,7 @@ lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, desc = (struct priority_range_desc *)(pcmd + 8); vmid_range = vport->vmid_priority.vmid_range; if (!vmid_range) { - vmid_range = kcalloc(MAX_PRIORITY_DESC, sizeof(*vmid_range), - GFP_KERNEL); + vmid_range = kzalloc_objs(*vmid_range, MAX_PRIORITY_DESC); if (!vmid_range) { kfree(vport->qfpa_res); goto out; @@ -12263,7 +12453,7 @@ lpfc_vmid_uvem(struct lpfc_vport *vport, if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) return -ENXIO; - vmid_context = kmalloc(sizeof(*vmid_context), GFP_KERNEL); + vmid_context = kmalloc_obj(*vmid_context); if (!vmid_context) return -ENOMEM; elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_UVEM_SIZE, 2, diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 36e66df36a18..f3a85f6c796e 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -161,7 +161,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) struct lpfc_hba *phba; struct lpfc_work_evt *evtp; unsigned long iflags; - bool nvme_reg = false; + bool drop_initial_node_ref = false; ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; if (!ndlp) @@ -183,13 +183,19 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) /* Don't schedule a worker thread event if the vport is going down. */ if (test_bit(FC_UNLOADING, &vport->load_flag) || - !test_bit(HBA_SETUP, &phba->hba_flag)) { + (phba->sli_rev == LPFC_SLI_REV4 && + !test_bit(HBA_SETUP, &phba->hba_flag))) { spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; - if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) - nvme_reg = true; + /* Only 1 thread can drop the initial node reference. + * If not registered for NVME and NLP_DROPPED flag is + * clear, remove the initial reference. + */ + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + drop_initial_node_ref = true; /* The scsi_transport is done with the rport so lpfc cannot * call to unregister. @@ -200,13 +206,16 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) /* If NLP_XPT_REGD was cleared in lpfc_nlp_unreg_node, * unregister calls were made to the scsi and nvme * transports and refcnt was already decremented. Clear - * the NLP_XPT_REGD flag only if the NVME Rport is + * the NLP_XPT_REGD flag only if the NVME nrport is * confirmed unregistered. */ - if (!nvme_reg && ndlp->fc4_xpt_flags & NLP_XPT_REGD) { - ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) { + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) + ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; spin_unlock_irqrestore(&ndlp->lock, iflags); - lpfc_nlp_put(ndlp); /* may free ndlp */ + + /* Release scsi transport reference */ + lpfc_nlp_put(ndlp); } else { spin_unlock_irqrestore(&ndlp->lock, iflags); } @@ -214,24 +223,24 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) spin_unlock_irqrestore(&ndlp->lock, iflags); } - /* Only 1 thread can drop the initial node reference. If - * another thread has set NLP_DROPPED, this thread is done. - */ - if (nvme_reg || test_bit(NLP_DROPPED, &ndlp->nlp_flag)) - return; - - set_bit(NLP_DROPPED, &ndlp->nlp_flag); - lpfc_nlp_put(ndlp); + if (drop_initial_node_ref) + lpfc_nlp_put(ndlp); return; } if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) return; - /* check for recovered fabric node */ - if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - ndlp->nlp_DID == Fabric_DID) + /* Ignore callback for a mismatched (stale) rport */ + if (ndlp->rport != rport) { + lpfc_vlog_msg(vport, KERN_WARNING, LOG_NODE, + "6788 fc rport mismatch: d_id x%06x ndlp x%px " + "fc rport x%px node rport x%px state x%x " + "refcnt %u\n", + ndlp->nlp_DID, ndlp, rport, ndlp->rport, + ndlp->nlp_state, kref_read(&ndlp->kref)); return; + } if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -415,7 +424,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) { - lpfc_nlp_get(ndlp); + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, "8438 Devloss timeout reversed on DID x%x " "refcnt %d ndlp %p flag x%lx " @@ -557,7 +566,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } - lpfc_nlp_put(ndlp); + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); return fcf_inuse; } @@ -715,8 +725,7 @@ lpfc_alloc_fast_evt(struct lpfc_hba *phba) { if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT) return NULL; - ret = kzalloc(sizeof(struct lpfc_fast_path_event), - GFP_ATOMIC); + ret = kzalloc_obj(struct lpfc_fast_path_event, GFP_ATOMIC); if (ret) { atomic_inc(&phba->fast_event_count); INIT_LIST_HEAD(&ret->work_evt.evt_listp); @@ -1130,7 +1139,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will * be queued to worker thread for processing */ - evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC); + evtp = kmalloc_obj(struct lpfc_work_evt, GFP_ATOMIC); if (!evtp) return 0; @@ -1222,7 +1231,7 @@ lpfc_linkdown_port(struct lpfc_vport *vport) /* Stop delayed Nport discovery */ clear_bit(FC_DISC_DELAYED, &vport->fc_flag); - del_timer_sync(&vport->delayed_disc_tmo); + timer_delete_sync(&vport->delayed_disc_tmo); if (phba->sli_rev == LPFC_SLI_REV4 && vport->port_type == LPFC_PHYSICAL_PORT && @@ -1258,6 +1267,10 @@ lpfc_linkdown(struct lpfc_hba *phba) } phba->defer_flogi_acc.flag = false; + /* reinitialize initial HBA flag */ + clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); + clear_bit(HBA_RHBA_CMPL, &phba->hba_flag); + /* Clear external loopback plug detected flag */ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; @@ -1412,7 +1425,7 @@ lpfc_linkup(struct lpfc_hba *phba) /* Unblock fabric iocbs if they are blocked */ clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - del_timer_sync(&phba->fabric_block_timer); + timer_delete_sync(&phba->fabric_block_timer); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) @@ -1428,10 +1441,6 @@ lpfc_linkup(struct lpfc_hba *phba) phba->pport->rcv_flogi_cnt = 0; spin_unlock_irq(shost->host_lock); - /* reinitialize initial HBA flag */ - clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); - clear_bit(HBA_RHBA_CMPL, &phba->hba_flag); - return 0; } @@ -3164,7 +3173,11 @@ lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) return; } - lpfc_initial_flogi(vport); + if (!lpfc_initial_flogi(vport)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_ELS, + "2345 Can't issue initial FLOGI\n"); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + } mempool_free(mboxq, phba->mbox_mem_pool); return; } @@ -3237,8 +3250,14 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) return; } - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) - lpfc_initial_fdisc(vport); + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { + if (!lpfc_initial_fdisc(vport)) { + lpfc_printf_vlog(vport, KERN_WARNING, + LOG_MBOX | LOG_ELS, + "2346 Can't issue initial FDISC\n"); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + } + } else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -3518,7 +3537,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) if (phba->fc_topology && phba->fc_topology != bf_get(lpfc_mbx_read_top_topology, la)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3314 Toplogy changed was 0x%x is 0x%x\n", + "3314 Topology changed was 0x%x is 0x%x\n", phba->fc_topology, bf_get(lpfc_mbx_read_top_topology, la)); phba->fc_topology_changed = 1; @@ -3633,8 +3652,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) * defaults. */ if (!test_bit(HBA_FIP_SUPPORT, &phba->hba_flag)) { - fcf_record = kzalloc(sizeof(struct fcf_record), - GFP_KERNEL); + fcf_record = kzalloc_obj(struct fcf_record); if (unlikely(!fcf_record)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -3799,7 +3817,7 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->cmf_active_mode != LPFC_CFG_OFF) lpfc_cmf_signal_init(phba); - if (phba->lmt & LMT_64Gb) + if (phba->lmt & (LMT_64Gb | LMT_128Gb)) lpfc_read_lds_params(phba); } else if (attn_type == LPFC_ATT_LINK_DOWN || @@ -4045,7 +4063,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb = &pmb->u.mb; - vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); + vport_info = kzalloc_obj(struct static_vport_info); if (!vport_info) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0543 lpfc_create_static_vport failed to" @@ -4362,6 +4380,8 @@ out: lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); + if (phba->pni) + lpfc_ns_cmd(vport, SLI_CTNS_RSPNI_PNI, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || @@ -4390,7 +4410,7 @@ out: LOG_INIT | LOG_ELS | LOG_DISCOVERY, "4220 Issue EDC status x%x Data x%x\n", rc, phba->cgn_init_reg_signal); - } else if (phba->lmt & LMT_64Gb) { + } else if (phba->lmt & (LMT_64Gb | LMT_128Gb)) { /* may send link fault capability descriptor */ lpfc_issue_els_edc(vport, 0); } else { @@ -4689,9 +4709,7 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { vport->phba->nport_event_cnt++; if (vport->phba->nvmet_support == 0) { - /* Start devloss if target. */ - if (ndlp->nlp_type & NLP_NVME_TARGET) - lpfc_nvme_unregister_port(vport, ndlp); + lpfc_nvme_unregister_port(vport, ndlp); } else { /* NVMET has no upcall. */ lpfc_nlp_put(ndlp); @@ -4973,7 +4991,7 @@ lpfc_set_disctmo(struct lpfc_vport *vport) tmo, vport->port_state, vport->fc_flag); } - mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo)); + mod_timer(&vport->fc_disctmo, jiffies + secs_to_jiffies(tmo)); set_bit(FC_DISC_TMO, &vport->fc_flag); /* Start Discovery Timer state <hba_state> */ @@ -5004,7 +5022,7 @@ lpfc_can_disctmo(struct lpfc_vport *vport) if (test_bit(FC_DISC_TMO, &vport->fc_flag) || timer_pending(&vport->fc_disctmo)) { clear_bit(FC_DISC_TMO, &vport->fc_flag); - del_timer_sync(&vport->fc_disctmo); + timer_delete_sync(&vport->fc_disctmo); spin_lock_irqsave(&vport->work_port_lock, iflags); vport->work_port_events &= ~WORKER_DISC_TMO; spin_unlock_irqrestore(&vport->work_port_lock, iflags); @@ -5047,7 +5065,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, case CMD_GEN_REQUEST64_CR: if (iocb->ndlp == ndlp) return 1; - fallthrough; + break; case CMD_ELS_REQUEST64_CR: if (remote_id == ndlp->nlp_DID) return 1; @@ -5219,12 +5237,11 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, /* * Free rpi associated with LPFC_NODELIST entry. - * This routine is called from lpfc_freenode(), when we are removing - * a LPFC_NODELIST entry. It is also called if the driver initiates a - * LOGO that completes successfully, and we are waiting to PLOGI back - * to the remote NPort. In addition, it is called after we receive - * and unsolicated ELS cmd, send back a rsp, the rsp completes and - * we are waiting to PLOGI back to the remote NPort. + * This routine is called if the driver initiates a LOGO that completes + * successfully, and we are waiting to PLOGI back to the remote NPort. + * In addition, it is called after we receive and unsolicated ELS cmd, + * send back a rsp, the rsp completes and we are waiting to PLOGI back + * to the remote NPort. */ int lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) @@ -5329,6 +5346,7 @@ out: clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); if (acc_plogi) clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); + memset(&ndlp->nlp_enc_info, 0, sizeof(ndlp->nlp_enc_info)); return 1; } clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); @@ -5495,7 +5513,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) clear_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = 0; - del_timer_sync(&ndlp->nlp_delayfunc); + timer_delete_sync(&ndlp->nlp_delayfunc); list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->dev_loss_evt.evt_listp); @@ -5564,6 +5582,7 @@ static struct lpfc_nodelist * __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) { struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *np = NULL; uint32_t data1; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { @@ -5578,14 +5597,20 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1, ndlp->nlp_rpi, ndlp->active_rrqs_xri_bitmap); - return ndlp; + + /* Check for new or potentially stale node */ + if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) + return ndlp; + np = ndlp; } } - /* FIND node did <did> NOT FOUND */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0932 FIND node did x%x NOT FOUND.\n", did); - return NULL; + if (!np) + /* FIND node did <did> NOT FOUND */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0932 FIND node did x%x NOT FOUND.\n", did); + + return np; } struct lpfc_nodelist * @@ -6046,7 +6071,7 @@ lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) void lpfc_disc_timeout(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo); + struct lpfc_vport *vport = timer_container_of(vport, t, fc_disctmo); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long flags = 0; @@ -6582,11 +6607,6 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) unsigned long flags; if (ndlp) { - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node get: did:x%x flg:x%lx refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref)); - /* The check of ndlp usage to prevent incrementing the * ndlp reference count that is in the process of being * released. @@ -6594,9 +6614,8 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) spin_lock_irqsave(&ndlp->lock, flags); if (!kref_get_unless_zero(&ndlp->kref)) { spin_unlock_irqrestore(&ndlp->lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 %s: ndlp:x%px refcnt:%d\n", - __func__, (void *)ndlp, kref_read(&ndlp->kref)); + pr_info("0276 %s: NDLP x%px has zero reference count. " + "Exiting\n", __func__, ndlp); return NULL; } spin_unlock_irqrestore(&ndlp->lock, flags); @@ -6993,8 +7012,7 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, for (i = 0; i < record_count; i++) { if (!(conn_rec[i].flags & FCFCNCT_VALID)) continue; - conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), - GFP_KERNEL); + conn_entry = kzalloc_obj(struct lpfc_fcf_conn_entry); if (!conn_entry) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2566 Failed to allocate connection" diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 32298285ea5e..6326f7353dd6 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -168,6 +168,11 @@ struct lpfc_sli_ct_request { uint8_t len; uint8_t symbname[255]; } rspn; + struct rspni { /* For RSPNI_PNI requests */ + __be64 pni; + u8 len; + u8 symbname[255]; + } rspni; struct gff { uint32_t PortId; } gff; @@ -213,6 +218,8 @@ struct lpfc_sli_ct_request { sizeof(struct da_id)) #define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rspn)) +#define RSPNI_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ + sizeof(struct rspni)) /* * FsType Definitions @@ -309,6 +316,7 @@ struct lpfc_sli_ct_request { #define SLI_CTNS_RIP_NN 0x0235 #define SLI_CTNS_RIPA_NN 0x0236 #define SLI_CTNS_RSNN_NN 0x0239 +#define SLI_CTNS_RSPNI_PNI 0x0240 #define SLI_CTNS_DA_ID 0x0300 /* @@ -366,6 +374,7 @@ struct lpfc_name { } s; uint8_t wwn[8]; uint64_t name __packed __aligned(4); + __be64 wwn_be __packed __aligned(4); } u; }; @@ -511,6 +520,21 @@ struct class_parms { uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */ }; +enum aux_parm_flags { + AUX_PARM_PNI_VALID = 0x20, /* FC Word 0, bit 29 */ + AUX_PARM_DATA_VALID = 0x40, /* FC Word 0, bit 30 */ +}; + +struct aux_parm { + u8 flags; /* FC Word 0, bit 31:24 */ + u8 ext_feat[3]; /* FC Word 0, bit 23:0 */ + + __be64 pni; /* FC Word 1 and 2, platform name identifier */ + + __be16 rsvd; /* FC Word 3, bit 31:16 */ + __be16 npiv_cnt; /* FC Word 3, bit 15:0 */ +} __packed; + struct serv_parm { /* Structure is in Big Endian format */ struct csp cmn; struct lpfc_name portName; @@ -518,7 +542,7 @@ struct serv_parm { /* Structure is in Big Endian format */ struct class_parms cls1; struct class_parms cls2; struct class_parms cls3; - struct class_parms cls4; + struct aux_parm aux; union { uint8_t vendorVersion[16]; struct { @@ -1747,6 +1771,7 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 #define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 #define PCI_DEVICE_ID_LANCER_G7P_FC 0xf500 +#define PCI_DEVICE_ID_LANCER_G8_FC 0xd300 #define PCI_DEVICE_ID_SAT_SMB 0xf011 #define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 2dedb273b091..f91bde4a6c38 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -100,7 +100,8 @@ struct lpfc_sli_intf { #define lpfc_sli_intf_sli_family_MASK 0x0000000F #define lpfc_sli_intf_sli_family_WORD word0 #define LPFC_SLI_INTF_FAMILY_BE2 0x0 -#define LPFC_SLI_INTF_FAMILY_BE3 0x1 +#define LPFC_SLI_INTF_ASIC_ID 0x1 /* Refer to ASIC_ID register */ +#define LPFC_SLI_INTF_FAMILY_BE3 0x3 #define LPFC_SLI_INTF_FAMILY_LNCR_A0 0xa #define LPFC_SLI_INTF_FAMILY_LNCR_B0 0xb #define LPFC_SLI_INTF_FAMILY_G6 0xc @@ -118,6 +119,17 @@ struct lpfc_sli_intf { #define LPFC_SLI_INTF_IF_TYPE_VIRT 1 }; +struct lpfc_asic_id { + u32 word0; +#define lpfc_asic_id_gen_num_SHIFT 8 +#define lpfc_asic_id_gen_num_MASK 0x000000FF +#define lpfc_asic_id_gen_num_WORD word0 +#define LPFC_SLI_INTF_FAMILY_G8 0x10 +#define lpfc_asic_id_rev_num_SHIFT 0 +#define lpfc_asic_id_rev_num_MASK 0x000000FF +#define lpfc_asic_id_rev_num_WORD word0 +}; + #define LPFC_SLI4_MBX_EMBED true #define LPFC_SLI4_MBX_NEMBED false @@ -437,6 +449,12 @@ struct lpfc_wcqe_complete { #define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF #define lpfc_wcqe_c_cmf_bw_WORD total_data_placed uint32_t parameter; +#define lpfc_wcqe_c_enc_SHIFT 31 +#define lpfc_wcqe_c_enc_MASK 0x00000001 +#define lpfc_wcqe_c_enc_WORD parameter +#define lpfc_wcqe_c_enc_lvl_SHIFT 30 +#define lpfc_wcqe_c_enc_lvl_MASK 0x00000001 +#define lpfc_wcqe_c_enc_lvl_WORD parameter #define lpfc_wcqe_c_bg_edir_SHIFT 5 #define lpfc_wcqe_c_bg_edir_MASK 0x00000001 #define lpfc_wcqe_c_bg_edir_WORD parameter @@ -618,6 +636,10 @@ struct lpfc_register { #define LPFC_PORT_SEM_UE_RECOVERABLE 0xE000 #define LPFC_PORT_SEM_MASK 0xF000 + +/* The following are config space register offsets */ +#define LPFC_ASIC_ID_OFFSET 0x0308 + /* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */ #define LPFC_UERR_STATUS_HI 0x00A4 #define LPFC_UERR_STATUS_LO 0x00A0 @@ -626,7 +648,6 @@ struct lpfc_register { /* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */ #define LPFC_SLI_INTF 0x0058 -#define LPFC_SLI_ASIC_VER 0x009C #define LPFC_CTL_PORT_SEM_OFFSET 0x400 #define lpfc_port_smphr_perr_SHIFT 31 @@ -1328,6 +1349,9 @@ struct cq_context { #define LPFC_CQ_CNT_512 0x1 #define LPFC_CQ_CNT_1024 0x2 #define LPFC_CQ_CNT_WORD7 0x3 +#define lpfc_cq_context_cqe_sz_SHIFT 25 +#define lpfc_cq_context_cqe_sz_MASK 0x00000003 +#define lpfc_cq_context_cqe_sz_WORD word0 #define lpfc_cq_context_autovalid_SHIFT 15 #define lpfc_cq_context_autovalid_MASK 0x00000001 #define lpfc_cq_context_autovalid_WORD word0 @@ -1383,9 +1407,9 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_valid_SHIFT 29 #define lpfc_mbx_cq_create_set_valid_MASK 0x00000001 #define lpfc_mbx_cq_create_set_valid_WORD word1 -#define lpfc_mbx_cq_create_set_cqe_cnt_SHIFT 27 -#define lpfc_mbx_cq_create_set_cqe_cnt_MASK 0x00000003 -#define lpfc_mbx_cq_create_set_cqe_cnt_WORD word1 +#define lpfc_mbx_cq_create_set_cqecnt_SHIFT 27 +#define lpfc_mbx_cq_create_set_cqecnt_MASK 0x00000003 +#define lpfc_mbx_cq_create_set_cqecnt_WORD word1 #define lpfc_mbx_cq_create_set_cqe_size_SHIFT 25 #define lpfc_mbx_cq_create_set_cqe_size_MASK 0x00000003 #define lpfc_mbx_cq_create_set_cqe_size_WORD word1 @@ -1398,13 +1422,16 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_clswm_SHIFT 12 #define lpfc_mbx_cq_create_set_clswm_MASK 0x00000003 #define lpfc_mbx_cq_create_set_clswm_WORD word1 +#define lpfc_mbx_cq_create_set_cqe_cnt_hi_SHIFT 0 +#define lpfc_mbx_cq_create_set_cqe_cnt_hi_MASK 0x0000001F +#define lpfc_mbx_cq_create_set_cqe_cnt_hi_WORD word1 uint32_t word2; #define lpfc_mbx_cq_create_set_arm_SHIFT 31 #define lpfc_mbx_cq_create_set_arm_MASK 0x00000001 #define lpfc_mbx_cq_create_set_arm_WORD word2 -#define lpfc_mbx_cq_create_set_cq_cnt_SHIFT 16 -#define lpfc_mbx_cq_create_set_cq_cnt_MASK 0x00007FFF -#define lpfc_mbx_cq_create_set_cq_cnt_WORD word2 +#define lpfc_mbx_cq_create_set_cqe_cnt_lo_SHIFT 16 +#define lpfc_mbx_cq_create_set_cqe_cnt_lo_MASK 0x00007FFF +#define lpfc_mbx_cq_create_set_cqe_cnt_lo_WORD word2 #define lpfc_mbx_cq_create_set_num_cq_SHIFT 0 #define lpfc_mbx_cq_create_set_num_cq_MASK 0x0000FFFF #define lpfc_mbx_cq_create_set_num_cq_WORD word2 @@ -2936,7 +2963,10 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_WORD word2 - uint32_t rsvd_3; + uint32_t word3; +#define lpfc_mbx_rd_conf_fedif_SHIFT 6 +#define lpfc_mbx_rd_conf_fedif_MASK 0x00000001 +#define lpfc_mbx_rd_conf_fedif_WORD word3 uint32_t word4; #define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0 #define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF @@ -3047,9 +3077,6 @@ struct lpfc_mbx_request_features { #define lpfc_mbx_rq_ftr_rq_iaar_SHIFT 9 #define lpfc_mbx_rq_ftr_rq_iaar_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rq_iaar_WORD word2 -#define lpfc_mbx_rq_ftr_rq_perfh_SHIFT 11 -#define lpfc_mbx_rq_ftr_rq_perfh_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_perfh_WORD word2 #define lpfc_mbx_rq_ftr_rq_mrqp_SHIFT 16 #define lpfc_mbx_rq_ftr_rq_mrqp_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rq_mrqp_WORD word2 @@ -3081,9 +3108,6 @@ struct lpfc_mbx_request_features { #define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT 7 #define lpfc_mbx_rq_ftr_rsp_ifip_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rsp_ifip_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_perfh_SHIFT 11 -#define lpfc_mbx_rq_ftr_rsp_perfh_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_perfh_WORD word3 #define lpfc_mbx_rq_ftr_rsp_mrqp_SHIFT 16 #define lpfc_mbx_rq_ftr_rsp_mrqp_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rsp_mrqp_WORD word3 @@ -3446,10 +3470,6 @@ struct lpfc_sli4_parameters { #define cfg_pvl_MASK 0x00000001 #define cfg_pvl_WORD word19 -#define cfg_pbde_SHIFT 20 -#define cfg_pbde_MASK 0x00000001 -#define cfg_pbde_WORD word19 - uint32_t word20; #define cfg_max_tow_xri_SHIFT 0 #define cfg_max_tow_xri_MASK 0x0000ffff @@ -4469,9 +4489,6 @@ struct wqe_common { #define wqe_irsp_SHIFT 4 #define wqe_irsp_MASK 0x00000001 #define wqe_irsp_WORD word11 -#define wqe_pbde_SHIFT 5 -#define wqe_pbde_MASK 0x00000001 -#define wqe_pbde_WORD word11 #define wqe_sup_SHIFT 6 #define wqe_sup_MASK 0x00000001 #define wqe_sup_WORD word11 @@ -4903,18 +4920,18 @@ struct send_frame_wqe { #define ELS_RDF_REG_TAG_CNT 4 struct lpfc_els_rdf_reg_desc { - struct fc_df_desc_fpin_reg reg_desc; /* descriptor header */ + struct fc_df_desc_fpin_reg_hdr 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 fc_els_rdf_hdr 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 fc_els_rdf_resp_hdr rdf_resp; /* hdr up to descriptors */ struct lpfc_els_rdf_reg_desc reg_d1; /* 1st descriptor */ }; @@ -4963,6 +4980,7 @@ union lpfc_wqe128 { #define MAGIC_NUMBER_G6 0xFEAA0003 #define MAGIC_NUMBER_G7 0xFEAA0005 #define MAGIC_NUMBER_G7P 0xFEAA0020 +#define MAGIC_NUMBER_G8 0xFEAA0070 struct lpfc_grp_hdr { uint32_t size; diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h index 0b1616e93cf4..a0a6e2d379b8 100644 --- a/drivers/scsi/lpfc/lpfc_ids.h +++ b/drivers/scsi/lpfc/lpfc_ids.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -118,6 +118,8 @@ const struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7P_FC, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G8_FC, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bcadf11414c8..968a25235a2d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2026 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. * * www.broadcom.com * @@ -22,6 +22,7 @@ *******************************************************************/ #include <linux/blkdev.h> +#include <linux/crc32.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/idr.h> @@ -595,7 +596,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Set up ring-0 (ELS) timer */ timeout = phba->fc_ratov * 2; mod_timer(&vport->els_tmofunc, - jiffies + msecs_to_jiffies(1000 * timeout)); + jiffies + secs_to_jiffies(timeout)); /* Set up heart beat (HB) timer */ mod_timer(&phba->hb_tmofunc, jiffies + secs_to_jiffies(LPFC_HB_MBOX_INTERVAL)); @@ -604,7 +605,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->last_completion_time = jiffies; /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, - jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); if (test_bit(LINK_DISABLED, &phba->hba_flag)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -788,7 +789,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb)) || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) && - !(phba->lmt & LMT_64Gb))) { + !(phba->lmt & LMT_64Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_128G) && + !(phba->lmt & LMT_128Gb))) { /* Reset link speed to auto */ lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1302 Invalid speed for this board:%d " @@ -1087,7 +1090,6 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) struct lpfc_async_xchg_ctx *ctxp, *ctxp_next; struct lpfc_sli4_hdw_queue *qp; LIST_HEAD(aborts); - LIST_HEAD(nvme_aborts); LIST_HEAD(nvmet_aborts); struct lpfc_sglq *sglq_entry = NULL; int cnt, idx; @@ -1196,7 +1198,7 @@ lpfc_hb_timeout(struct timer_list *t) uint32_t tmo_posted; unsigned long iflag; - phba = from_timer(phba, t, hb_tmofunc); + phba = timer_container_of(phba, t, hb_tmofunc); /* Check for heart beat timeout conditions */ spin_lock_irqsave(&phba->pport->work_port_lock, iflag); @@ -1228,7 +1230,7 @@ lpfc_rrq_timeout(struct timer_list *t) { struct lpfc_hba *phba; - phba = from_timer(phba, t, rrq_tmr); + phba = timer_container_of(phba, t, rrq_tmr); if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { clear_bit(HBA_RRQ_ACTIVE, &phba->hba_flag); return; @@ -1907,6 +1909,9 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, uint32_t intr_mode; LPFC_MBOXQ_t *mboxq; + /* Notifying the transport that the targets are going offline. */ + lpfc_scsi_dev_block(phba); + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) { /* @@ -1943,6 +1948,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, lpfc_offline_prep(phba, mbx_action); lpfc_sli_flush_io_rings(phba); + lpfc_nvme_flush_abts_list(phba); lpfc_nvmels_flush_cmd(phba); lpfc_offline(phba); /* release interrupt for possible resource change */ @@ -2531,7 +2537,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) return; } - if (phba->lmt & LMT_64Gb) + if (phba->lmt & LMT_128Gb) + max_speed = 128; + else if (phba->lmt & LMT_64Gb) max_speed = 64; else if (phba->lmt & LMT_32Gb) max_speed = 32; @@ -2624,27 +2632,33 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BMID: - m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP1150", "PCI-X2", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BSMB: m = (typeof(m)){"LP111", "PCI-X2", "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR: - m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe11000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_SCSP: - m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe11000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"}; + m = (typeof(m)){"LP2105", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; GE = 1; break; case PCI_DEVICE_ID_ZMID: - m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1150", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZSMB: - m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe111", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP101: m = (typeof(m)){"LP101", "PCI-X", @@ -2663,22 +2677,28 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT: - m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_MID: - m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1250", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SMB: - m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe121", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_DCSP: - m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12002-SP", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SCSP: - m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000-SP", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_S: - m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000-S", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_VF: m = (typeof(m)){"LPev12000", "PCIe IOV", @@ -2694,22 +2714,25 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_TIGERSHARK: oneConnect = 1; - m = (typeof(m)){"OCe10100", "PCIe", "FCoE"}; + m = (typeof(m)){"OCe10100", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; break; case PCI_DEVICE_ID_TOMCAT: oneConnect = 1; - m = (typeof(m)){"OCe11100", "PCIe", "FCoE"}; + m = (typeof(m)){"OCe11100", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; break; case PCI_DEVICE_ID_FALCON: m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", - "EmulexSecure Fibre"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BALIUS: m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LANCER_FC: - m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe16000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LANCER_FC_VF: m = (typeof(m)){"LPe16000", "PCIe", @@ -2717,12 +2740,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_LANCER_FCOE: oneConnect = 1; - m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; + m = (typeof(m)){"OCe15100", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; break; case PCI_DEVICE_ID_LANCER_FCOE_VF: oneConnect = 1; m = (typeof(m)){"OCe15100", "PCIe", - "Obsolete, Unsupported FCoE"}; + "Obsolete, Unsupported FCoE Adapter"}; break; case PCI_DEVICE_ID_LANCER_G6_FC: m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; @@ -2733,10 +2757,14 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_LANCER_G7P_FC: m = (typeof(m)){"LPe38000", "PCIe", "Fibre Channel Adapter"}; break; + case PCI_DEVICE_ID_LANCER_G8_FC: + m = (typeof(m)){"LPe42100", "PCIe", "Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; - m = (typeof(m)){"OCe14000", "PCIe", "FCoE"}; + m = (typeof(m)){"OCe14000", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; break; default: m = (typeof(m)){"Unknown", "", ""}; @@ -2800,7 +2828,7 @@ lpfc_sli3_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cn /* 2 buffers can be posted per command */ /* Allocate buffer to post */ - mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + mp1 = kmalloc_obj(struct lpfc_dmabuf); if (mp1) mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys); if (!mp1 || !mp1->virt) { @@ -2813,7 +2841,7 @@ lpfc_sli3_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cn INIT_LIST_HEAD(&mp1->list); /* Allocate buffer to post */ if (cnt > 1) { - mp2 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + mp2 = kmalloc_obj(struct lpfc_dmabuf); if (mp2) mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp2->phys); @@ -3037,19 +3065,6 @@ lpfc_cleanup(struct lpfc_vport *vport) lpfc_vmid_vport_cleanup(vport); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (vport->port_type != LPFC_PHYSICAL_PORT && - ndlp->nlp_DID == Fabric_DID) { - /* Just free up ndlp with Fabric_DID for vports */ - lpfc_nlp_put(ndlp); - continue; - } - - if (ndlp->nlp_DID == Fabric_Cntl_DID && - ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - lpfc_nlp_put(ndlp); - continue; - } - /* Fabric Ports not in UNMAPPED state are cleaned up in the * DEVICE_RM event. */ @@ -3120,8 +3135,8 @@ lpfc_cleanup(struct lpfc_vport *vport) void lpfc_stop_vport_timers(struct lpfc_vport *vport) { - del_timer_sync(&vport->els_tmofunc); - del_timer_sync(&vport->delayed_disc_tmo); + timer_delete_sync(&vport->els_tmofunc); + timer_delete_sync(&vport->delayed_disc_tmo); lpfc_can_disctmo(vport); return; } @@ -3140,7 +3155,7 @@ __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) phba->fcf.fcf_flag &= ~FCF_REDISC_PEND; /* Now, try to stop the timer */ - del_timer(&phba->fcf.redisc_wait); + timer_delete(&phba->fcf.redisc_wait); } /** @@ -3302,12 +3317,12 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) lpfc_stop_vport_timers(phba->pport); cancel_delayed_work_sync(&phba->eq_delay_work); cancel_delayed_work_sync(&phba->idle_stat_delay_work); - del_timer_sync(&phba->sli.mbox_tmo); - del_timer_sync(&phba->fabric_block_timer); - del_timer_sync(&phba->eratt_poll); - del_timer_sync(&phba->hb_tmofunc); + timer_delete_sync(&phba->sli.mbox_tmo); + timer_delete_sync(&phba->fabric_block_timer); + timer_delete_sync(&phba->eratt_poll); + timer_delete_sync(&phba->hb_tmofunc); if (phba->sli_rev == LPFC_SLI_REV4) { - del_timer_sync(&phba->rrq_tmr); + timer_delete_sync(&phba->rrq_tmr); clear_bit(HBA_RRQ_ACTIVE, &phba->hba_flag); } clear_bit(HBA_HBEAT_INP, &phba->hba_flag); @@ -3316,7 +3331,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: /* Stop any LightPulse device specific driver timers */ - del_timer_sync(&phba->fcp_poll_timer); + timer_delete_sync(&phba->fcp_poll_timer); break; case LPFC_PCI_DEV_OC: /* Stop any OneConnect device specific driver timers */ @@ -3361,8 +3376,8 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) /* Determine how long we might wait for the active mailbox * command to be gracefully completed by firmware. */ - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * 1000) + jiffies; + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, + phba->sli.mbox_active)) + jiffies; } spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -3532,7 +3547,7 @@ void lpfc_create_multixri_pools(struct lpfc_hba *phba) count_per_hwq = phba->sli4_hba.io_xri_cnt / hwq_count; for (i = 0; i < hwq_count; i++) { - multixri_pool = kzalloc(sizeof(*multixri_pool), GFP_KERNEL); + multixri_pool = kzalloc_obj(*multixri_pool); if (!multixri_pool) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -4057,8 +4072,7 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) els_xri_cnt); /* allocate the additional els sgls */ for (i = 0; i < xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), - GFP_KERNEL); + sglq_entry = kzalloc_obj(struct lpfc_sglq); if (sglq_entry == NULL) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -4177,8 +4191,7 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) phba->sli4_hba.nvmet_xri_cnt, nvmet_xri_cnt); /* allocate the additional nvmet sgls */ for (i = 0; i < xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), - GFP_KERNEL); + sglq_entry = kzalloc_obj(struct lpfc_sglq); if (sglq_entry == NULL) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -4471,7 +4484,7 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) phba->sli4_hba.io_xri_cnt = 0; for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { - lpfc_ncmd = kzalloc(sizeof(*lpfc_ncmd), GFP_KERNEL); + lpfc_ncmd = kzalloc_obj(*lpfc_ncmd); if (!lpfc_ncmd) break; /* @@ -4630,8 +4643,7 @@ lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport) if (lpfc_is_vmid_enabled(phba)) { vport->vmid = - kcalloc(phba->cfg_max_vmid, sizeof(struct lpfc_vmid), - GFP_KERNEL); + kzalloc_objs(struct lpfc_vmid, phba->cfg_max_vmid); if (!vport->vmid) return -ENOMEM; @@ -5128,7 +5140,7 @@ lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba) static void lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fcf.redisc_wait); + struct lpfc_hba *phba = timer_container_of(phba, t, fcf.redisc_wait); /* Don't send FCF rediscovery event if timer cancelled */ spin_lock_irq(&phba->hbalock); @@ -5159,7 +5171,8 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) static void lpfc_vmid_poll(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll); + struct lpfc_hba *phba = timer_container_of(phba, t, + inactive_vmid_poll); u32 wake_up = 0; /* check if there is a need to issue QFPA */ @@ -5629,8 +5642,7 @@ lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag) cp->cgn_stat_npm = value; } - value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, - LPFC_CGN_CRC32_SEED); + value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(value); } @@ -5892,8 +5904,7 @@ lpfc_cmf_stats_timer(struct hrtimer *timer) cp->cgn_warn_freq = cpu_to_le16(value); cp->cgn_alarm_freq = cpu_to_le16(value); - lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, - LPFC_CGN_CRC32_SEED); + lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(lvalue); hrtimer_forward_now(timer, ktime_set(0, LPFC_SEC_MIN * NSEC_PER_SEC)); @@ -6909,7 +6920,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, * re-instantiate the Vlink using FDISC. */ mod_timer(&ndlp->nlp_delayfunc, - jiffies + msecs_to_jiffies(1000)); + jiffies + secs_to_jiffies(1)); set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; @@ -7116,8 +7127,7 @@ lpfc_cgn_params_parse(struct lpfc_hba *phba, cp->cgn_info_level0 = phba->cgn_p.cgn_param_level0; cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1; cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2; - crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, - LPFC_CGN_CRC32_SEED); + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(crc); } spin_unlock_irq(&phba->hbalock); @@ -7765,9 +7775,8 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) return -ENODEV; if (!phba->sli.sli3_ring) - phba->sli.sli3_ring = kcalloc(LPFC_SLI3_MAX_RING, - sizeof(struct lpfc_sli_ring), - GFP_KERNEL); + phba->sli.sli3_ring = kzalloc_objs(struct lpfc_sli_ring, + LPFC_SLI3_MAX_RING); if (!phba->sli.sli3_ring) return -ENOMEM; @@ -7915,8 +7924,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) int longs; int extra; uint64_t wwn; - u32 if_type; - u32 if_fam; phba->sli4_hba.num_present_cpu = lpfc_present_cpu; phba->sli4_hba.num_possible_cpu = cpumask_last(cpu_possible_mask) + 1; @@ -7938,7 +7945,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate all driver workqueues here */ /* The lpfc_wq workqueue for deferred irq use */ - phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); + phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!phba->wq) return -ENOMEM; @@ -7952,11 +7959,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) timer_setup(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo, 0); /* CMF congestion timer */ - hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - phba->cmf_timer.function = lpfc_cmf_timer; + hrtimer_setup(&phba->cmf_timer, lpfc_cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); /* CMF 1 minute stats collection timer */ - hrtimer_init(&phba->cmf_stats_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - phba->cmf_stats_timer.function = lpfc_cmf_stats_timer; + hrtimer_setup(&phba->cmf_stats_timer, lpfc_cmf_stats_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); /* * Control structure for handling external multi-buffer mailbox @@ -8177,28 +8183,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) */ rc = lpfc_get_sli4_parameters(phba, mboxq); if (rc) { - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - if_fam = bf_get(lpfc_sli_intf_sli_family, - &phba->sli4_hba.sli_intf); - if (phba->sli4_hba.extents_in_use && - phba->sli4_hba.rpi_hdrs_in_use) { - lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "2999 Unsupported SLI4 Parameters " - "Extents and RPI headers enabled.\n"); - if (if_type == LPFC_SLI_INTF_IF_TYPE_0 && - if_fam == LPFC_SLI_INTF_FAMILY_BE2) { - mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; - goto out_free_bsmbx; - } - } - if (!(if_type == LPFC_SLI_INTF_IF_TYPE_0 && - if_fam == LPFC_SLI_INTF_FAMILY_BE2)) { - mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; - goto out_free_bsmbx; - } + lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, + "2999 Could not get SLI4 parameters\n"); + rc = -EIO; + mempool_free(mboxq, phba->mbox_mem_pool); + goto out_free_bsmbx; } /* @@ -8299,10 +8288,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, phba->cfg_nvme_seg_cnt); - if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE) - i = phba->cfg_sg_dma_buf_size; - else - i = SLI4_PAGE_SIZE; + i = min_t(u32, phba->cfg_sg_dma_buf_size, SLI4_PAGE_SIZE); phba->lpfc_sg_dma_buf_pool = dma_pool_create("lpfc_sg_dma_buf_pool", @@ -8372,9 +8358,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_remove_rpi_hdrs; } - phba->sli4_hba.hba_eq_hdl = kcalloc(phba->cfg_irq_chann, - sizeof(struct lpfc_hba_eq_hdl), - GFP_KERNEL); + phba->sli4_hba.hba_eq_hdl = kzalloc_objs(struct lpfc_hba_eq_hdl, + phba->cfg_irq_chann); if (!phba->sli4_hba.hba_eq_hdl) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2572 Failed allocate memory for " @@ -8383,9 +8368,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_free_fcf_rr_bmask; } - phba->sli4_hba.cpu_map = kcalloc(phba->sli4_hba.num_possible_cpu, - sizeof(struct lpfc_vector_map_info), - GFP_KERNEL); + phba->sli4_hba.cpu_map = kzalloc_objs(struct lpfc_vector_map_info, + phba->sli4_hba.num_possible_cpu); if (!phba->sli4_hba.cpu_map) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3327 Failed allocate memory for msi-x " @@ -8402,9 +8386,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_free_hba_cpu_map; } - phba->sli4_hba.idle_stat = kcalloc(phba->sli4_hba.num_possible_cpu, - sizeof(*phba->sli4_hba.idle_stat), - GFP_KERNEL); + phba->sli4_hba.idle_stat = kzalloc_objs(*phba->sli4_hba.idle_stat, + phba->sli4_hba.num_possible_cpu); if (!phba->sli4_hba.idle_stat) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3390 Failed allocation for idle_stat\n"); @@ -8678,7 +8661,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) /* Initialize and populate the iocb list per host. */ INIT_LIST_HEAD(&phba->lpfc_iocb_list); for (i = 0; i < iocb_count; i++) { - iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); + iocbq_entry = kzalloc_obj(struct lpfc_iocbq); if (iocbq_entry == NULL) { printk(KERN_ERR "%s: only allocated %d iocbs of " "expected %d count. Unloading driver.\n", @@ -8928,7 +8911,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * First allocate the protocol header region for the port. The * port expects a 4KB DMA-mapped memory region that is 4K aligned. */ - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + dmabuf = kzalloc_obj(struct lpfc_dmabuf); if (!dmabuf) return NULL; @@ -8946,7 +8929,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) } /* Save the rpi header data for cleanup later. */ - rpi_hdr = kzalloc(sizeof(struct lpfc_rpi_hdr), GFP_KERNEL); + rpi_hdr = kzalloc_obj(struct lpfc_rpi_hdr); if (!rpi_hdr) goto err_free_coherent; @@ -9019,7 +9002,7 @@ lpfc_hba_alloc(struct pci_dev *pdev) struct lpfc_hba *phba; /* Allocate memory for HBA structure */ - phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL); + phba = kzalloc_obj(struct lpfc_hba); if (!phba) { dev_err(&pdev->dev, "failed to allocate hba struct\n"); return NULL; @@ -9091,9 +9074,9 @@ lpfc_setup_fdmi_mask(struct lpfc_vport *vport) vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; } - lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "6077 Setup FDMI mask: hba x%x port x%x\n", - vport->fdmi_hba_mask, vport->fdmi_port_mask); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6077 Setup FDMI mask: hba x%x port x%x\n", + vport->fdmi_hba_mask, vport->fdmi_port_mask); } /** @@ -9737,7 +9720,7 @@ lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) uint32_t pa_addr; uint64_t phys_addr; - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + dmabuf = kzalloc_obj(struct lpfc_dmabuf); if (!dmabuf) return -ENOMEM; @@ -10014,6 +9997,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + if (bf_get(lpfc_mbx_rd_conf_fedif, rd_config)) + phba->sli4_hba.encryption_support = true; + else + phba->sli4_hba.encryption_support = false; + /* Next decide on FPIN or Signal E2E CGN support * For congestion alarms and warnings valid combination are: * 1. FPIN alarms / FPIN warnings @@ -10163,6 +10151,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->cfg_link_speed = LPFC_USER_LINK_SPEED_64G; break; + case LINK_SPEED_128G: + phba->cfg_link_speed = + LPFC_USER_LINK_SPEED_128G; + break; case 0xffff: phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; @@ -10452,9 +10444,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_ecount = LPFC_CQE_DEF_COUNT; if (!phba->sli4_hba.hdwq) { - phba->sli4_hba.hdwq = kcalloc( - phba->cfg_hdw_queue, sizeof(struct lpfc_sli4_hdw_queue), - GFP_KERNEL); + phba->sli4_hba.hdwq = kzalloc_objs(struct lpfc_sli4_hdw_queue, + phba->cfg_hdw_queue); if (!phba->sli4_hba.hdwq) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6427 Failed allocate memory for " @@ -10483,30 +10474,24 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { if (phba->nvmet_support) { - phba->sli4_hba.nvmet_cqset = kcalloc( - phba->cfg_nvmet_mrq, - sizeof(struct lpfc_queue *), - GFP_KERNEL); + phba->sli4_hba.nvmet_cqset = kzalloc_objs(struct lpfc_queue *, + phba->cfg_nvmet_mrq); if (!phba->sli4_hba.nvmet_cqset) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3121 Fail allocate memory for " "fast-path CQ set array\n"); goto out_error; } - phba->sli4_hba.nvmet_mrq_hdr = kcalloc( - phba->cfg_nvmet_mrq, - sizeof(struct lpfc_queue *), - GFP_KERNEL); + phba->sli4_hba.nvmet_mrq_hdr = kzalloc_objs(struct lpfc_queue *, + phba->cfg_nvmet_mrq); if (!phba->sli4_hba.nvmet_mrq_hdr) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3122 Fail allocate memory for " "fast-path RQ set hdr array\n"); goto out_error; } - phba->sli4_hba.nvmet_mrq_data = kcalloc( - phba->cfg_nvmet_mrq, - sizeof(struct lpfc_queue *), - GFP_KERNEL); + phba->sli4_hba.nvmet_mrq_data = kzalloc_objs(struct lpfc_queue *, + phba->cfg_nvmet_mrq); if (!phba->sli4_hba.nvmet_mrq_data) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3124 Fail allocate memory for " @@ -11391,8 +11376,8 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (phba->sli4_hba.cq_max) { kfree(phba->sli4_hba.cq_lookup); - phba->sli4_hba.cq_lookup = kcalloc((phba->sli4_hba.cq_max + 1), - sizeof(struct lpfc_queue *), GFP_KERNEL); + phba->sli4_hba.cq_lookup = kzalloc_objs(struct lpfc_queue *, + (phba->sli4_hba.cq_max + 1)); if (!phba->sli4_hba.cq_lookup) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0549 Failed setup of CQ Lookup table: " @@ -11521,7 +11506,7 @@ lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba) int i; for (i = 0; i < (4 * phba->sli4_hba.cq_ecount); i++) { - cq_event = kmalloc(sizeof(struct lpfc_cq_event), GFP_KERNEL); + cq_event = kmalloc_obj(struct lpfc_cq_event); if (!cq_event) goto out_pool_create_fail; list_add_tail(&cq_event->list, @@ -11819,6 +11804,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) unsigned long bar0map_len, bar1map_len, bar2map_len; int error; uint32_t if_type; + u8 sli_family; if (!pdev) return -ENODEV; @@ -11849,6 +11835,14 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) return -ENODEV; } + /* Check if ASIC_ID register should be read */ + sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf); + if (sli_family == LPFC_SLI_INTF_ASIC_ID) { + if (pci_read_config_dword(pdev, LPFC_ASIC_ID_OFFSET, + &phba->sli4_hba.asic_id.word0)) + return -ENODEV; + } + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); /* * Get the bus address of SLI4 device Bar regions and the @@ -12049,6 +12043,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) iounmap(phba->sli4_hba.conf_regs_memmap_p); if (phba->sli4_hba.dpp_regs_memmap_p) iounmap(phba->sli4_hba.dpp_regs_memmap_p); + if (phba->sli4_hba.dpp_regs_memmap_wc_p) + iounmap(phba->sli4_hba.dpp_regs_memmap_wc_p); break; case LPFC_SLI_INTF_IF_TYPE_1: break; @@ -12762,7 +12758,7 @@ static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) * timer. Wait for the poll timer to retire. */ synchronize_rcu(); - del_timer_sync(&phba->cpuhp_poll_timer); + timer_delete_sync(&phba->cpuhp_poll_timer); } static void lpfc_cpuhp_remove(struct lpfc_hba *phba) @@ -12873,7 +12869,7 @@ lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline) if (offline) { /* Find next online CPU on original mask */ - cpu_next = cpumask_next_wrap(cpu, orig_mask, cpu, true); + cpu_next = cpumask_next_wrap(cpu, orig_mask); cpu_select = lpfc_next_online_cpu(orig_mask, cpu_next); /* Found a valid CPU */ @@ -13065,6 +13061,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) /* Iterate to next offline or online cpu in aff_mask */ cpu = cpumask_next(cpu, aff_mask); + /* Reached the end of the aff_mask */ + if (cpu >= nr_cpu_ids) + break; + /* Find next online cpu in aff_mask to set affinity */ cpu_select = lpfc_next_online_cpu(aff_mask, cpu); } else if (vectors == 1) { @@ -13170,6 +13170,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) eqhdl = lpfc_get_eq_hdl(0); rc = pci_irq_vector(phba->pcidev, 0); if (rc < 0) { + free_irq(phba->pcidev->irq, phba); pci_free_irq_vectors(phba->pcidev); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0496 MSI pci_irq_vec failed (%d)\n", rc); @@ -13250,6 +13251,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) eqhdl = lpfc_get_eq_hdl(0); retval = pci_irq_vector(phba->pcidev, 0); if (retval < 0) { + free_irq(phba->pcidev->irq, phba); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0502 INTR pci_irq_vec failed (%d)\n", retval); @@ -13515,54 +13517,14 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) phba->pport->work_port_events = 0; } -static uint32_t -lpfc_cgn_crc32(uint32_t crc, u8 byte) -{ - uint32_t msb = 0; - uint32_t bit; - - for (bit = 0; bit < 8; bit++) { - msb = (crc >> 31) & 1; - crc <<= 1; - - if (msb ^ (byte & 1)) { - crc ^= LPFC_CGN_CRC32_MAGIC_NUMBER; - crc |= 1; - } - byte >>= 1; - } - return crc; -} - -static uint32_t -lpfc_cgn_reverse_bits(uint32_t wd) -{ - uint32_t result = 0; - uint32_t i; - - for (i = 0; i < 32; i++) { - result <<= 1; - result |= (1 & (wd >> i)); - } - return result; -} - /* * The routine corresponds with the algorithm the HBA firmware * uses to validate the data integrity. */ uint32_t -lpfc_cgn_calc_crc32(void *ptr, uint32_t byteLen, uint32_t crc) +lpfc_cgn_calc_crc32(const void *data, size_t size) { - uint32_t i; - uint32_t result; - uint8_t *data = (uint8_t *)ptr; - - for (i = 0; i < byteLen; ++i) - crc = lpfc_cgn_crc32(crc, data[i]); - - result = ~lpfc_cgn_reverse_bits(crc); - return result; + return ~crc32c(~0, data, size); } void @@ -13611,7 +13573,7 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba) cp->cgn_warn_freq = cpu_to_le16(LPFC_FPIN_INIT_FREQ); cp->cgn_alarm_freq = cpu_to_le16(LPFC_FPIN_INIT_FREQ); - crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(crc); phba->cgn_evt_timestamp = jiffies + @@ -13634,7 +13596,7 @@ lpfc_init_congestion_stat(struct lpfc_hba *phba) memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat)); lpfc_cgn_update_tstamp(phba, &cp->stat_start); - crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ); cp->cgn_info_crc = cpu_to_le32(crc); } @@ -13776,7 +13738,9 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters); sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters); sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters); - sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters); + sli4_params->rqv = + (sli4_params->if_type < LPFC_SLI_INTF_IF_TYPE_2) ? + LPFC_Q_CREATE_VERSION_0 : LPFC_Q_CREATE_VERSION_1; sli4_params->eqav = bf_get(cfg_eqav, mbx_sli4_parameters); sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters); sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters); @@ -13838,12 +13802,6 @@ fcponly: if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - /* Enable embedded Payload BDE if support is indicated */ - if (bf_get(cfg_pbde, mbx_sli4_parameters)) - phba->cfg_enable_pbde = 1; - else - phba->cfg_enable_pbde = 0; - /* * To support Suppress Response feature we must satisfy 3 conditions. * lpfc_suppress_rsp module parameter must be set (default). @@ -13878,9 +13836,8 @@ fcponly: phba->fcp_embed_io = 0; lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME, - "6422 XIB %d PBDE %d: FCP %d NVME %d %d %d\n", + "6422 XIB %d: FCP %d NVME %d %d %d\n", bf_get(cfg_xib, mbx_sli4_parameters), - phba->cfg_enable_pbde, phba->fcp_embed_io, sli4_params->nvme, phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp); @@ -14374,7 +14331,7 @@ lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) * as desired. * * Return codes - * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link + * PCI_ERS_RESULT_CAN_RECOVER - can be recovered without reset * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery * PCI_ERS_RESULT_DISCONNECT - device could not be recovered **/ @@ -14441,12 +14398,6 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) pci_restore_state(pdev); - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - if (pdev->is_busmaster) pci_set_master(pdev); @@ -14551,6 +14502,12 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, u8 sli_family; sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf); + + /* Refer to ASIC_ID register case */ + if (sli_family == LPFC_SLI_INTF_ASIC_ID) + sli_family = bf_get(lpfc_asic_id_gen_num, + &phba->sli4_hba.asic_id); + /* Three cases: (1) FW was not supported on the detected adapter. * (2) FW update has been locked out administratively. * (3) Some other error during FW update. @@ -14563,7 +14520,9 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, (sli_family == LPFC_SLI_INTF_FAMILY_G7 && magic_number != MAGIC_NUMBER_G7) || (sli_family == LPFC_SLI_INTF_FAMILY_G7P && - magic_number != MAGIC_NUMBER_G7P)) { + magic_number != MAGIC_NUMBER_G7P) || + (sli_family == LPFC_SLI_INTF_FAMILY_G8 && + magic_number != MAGIC_NUMBER_G8)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3030 This firmware version is not supported on" " this HBA model. Device:%x Magic:%x Type:%x " @@ -14630,8 +14589,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) "New Version:%s\n", fwrev, image->revision); for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), - GFP_KERNEL); + dmabuf = kzalloc_obj(struct lpfc_dmabuf); if (!dmabuf) { rc = -ENOMEM; goto release_out; diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 59bd2bafc73f..e00d101d548c 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -47,6 +47,7 @@ #define LOG_RSVD1 0x01000000 /* Reserved */ #define LOG_RSVD2 0x02000000 /* Reserved */ #define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */ +#define LOG_ENCRYPTION 0x40000000 /* EDIF Encryption events. */ #define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */ #define LOG_ALL_MSG 0x7fffffff /* LOG all messages */ diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index fb6dbcb86c09..4c058904758d 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -64,7 +64,7 @@ lpfc_mbox_rsrc_prep(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) { struct lpfc_dmabuf *mp; - mp = kmalloc(sizeof(*mp), GFP_KERNEL); + mp = kmalloc_obj(*mp); if (!mp) return -ENOMEM; @@ -625,6 +625,10 @@ lpfc_init_link(struct lpfc_hba * phba, mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; mb->un.varInitLnk.link_speed = LINK_SPEED_64G; break; + case LPFC_USER_LINK_SPEED_128G: + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = LINK_SPEED_128G; + break; case LPFC_USER_LINK_SPEED_AUTO: default: mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; @@ -1869,8 +1873,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ? LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount; /* Allocate record for keeping SGE virtual addresses */ - mbox->sge_array = kzalloc(sizeof(struct lpfc_mbx_nembed_sge_virt), - GFP_KERNEL); + mbox->sge_array = kzalloc_obj(struct lpfc_mbx_nembed_sge_virt); if (!mbox->sge_array) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "2527 Failed to allocate non-embedded SGE " @@ -2140,7 +2143,6 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) /* Set up host requested features. */ bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1); - bf_set(lpfc_mbx_rq_ftr_rq_perfh, &mboxq->u.mqe.un.req_ftrs, 1); /* Enable DIF (block guard) only if configured to do so. */ if (phba->cfg_enable_bg) diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 2697da3248b3..057a7910c570 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -118,9 +118,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) if (!phba->lpfc_mbuf_pool) goto fail; - pool->elements = kmalloc_array(LPFC_MBUF_POOL_SIZE, - sizeof(struct lpfc_dmabuf), - GFP_KERNEL); + pool->elements = kmalloc_objs(struct lpfc_dmabuf, LPFC_MBUF_POOL_SIZE); if (!pool->elements) goto fail_free_lpfc_mbuf_pool; @@ -511,7 +509,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *hbqbp; - hbqbp = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + hbqbp = kzalloc_obj(struct hbq_dmabuf); if (!hbqbp) return NULL; @@ -563,7 +561,7 @@ lpfc_sli4_rb_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *dma_buf; - dma_buf = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + dma_buf = kzalloc_obj(struct hbq_dmabuf); if (!dma_buf) return NULL; @@ -621,7 +619,7 @@ lpfc_sli4_nvmet_alloc(struct lpfc_hba *phba) { struct rqb_dmabuf *dma_buf; - dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); + dma_buf = kzalloc_obj(*dma_buf); if (!dma_buf) return NULL; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index a596b80d03d4..9c449055a55e 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -316,8 +316,7 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) struct lpfc_iocbq *save_iocb; struct lpfc_nodelist *ndlp; MAILBOX_t *mb = &login_mbox->u.mb; - - int rc; + int rc = 0; ndlp = login_mbox->ctx_ndlp; save_iocb = login_mbox->ctx_u.save_iocb; @@ -326,8 +325,14 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) /* Now that REG_RPI completed successfully, * we can now proceed with sending the PLOGI ACC. */ - rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, - save_iocb, ndlp, NULL); + if (test_bit(FC_PT2PT, &ndlp->vport->fc_flag)) { + rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, + save_iocb, ndlp, login_mbox); + } else { + rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, + save_iocb, ndlp, NULL); + } + if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4576 PLOGI ACC fails pt2pt discovery: " @@ -335,9 +340,16 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) } } - /* Now process the REG_RPI cmpl */ - lpfc_mbx_cmpl_reg_login(phba, login_mbox); - clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); + /* If this is a fabric topology, complete the reg_rpi and prli now. + * For Pt2Pt, the reg_rpi and PRLI are deferred until after the LS_ACC + * completes. This ensures, in Pt2Pt, that the PLOGI LS_ACC is sent + * before the PRLI. + */ + if (!test_bit(FC_PT2PT, &ndlp->vport->fc_flag) || mb->mbxStatus || rc) { + /* Now process the REG_RPI cmpl */ + lpfc_mbx_cmpl_reg_login(phba, login_mbox); + clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); + } kfree(save_iocb); } @@ -419,8 +431,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; /* if already logged in, do implicit logout */ @@ -439,18 +449,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_type & NLP_FABRIC) && !(phba->nvmet_support)) { - /* Clear ndlp info, since follow up PRLI may have - * updated ndlp information - */ - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; - clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); - - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, - ndlp, NULL); - return 1; + break; } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) @@ -472,7 +471,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); break; } - + /* Clear ndlp info, since follow up processes may have + * updated ndlp information + */ ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; @@ -523,13 +524,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Issue CONFIG_LINK for SLI3 or REG_VFI for SLI4, * to account for updated TOV's / parameters */ - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_issue_reg_vfi(vport); - else { + if (phba->sli_rev == LPFC_SLI_REV4) { + rc = lpfc_issue_reg_vfi(vport); + } else { link_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!link_mbox) - goto out; + goto rsp_rjt; lpfc_config_link(phba, link_mbox); link_mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; link_mbox->vport = vport; @@ -542,11 +543,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(link_mbox, phba->mbox_mem_pool); - goto out; + goto rsp_rjt; } } lpfc_can_disctmo(vport); + if (rc) + goto rsp_rjt; } clear_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag); @@ -560,11 +563,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, login_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!login_mbox) - goto out; + goto rsp_rjt; - save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL); + save_iocb = kzalloc_obj(*save_iocb); if (!save_iocb) - goto out; + goto free_login_mbox; /* Save info from cmd IOCB to be used in rsp after all mbox completes */ memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb, @@ -584,7 +587,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rc = lpfc_reg_rpi(phba, vport->vpi, remote_did, (uint8_t *)sp, login_mbox, ndlp->nlp_rpi); if (rc) - goto out; + goto free_save_iocb; login_mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; login_mbox->vport = vport; @@ -657,7 +660,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, login_mbox->mbox_cmpl = lpfc_defer_plogi_acc; login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp); if (!login_mbox->ctx_ndlp) - goto out; + goto free_save_iocb; login_mbox->ctx_u.save_iocb = save_iocb; /* For PLOGI ACC */ @@ -668,16 +671,17 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rc = lpfc_sli_issue_mbox(phba, login_mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { lpfc_nlp_put(ndlp); - goto out; + goto free_save_iocb; } lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); return 1; -out: - kfree(save_iocb); - if (login_mbox) - mempool_free(login_mbox, phba->mbox_mem_pool); +free_save_iocb: + kfree(save_iocb); +free_login_mbox: + mempool_free(login_mbox, phba->mbox_mem_pool); +rsp_rjt: stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); @@ -762,7 +766,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * registered. */ if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) { - elsiocb = kmalloc(sizeof(*elsiocb), GFP_KERNEL); + elsiocb = kmalloc_obj(*elsiocb); if (elsiocb) { /* Save info from cmd IOCB used in * rsp @@ -1413,8 +1417,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index b1adb9f59097..71714ea390d9 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -98,7 +98,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, test_bit(HBA_IOQ_FLUSH, &vport->phba->hba_flag)) return -ENODEV; - qhandle = kzalloc(sizeof(struct lpfc_nvme_qhandle), GFP_KERNEL); + qhandle = kzalloc_obj(struct lpfc_nvme_qhandle); if (qhandle == NULL) return -ENOMEM; @@ -587,7 +587,7 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * in the nvme-fc layer. */ - bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + bmp = kmalloc_obj(*bmp); if (!bmp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6044 NVMEx LS REQ: Could not alloc LS buf " @@ -1234,12 +1234,8 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, if ((phba->cfg_nvme_enable_fb) && test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) { req_len = lpfc_ncmd->nvmeCmd->payload_length; - if (req_len < pnode->nvme_fb_size) - wqe->fcp_iwrite.initial_xfer_len = - req_len; - else - wqe->fcp_iwrite.initial_xfer_len = - pnode->nvme_fb_size; + wqe->fcp_iwrite.initial_xfer_len = min(req_len, + pnode->nvme_fb_size); } else { wqe->fcp_iwrite.initial_xfer_len = 0; } @@ -1300,8 +1296,6 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 10 */ bf_set(wqe_xchg, &wqe->fcp_iwrite.wqe_com, LPFC_NVME_XCHG); - /* Words 13 14 15 are for PBDE support */ - /* add the VMID tags as per switch response */ if (unlikely(lpfc_ncmd->cur_iocbq.cmd_flag & LPFC_IO_VMID)) { if (phba->pport->vmid_priority_tagging) { @@ -1339,16 +1333,13 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, { struct lpfc_hba *phba = vport->phba; struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; - union lpfc_wqe128 *wqe = &lpfc_ncmd->cur_iocbq.wqe; struct sli4_sge *sgl = lpfc_ncmd->dma_sgl; struct sli4_hybrid_sgl *sgl_xtra = NULL; struct scatterlist *data_sg; - struct sli4_sge *first_data_sgl; - struct ulp_bde64 *bde; dma_addr_t physaddr = 0; uint32_t dma_len = 0; uint32_t dma_offset = 0; - int nseg, i, j; + int nseg, i, j, k; bool lsp_just_set = false; /* Fix up the command and response DMA stuff. */ @@ -1365,7 +1356,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, */ sgl += 2; - first_data_sgl = sgl; lpfc_ncmd->seg_cnt = nCmd->sg_cnt; if (lpfc_ncmd->seg_cnt > lpfc_nvme_template.max_sgl_segments) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -1389,6 +1379,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, /* for tracking the segment boundaries */ j = 2; + k = 5; + if (unlikely(!phba->cfg_xpsgl)) + k = 1; for (i = 0; i < nseg; i++) { if (data_sg == NULL) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -1407,9 +1400,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, bf_set(lpfc_sli4_sge_last, sgl, 0); /* expand the segment */ - if (!lsp_just_set && - !((j + 1) % phba->border_sge_num) && - ((nseg - 1) != i)) { + if (!lsp_just_set && (nseg != (i + k)) && + !((j + k) % phba->border_sge_num)) { /* set LSP type */ bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP); @@ -1432,8 +1424,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, } } - if (!(bf_get(lpfc_sli4_sge_type, sgl) & - LPFC_SGE_TYPE_LSP)) { + if (bf_get(lpfc_sli4_sge_type, sgl) != + LPFC_SGE_TYPE_LSP) { if ((nseg - 1) == i) bf_set(lpfc_sli4_sge_last, sgl, 1); @@ -1454,40 +1446,26 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, sgl++; lsp_just_set = false; + j++; } else { sgl->word2 = cpu_to_le32(sgl->word2); - - sgl->sge_len = cpu_to_le32( - phba->cfg_sg_dma_buf_size); + /* will remaining SGEs fill the next SGL? */ + if ((nseg - i) < phba->border_sge_num) + sgl->sge_len = + cpu_to_le32((nseg - i) * + sizeof(*sgl)); + else + sgl->sge_len = + cpu_to_le32(phba->cfg_sg_dma_buf_size); sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; i = i - 1; lsp_just_set = true; + j += k; + k = 1; } - - j++; - } - - /* PBDE support for first data SGE only */ - if (nseg == 1 && phba->cfg_enable_pbde) { - /* Words 13-15 */ - bde = (struct ulp_bde64 *) - &wqe->words[13]; - bde->addrLow = first_data_sgl->addr_lo; - bde->addrHigh = first_data_sgl->addr_hi; - bde->tus.f.bdeSize = - le32_to_cpu(first_data_sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - - /* Word 11 - set PBDE bit */ - bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); - } else { - memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); - /* Word 11 - PBDE bit disabled by default template */ } - } else { lpfc_ncmd->seg_cnt = 0; @@ -2508,7 +2486,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "6031 RemotePort Registration failed " "err: %d, DID x%06x ref %u\n", ret, ndlp->nlp_DID, kref_read(&ndlp->kref)); - lpfc_nlp_put(ndlp); + + /* Only release reference if one was taken for this request */ + if (!oldrport) + lpfc_nlp_put(ndlp); } return ret; @@ -2614,7 +2595,8 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * clear any rport state until the transport calls back. */ - if (ndlp->nlp_type & NLP_NVME_TARGET) { + if ((ndlp->nlp_type & NLP_NVME_TARGET) || + (remoteport->port_role & FC_PORT_ROLE_NVME_TARGET)) { /* No concern about the role change on the nvme remoteport. * The transport will update it. */ @@ -2847,6 +2829,54 @@ lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, } /** + * lpfc_nvme_flush_abts_list - Clean up nvme commands from the abts list + * @phba: Pointer to HBA context object. + * + **/ +void +lpfc_nvme_flush_abts_list(struct lpfc_hba *phba) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_io_buf *psb, *psb_next; + struct lpfc_sli4_hdw_queue *qp; + LIST_HEAD(aborts); + int i; + + /* abts_xxxx_buf_list_lock required because worker thread uses this + * list. + */ + spin_lock_irq(&phba->hbalock); + for (i = 0; i < phba->cfg_hdw_queue; i++) { + qp = &phba->sli4_hba.hdwq[i]; + + spin_lock(&qp->abts_io_buf_list_lock); + list_for_each_entry_safe(psb, psb_next, + &qp->lpfc_abts_io_buf_list, list) { + if (!(psb->cur_iocbq.cmd_flag & LPFC_IO_NVME)) + continue; + list_move(&psb->list, &aborts); + qp->abts_nvme_io_bufs--; + } + spin_unlock(&qp->abts_io_buf_list_lock); + } + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(psb, psb_next, &aborts, list) { + list_del_init(&psb->list); + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6195 %s: lpfc_ncmd x%px flags x%x " + "cmd_flag x%x xri x%x\n", __func__, + psb, psb->flags, + psb->cur_iocbq.cmd_flag, + psb->cur_iocbq.sli4_xritag); + psb->flags &= ~LPFC_SBUF_XBUSY; + psb->status = IOSTAT_SUCCESS; + lpfc_sli4_nvme_pci_offline_aborted(phba, psb); + } +#endif +} + +/** * lpfc_nvmels_flush_cmd - Clean up outstanding nvmels commands for a port * @phba: Pointer to HBA context object. * diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index fba2e62027b7..72f3f6f9444d 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -118,12 +118,9 @@ lpfc_nvmet_cmd_template(void) bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0); bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_pbde, &wqe->fcp_tsend.wqe_com, 0); /* Word 12 - fcp_data_len is variable */ - /* Word 13, 14, 15 - PBDE is zero */ - /* TRECEIVE template */ wqe = &lpfc_treceive_cmd_template; memset(wqe, 0, sizeof(union lpfc_wqe128)); @@ -158,18 +155,15 @@ lpfc_nvmet_cmd_template(void) bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12); bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); - /* Word 11 - pbde is variable */ + /* Word 11 */ bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com, FCP_COMMAND_TRECEIVE); bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); bf_set(wqe_sup, &wqe->fcp_treceive.wqe_com, 0); bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0); bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 1); /* Word 12 - fcp_data_len is variable */ - /* Word 13, 14, 15 - PBDE is variable */ - /* TRSP template */ wqe = &lpfc_trsp_cmd_template; memset(wqe, 0, sizeof(union lpfc_wqe128)); @@ -207,7 +201,6 @@ lpfc_nvmet_cmd_template(void) bf_set(wqe_sup, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0); - bf_set(wqe_pbde, &wqe->fcp_trsp.wqe_com, 0); /* Word 12, 13, 14, 15 - is zero */ } @@ -1243,7 +1236,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, struct lpfc_nvmet_tgtport *tgtp; struct lpfc_async_xchg_ctx *ctxp = container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); - struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; + struct rqb_dmabuf *nvmebuf; struct lpfc_hba *phba = ctxp->phba; unsigned long iflag; @@ -1251,13 +1244,18 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, lpfc_nvmeio_data(phba, "NVMET DEFERRCV: xri x%x sz %d CPU %02x\n", ctxp->oxid, ctxp->size, raw_smp_processor_id()); + spin_lock_irqsave(&ctxp->ctxlock, iflag); + nvmebuf = ctxp->rqb_buffer; if (!nvmebuf) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, "6425 Defer rcv: no buffer oxid x%x: " "flg %x ste %x\n", ctxp->oxid, ctxp->flag, ctxp->state); return; } + ctxp->rqb_buffer = NULL; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); tgtp = phba->targetport->private; if (tgtp) @@ -1265,9 +1263,6 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, /* Free the nvmebuf since a new buffer already replaced it */ nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); - spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->rqb_buffer = NULL; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } /** @@ -1505,9 +1500,8 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) "6403 Allocate NVMET resources for %d XRIs\n", phba->sli4_hba.nvmet_xri_cnt); - phba->sli4_hba.nvmet_ctx_info = kcalloc( - phba->sli4_hba.num_possible_cpu * phba->cfg_nvmet_mrq, - sizeof(struct lpfc_nvmet_ctx_info), GFP_KERNEL); + phba->sli4_hba.nvmet_ctx_info = kzalloc_objs(struct lpfc_nvmet_ctx_info, + phba->sli4_hba.num_possible_cpu * phba->cfg_nvmet_mrq); if (!phba->sli4_hba.nvmet_ctx_info) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6419 Failed allocate memory for " @@ -1565,15 +1559,14 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) idx = 0; cpu = cpumask_first(cpu_present_mask); for (i = 0; i < phba->sli4_hba.nvmet_xri_cnt; i++) { - ctx_buf = kzalloc(sizeof(*ctx_buf), GFP_KERNEL); + ctx_buf = kzalloc_obj(*ctx_buf); if (!ctx_buf) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6404 Ran out of memory for NVMET\n"); return -ENOMEM; } - ctx_buf->context = kzalloc(sizeof(*ctx_buf->context), - GFP_KERNEL); + ctx_buf->context = kzalloc_obj(*ctx_buf->context); if (!ctx_buf->context) { kfree(ctx_buf); lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -2722,7 +2715,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct ulp_bde64 *bde; dma_addr_t physaddr; int i, cnt, nsegs; - bool use_pbde = false; int xc = 1; if (!lpfc_is_link_up(phba)) { @@ -2907,15 +2899,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!xc) bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0); - /* Word 11 - check for pbde */ - if (nsegs == 1 && phba->cfg_enable_pbde) { - use_pbde = true; - /* Word 11 - PBDE bit already preset by template */ - } else { - /* Overwrite default template setting */ - bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0); - } - /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; @@ -3023,19 +3006,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } bde = (struct ulp_bde64 *)&wqe->words[13]; - if (use_pbde) { - /* decrement sgl ptr backwards once to first data sge */ - sgl--; - - /* Words 13-15 (PBDE) */ - bde->addrLow = sgl->addr_lo; - bde->addrHigh = sgl->addr_hi; - bde->tus.f.bdeSize = le32_to_cpu(sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - } else { - memset(bde, 0, sizeof(struct ulp_bde64)); - } + + memset(bde, 0, sizeof(struct ulp_bde64)); + ctxp->state = LPFC_NVME_STE_DATA; ctxp->entry_cnt++; return nvmewqe; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 055ed632c14d..1dce33b79beb 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -265,7 +265,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) (int)sizeof(struct fcp_rsp), bpl_size); for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { - psb = kzalloc(sizeof(struct lpfc_io_buf), GFP_KERNEL); + psb = kzalloc_obj(struct lpfc_io_buf); if (!psb) break; @@ -390,6 +390,10 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) return; + /* may be called before queues established if hba_setup fails */ + if (!phba->sli4_hba.hdwq) + return; + spin_lock_irqsave(&phba->hbalock, iflag); for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; @@ -532,7 +536,8 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); psb->flags &= ~LPFC_SBUF_XBUSY; spin_unlock_irqrestore(&phba->hbalock, iflag); - if (!list_empty(&pring->txq)) + if (test_bit(HBA_SETUP, &phba->hba_flag) && + !list_empty(&pring->txq)) lpfc_worker_wake_up(phba); return; } @@ -1933,7 +1938,7 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t dma_len; uint32_t dma_offset = 0; struct sli4_hybrid_sgl *sgl_xtra = NULL; - int j; + int j, k; bool lsp_just_set = false; status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); @@ -1996,13 +2001,16 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* assumption: caller has already run dma_map_sg on command data */ sgde = scsi_sglist(sc); j = 3; + k = 5; + if (unlikely(!phba->cfg_xpsgl)) + k = 1; for (i = 0; i < datasegcnt; i++) { /* clear it */ sgl->word2 = 0; - /* do we need to expand the segment */ - if (!lsp_just_set && !((j + 1) % phba->border_sge_num) && - ((datasegcnt - 1) != i)) { + /* do we need to expand the segment? */ + if (!lsp_just_set && (datasegcnt != (i + k)) && + !((j + k) % phba->border_sge_num)) { /* set LSP type */ bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP); @@ -2021,7 +2029,7 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); } - if (!(bf_get(lpfc_sli4_sge_type, sgl) & LPFC_SGE_TYPE_LSP)) { + if (bf_get(lpfc_sli4_sge_type, sgl) != LPFC_SGE_TYPE_LSP) { if ((datasegcnt - 1) == i) bf_set(lpfc_sli4_sge_last, sgl, 1); physaddr = sg_dma_address(sgde); @@ -2038,20 +2046,23 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl++; num_sge++; + j++; lsp_just_set = false; - } else { sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size); - + /* will remaining SGEs fill the next SGL? */ + if ((datasegcnt - i) < phba->border_sge_num) + sgl->sge_len = cpu_to_le32((datasegcnt - i) * + sizeof(*sgl)); + else + sgl->sge_len = + cpu_to_le32(phba->cfg_sg_dma_buf_size); sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; i = i - 1; - + j += k; lsp_just_set = true; + k = 1; } - - j++; - } out: @@ -2104,6 +2115,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct scatterlist *sgde = NULL; /* s/g data entry */ struct scatterlist *sgpe = NULL; /* s/g prot entry */ struct sli4_sge_diseed *diseed = NULL; + struct sli4_sge_le *lsp_sgl = NULL; dma_addr_t dataphysaddr, protphysaddr; unsigned short curr_prot = 0; unsigned int split_offset; @@ -2120,8 +2132,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t rc; #endif uint32_t checking = 1; - uint32_t dma_offset = 0, num_sge = 0; - int j = 2; + uint32_t dma_offset = 0, num_sge = 0, lsp_len; + int j = 2, k = 4; struct sli4_hybrid_sgl *sgl_xtra = NULL; sgpe = scsi_prot_sglist(sc); @@ -2152,6 +2164,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, } #endif + if (unlikely(!phba->cfg_xpsgl)) + k = 0; split_offset = 0; do { /* Check to see if we ran out of space */ @@ -2159,10 +2173,10 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, !(phba->cfg_xpsgl)) return num_sge + 3; - /* DISEED and DIF have to be together */ - if (!((j + 1) % phba->border_sge_num) || - !((j + 2) % phba->border_sge_num) || - !((j + 3) % phba->border_sge_num)) { + /* DISEED and DIF have to be together */ + if (!((j + k + 1) % phba->border_sge_num) || + !((j + k + 2) % phba->border_sge_num) || + !((j + k + 3) % phba->border_sge_num)) { sgl->word2 = 0; /* set LSP type */ @@ -2181,9 +2195,18 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size); + if (lsp_sgl) { + j++; + if (j % phba->border_sge_num) { + lsp_len = j * (sizeof(*sgl)); + lsp_sgl->sge_len = cpu_to_le32(lsp_len); + } + } + lsp_sgl = (struct sli4_sge_le *)sgl; sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; j = 0; + k = 0; } /* setup DISEED with what we have */ @@ -2286,7 +2309,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return 0; } - if (!((j + 1) % phba->border_sge_num)) { + if (!((j + k + 1) % phba->border_sge_num)) { sgl->word2 = 0; /* set LSP type */ @@ -2308,8 +2331,11 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32( phba->cfg_sg_dma_buf_size); + lsp_sgl = (struct sli4_sge_le *)sgl; sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; + j = 0; + k = 0; } else { dataphysaddr = sg_dma_address(sgde) + split_offset; @@ -2357,11 +2383,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* Move to the next s/g segment if possible */ sgde = sg_next(sgde); - sgl++; + j++; } - - j++; } if (protgroup_offset) { @@ -2376,6 +2400,14 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl--; bf_set(lpfc_sli4_sge_last, sgl, 1); alldone = 1; + + /* Reset length in previous LSP where necessary */ + if (lsp_sgl) { + if (j % phba->border_sge_num) { + lsp_len = j * (sizeof(*sgl)); + lsp_sgl->sge_len = cpu_to_le32(lsp_len); + } + } } else if (curr_prot < protcnt) { /* advance to next prot buffer */ sgpe = sg_next(sgpe); @@ -2387,7 +2419,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9085 BLKGRD: bug in %s\n", __func__); } - } while (!alldone); out: @@ -3045,15 +3076,13 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) struct scatterlist *sgel = NULL; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - struct sli4_sge *first_data_sgl; struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; struct lpfc_vport *vport = phba->pport; union lpfc_wqe128 *wqe = &pwqeq->wqe; dma_addr_t physaddr; uint32_t dma_len; uint32_t dma_offset = 0; - int nseg, i, j; - struct ulp_bde64 *bde; + int nseg, i, j, k; bool lsp_just_set = false; struct sli4_hybrid_sgl *sgl_xtra = NULL; @@ -3080,7 +3109,6 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) bf_set(lpfc_sli4_sge_last, sgl, 0); sgl->word2 = cpu_to_le32(sgl->word2); sgl += 1; - first_data_sgl = sgl; lpfc_cmd->seg_cnt = nseg; if (!phba->cfg_xpsgl && lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { @@ -3109,6 +3137,9 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) /* for tracking segment boundaries */ sgel = scsi_sglist(scsi_cmnd); j = 2; + k = 5; + if (unlikely(!phba->cfg_xpsgl)) + k = 1; for (i = 0; i < nseg; i++) { sgl->word2 = 0; if (nseg == 1) { @@ -3119,9 +3150,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) bf_set(lpfc_sli4_sge_last, sgl, 0); /* do we need to expand the segment */ - if (!lsp_just_set && - !((j + 1) % phba->border_sge_num) && - ((nseg - 1) != i)) { + if (!lsp_just_set && (nseg != (i + k)) && + !((j + k) % phba->border_sge_num)) { /* set LSP type */ bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP); @@ -3145,8 +3175,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) } } - if (!(bf_get(lpfc_sli4_sge_type, sgl) & - LPFC_SGE_TYPE_LSP)) { + if (bf_get(lpfc_sli4_sge_type, sgl) != + LPFC_SGE_TYPE_LSP) { if ((nseg - 1) == i) bf_set(lpfc_sli4_sge_last, sgl, 1); @@ -3166,43 +3196,24 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) sgl++; lsp_just_set = false; - + j++; } else { sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32( - phba->cfg_sg_dma_buf_size); - + /* will remaining SGEs fill the next SGL? */ + if ((nseg - i) < phba->border_sge_num) + sgl->sge_len = + cpu_to_le32((nseg - i) * + sizeof(*sgl)); + else + sgl->sge_len = + cpu_to_le32(phba->cfg_sg_dma_buf_size); sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; i = i - 1; lsp_just_set = true; + j += k; + k = 1; } - - j++; - } - - /* PBDE support for first data SGE only. - * For FCoE, we key off Performance Hints. - * For FC, we key off lpfc_enable_pbde. - */ - if (nseg == 1 && - ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || - phba->cfg_enable_pbde)) { - /* Words 13-15 */ - bde = (struct ulp_bde64 *) - &wqe->words[13]; - bde->addrLow = first_data_sgl->addr_lo; - bde->addrHigh = first_data_sgl->addr_hi; - bde->tus.f.bdeSize = - le32_to_cpu(first_data_sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - - /* Word 11 - set PBDE bit */ - bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); - } else { - memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); - /* Word 11 - PBDE bit disabled by default template */ } } else { sgl += 1; @@ -3210,13 +3221,6 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) sgl->word2 = le32_to_cpu(sgl->word2); bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); - - if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || - phba->cfg_enable_pbde) { - bde = (struct ulp_bde64 *) - &wqe->words[13]; - memset(bde, 0, (sizeof(uint32_t) * 3)); - } } /* @@ -4660,7 +4664,7 @@ static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport, else piocbq->iocb.ulpFCP2Rcvy = 0; - piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); + piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & NLP_FCP_CLASS_MASK); piocbq->io_buf = lpfc_cmd; if (!piocbq->cmd_cmpl) piocbq->cmd_cmpl = lpfc_scsi_cmd_iocb_cmpl; @@ -4772,7 +4776,7 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport, bf_set(wqe_erp, &wqe->generic.wqe_com, 1); bf_set(wqe_class, &wqe->generic.wqe_com, - (pnode->nlp_fcp_info & 0x0f)); + (pnode->nlp_fcp_info & NLP_FCP_CLASS_MASK)); /* Word 8 */ wqe->generic.wqe_com.abort_tag = pwqeq->iotag; @@ -4872,7 +4876,7 @@ lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport, piocb->ulpCommand = CMD_FCP_ICMND64_CR; piocb->ulpContext = ndlp->nlp_rpi; piocb->ulpFCP2Rcvy = (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0; - piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); + piocb->ulpClass = (ndlp->nlp_fcp_info & NLP_FCP_CLASS_MASK); piocb->ulpPU = 0; piocb->un.fcpi.fcpi_parm = 0; @@ -4940,7 +4944,7 @@ lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport, bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0)); bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, - (ndlp->nlp_fcp_info & 0x0f)); + (ndlp->nlp_fcp_info & NLP_FCP_CLASS_MASK)); /* ulpTimeout is only one byte */ if (lpfc_cmd->timeout > 0xff) { @@ -5190,7 +5194,7 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba) **/ void lpfc_poll_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, fcp_poll_timer); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, @@ -5228,8 +5232,8 @@ static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd) * 0 - Success * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ -static int -lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; @@ -5488,7 +5492,7 @@ void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport) struct lpfc_vmid *cur; if (vport->port_type == LPFC_PHYSICAL_PORT) - del_timer_sync(&vport->phba->inactive_vmid_poll); + timer_delete_sync(&vport->phba->inactive_vmid_poll); kfree(vport->qfpa_res); kfree(vport->vmid_priority.vmid_range); @@ -5645,9 +5649,8 @@ wait_for_cmpl: * cmd_flag is set to LPFC_DRIVER_ABORTED before we wait * for abort to complete. */ - wait_event_timeout(waitq, - (lpfc_cmd->pCmd != cmnd), - msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); + wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), + secs_to_jiffies(2*vport->cfg_devloss_tmo)); spin_lock(&lpfc_cmd->buf_lock); @@ -5911,7 +5914,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) * If target is not in a MAPPED state, delay until * target is rediscovered or devloss timeout expires. */ - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; + later = secs_to_jiffies(2 * vport->cfg_devloss_tmo) + jiffies; while (time_after(later, jiffies)) { if (!pnode) return FAILED; @@ -5931,7 +5934,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) /** * lpfc_reset_flush_io_context - * @vport: The virtual port (scsi_host) for the flush context - * @tgt_id: If aborting by Target contect - specifies the target id + * @tgt_id: If aborting by Target context - specifies the target id * @lun_id: If aborting by Lun context - specifies the lun id * @context: specifies the context level to flush at. * @@ -5957,7 +5960,7 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, lpfc_sli_abort_taskmgmt(vport, &phba->sli.sli3_ring[LPFC_FCP_RING], tgt_id, lun_id, context); - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; + later = secs_to_jiffies(2 * vport->cfg_devloss_tmo) + jiffies; while (time_after(later, jiffies) && cnt) { schedule_timeout_uninterruptible(msecs_to_jiffies(20)); cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); @@ -6105,8 +6108,14 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; spin_unlock_irqrestore(&pnode->lock, flags); } - lpfc_reset_flush_io_context(vport, tgt_id, lun_id, - LPFC_CTX_TGT); + status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_TGT); + if (status != SUCCESS) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0726 Target Reset flush status x%x\n", + status); + return status; + } return FAST_IO_FAIL; } @@ -6137,8 +6146,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) wait_event_timeout(waitq, !test_bit(NLP_WAIT_FOR_LOGO, &pnode->save_flags), - msecs_to_jiffies(dev_loss_tmo * - 1000)); + secs_to_jiffies(dev_loss_tmo)); if (test_and_clear_bit(NLP_WAIT_FOR_LOGO, &pnode->save_flags)) @@ -6199,7 +6207,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) int rc, ret = SUCCESS; lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "3172 SCSI layer issued Host Reset Data:\n"); + "3172 SCSI layer issued Host Reset\n"); lpfc_offline_prep(phba, LPFC_MBX_WAIT); lpfc_offline(phba); @@ -6734,8 +6742,8 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, return false; } -static int -lpfc_no_command(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_no_command(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { return SCSI_MLQUEUE_HOST_BUSY; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3fd9723cd271..d38fb374b379 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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. * @@ -27,6 +27,8 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/lockdep.h> +#include <linux/dmi.h> +#include <linux/of.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -134,15 +136,12 @@ void lpfc_wqe_cmd_template(void) bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); - /* Word 11 - pbde is variable */ + /* Word 11 */ bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, COMMAND_DATA_IN); bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); /* Word 12 - is zero */ - /* Word 13, 14, 15 - PBDE is variable */ - /* IWRITE template */ wqe = &lpfc_iwrite_cmd_template; memset(wqe, 0, sizeof(union lpfc_wqe128)); @@ -174,15 +173,12 @@ void lpfc_wqe_cmd_template(void) bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); - /* Word 11 - pbde is variable */ + /* Word 11 */ bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, COMMAND_DATA_OUT); bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); /* Word 12 - is zero */ - /* Word 13, 14, 15 - PBDE is variable */ - /* ICMND template */ wqe = &lpfc_icmnd_cmd_template; memset(wqe, 0, sizeof(union lpfc_wqe128)); @@ -215,7 +211,6 @@ void lpfc_wqe_cmd_template(void) /* Word 11 */ bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, COMMAND_DATA_IN); bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); /* Word 12, 13, 14, 15 - is zero */ } @@ -1025,7 +1020,7 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) LIST_HEAD(send_rrq); clear_bit(HBA_RRQ_ACTIVE, &phba->hba_flag); - next_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); + next_time = jiffies + secs_to_jiffies(phba->fc_ratov + 1); spin_lock_irqsave(&phba->rrq_list_lock, iflags); list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) { @@ -1208,8 +1203,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, else rrq->send_rrq = 0; rrq->xritag = xritag; - rrq->rrq_stop_time = jiffies + - msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); + rrq->rrq_stop_time = jiffies + secs_to_jiffies(phba->fc_ratov + 1); rrq->nlp_DID = ndlp->nlp_DID; rrq->vport = ndlp->vport; rrq->rxid = rxid; @@ -1736,8 +1730,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, BUG_ON(!piocb->vport); if (!test_bit(FC_UNLOADING, &piocb->vport->load_flag)) mod_timer(&piocb->vport->els_tmofunc, - jiffies + - msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); + jiffies + secs_to_jiffies(phba->fc_ratov << 1)); } return 0; @@ -2135,8 +2128,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) - LPFC_IOCBQ_LOOKUP_INCREMENT)) { new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT; spin_unlock_irq(&phba->hbalock); - new_arr = kcalloc(new_len, sizeof(struct lpfc_iocbq *), - GFP_KERNEL); + new_arr = kzalloc_objs(struct lpfc_iocbq *, new_len); if (new_arr) { spin_lock_irq(&phba->hbalock); old_arr = psli->iocbq_lookup; @@ -2923,6 +2915,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); + } else { + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); } /* The unreg_login mailbox is complete and had a @@ -3238,7 +3232,7 @@ lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT))) { failwhy = "Bad NVME LS F_CTL"; } else { - axchg = kzalloc(sizeof(*axchg), GFP_ATOMIC); + axchg = kzalloc_obj(*axchg, GFP_ATOMIC); if (!axchg) failwhy = "No CTX memory"; } @@ -3925,13 +3919,20 @@ void lpfc_poll_eratt(struct timer_list *t) uint32_t eratt = 0; uint64_t sli_intr, cnt; - phba = from_timer(phba, t, eratt_poll); - if (!test_bit(HBA_SETUP, &phba->hba_flag)) - return; + phba = timer_container_of(phba, t, eratt_poll); if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; + if (phba->sli_rev == LPFC_SLI_REV4 && + !test_bit(HBA_SETUP, &phba->hba_flag)) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0663 HBA still initializing 0x%lx, restart " + "timer\n", + phba->hba_flag); + goto restart_timer; + } + /* Here we will also keep track of interrupts per sec of the hba */ sli_intr = phba->sli.slistat.sli_intr; @@ -3950,14 +3951,16 @@ void lpfc_poll_eratt(struct timer_list *t) /* Check chip HA register for error event */ eratt = lpfc_sli_check_eratt(phba); - if (eratt) + if (eratt) { /* Tell the worker thread there is work to do */ lpfc_worker_wake_up(phba); - else - /* Restart the timer for next eratt poll */ - mod_timer(&phba->eratt_poll, - jiffies + - msecs_to_jiffies(1000 * phba->eratt_poll_interval)); + return; + } + +restart_timer: + /* Restart the timer for next eratt poll */ + mod_timer(&phba->eratt_poll, + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); return; } @@ -4562,59 +4565,41 @@ void lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { LIST_HEAD(tx_completions); - LIST_HEAD(txcmplq_completions); + spinlock_t *plock; /* for transmit queue access */ struct lpfc_iocbq *iocb, *next_iocb; int offline; - if (pring->ringno == LPFC_ELS_RING) { + if (phba->sli_rev >= LPFC_SLI_REV4) + plock = &pring->ring_lock; + else + plock = &phba->hbalock; + + if (pring->ringno == LPFC_ELS_RING) lpfc_fabric_abort_hba(phba); - } + offline = pci_channel_offline(phba->pcidev); - /* Error everything on txq and txcmplq - * First do the txq. - */ - if (phba->sli_rev >= LPFC_SLI_REV4) { - spin_lock_irq(&pring->ring_lock); - list_splice_init(&pring->txq, &tx_completions); - pring->txq_cnt = 0; + /* Cancel everything on txq */ + spin_lock_irq(plock); + list_splice_init(&pring->txq, &tx_completions); + pring->txq_cnt = 0; - if (offline) { - list_splice_init(&pring->txcmplq, - &txcmplq_completions); - } else { - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, - &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, - iocb, NULL); - } - spin_unlock_irq(&pring->ring_lock); + if (offline) { + /* Cancel everything on txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; + list_splice_init(&pring->txcmplq, &tx_completions); + pring->txcmplq_cnt = 0; } else { - spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &tx_completions); - pring->txq_cnt = 0; - - if (offline) { - list_splice_init(&pring->txcmplq, &txcmplq_completions); - } else { - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, - &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, - iocb, NULL); - } - spin_unlock_irq(&phba->hbalock); + /* Issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); } + spin_unlock_irq(plock); - if (offline) { - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, - IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); - } else { - /* Make sure HBA is alive */ + if (!offline) lpfc_issue_hb_tmo(phba); - } + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); @@ -5042,7 +5027,7 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) return 1; } - del_timer_sync(&psli->mbox_tmo); + timer_delete_sync(&psli->mbox_tmo); if (ha_copy & HA_ERATT) { writel(HA_ERATT, phba->HAregaddr); phba->pport->stopped = 1; @@ -5158,7 +5143,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; - clear_bit(HBA_SETUP, &phba->hba_flag); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); @@ -5275,6 +5259,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) "0296 Restart HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); + clear_bit(HBA_SETUP, &phba->hba_flag); lpfc_sli4_queue_unset(phba); rc = lpfc_sli4_brdreset(phba); @@ -5883,7 +5868,7 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, struct lpfc_dmabuf *dmabuf; struct lpfc_mqe *mqe; - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + dmabuf = kzalloc_obj(struct lpfc_dmabuf); if (!dmabuf) return -ENOMEM; @@ -6004,9 +5989,9 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); - memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); - strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, + memcpy(phba->BIOSVersion, cntl_attr->bios_ver_str, sizeof(phba->BIOSVersion)); + phba->BIOSVersion[sizeof(phba->BIOSVersion) - 1] = '\0'; lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " @@ -6933,8 +6918,7 @@ lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, ras_fwlog->fw_buffcount = fwlog_buff_count; for (i = 0; i < ras_fwlog->fw_buffcount; i++) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), - GFP_KERNEL); + dmabuf = kzalloc_obj(struct lpfc_dmabuf); if (!dmabuf) { rc = -ENOMEM; lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -8037,8 +8021,7 @@ static void lpfc_sli4_dip(struct lpfc_hba *phba) int lpfc_rx_monitor_create_ring(struct lpfc_rx_info_monitor *rx_monitor, u32 entries) { - rx_monitor->ring = kmalloc_array(entries, sizeof(struct rx_info_entry), - GFP_KERNEL); + rx_monitor->ring = kmalloc_objs(struct rx_info_entry, entries); if (!rx_monitor->ring) return -ENOMEM; @@ -8285,7 +8268,7 @@ lpfc_cmf_setup(struct lpfc_hba *phba) /* Allocate Congestion Information Buffer */ if (!phba->cgn_i) { - mp = kmalloc(sizeof(*mp), GFP_KERNEL); + mp = kmalloc_obj(*mp); if (mp) mp->virt = dma_alloc_coherent (&phba->pcidev->dev, @@ -8367,8 +8350,7 @@ no_cmf: /* Allocate RX Monitor Buffer */ if (!phba->rx_monitor) { - phba->rx_monitor = kzalloc(sizeof(*phba->rx_monitor), - GFP_KERNEL); + phba->rx_monitor = kzalloc_obj(*phba->rx_monitor); if (!phba->rx_monitor) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8438,6 +8420,70 @@ lpfc_set_host_tm(struct lpfc_hba *phba) } /** + * lpfc_get_platform_uuid - Attempts to extract a platform uuid + * @phba: pointer to lpfc hba data structure. + * + * This routine attempts to first read SMBIOS DMI data for the System + * Information structure offset 08h called System UUID. Else, no platform + * UUID will be advertised. + **/ +static void +lpfc_get_platform_uuid(struct lpfc_hba *phba) +{ + int rc; + const char *uuid; + char pni[17] = {0}; /* 16 characters + '\0' */ + bool is_ff = true, is_00 = true; + u8 i; + + /* First attempt SMBIOS DMI */ + uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + if (uuid) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2088 SMBIOS UUID %s\n", + uuid); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2099 Could not extract UUID\n"); + } + + if (uuid && uuid_is_valid(uuid)) { + /* Generate PNI from UUID format. + * + * 1.) Extract lower 64 bits from UUID format. + * 2.) Set 3h for NAA Locally Assigned Name Identifier format. + * + * e.g. xxxxxxxx-xxxx-xxxx-yyyy-yyyyyyyyyyyy + * + * extract the yyyy-yyyyyyyyyyyy portion + * final PNI 3yyyyyyyyyyyyyyy + */ + scnprintf(pni, sizeof(pni), "3%c%c%c%s", + uuid[20], uuid[21], uuid[22], &uuid[24]); + + /* Sanitize the converted PNI */ + for (i = 1; i < 16 && (is_ff || is_00); i++) { + if (pni[i] != '0') + is_00 = false; + if (pni[i] != 'f' && pni[i] != 'F') + is_ff = false; + } + + /* Convert from char* to unsigned long */ + rc = kstrtoul(pni, 16, &phba->pni); + if (!rc && !is_ff && !is_00) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2100 PNI 0x%016lx\n", phba->pni); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2101 PNI %s generation status %d\n", + pni, rc); + phba->pni = 0; + } + } +} + +/** * lpfc_sli4_hba_setup - SLI4 device initialization PCI function * @phba: Pointer to HBA context object. * @@ -8520,6 +8566,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) clear_bit(HBA_FCOE_MODE, &phba->hba_flag); } + /* Obtain platform UUID, only for SLI4 FC adapters */ + if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag)) + lpfc_get_platform_uuid(phba); + if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) == LPFC_DCBX_CEE_MODE) set_bit(HBA_FIP_SUPPORT, &phba->hba_flag); @@ -8675,14 +8725,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) ftr_rsp++; } - /* Performance Hints are ONLY for FCoE */ - if (test_bit(HBA_FCOE_MODE, &phba->hba_flag)) { - if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs)) - phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED; - else - phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED; - } - /* * If the port cannot support the host's requested features * then turn off the global config parameters to disable the @@ -8811,7 +8853,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0381 Error %d during queue setup.\n", rc); - goto out_stop_timers; + goto out_destroy_queue; } /* Initialize the driver internal SLI layer lists. */ lpfc_sli4_setup(phba); @@ -9008,7 +9050,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start the ELS watchdog timer */ mod_timer(&vport->els_tmofunc, - jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov * 2))); + jiffies + secs_to_jiffies(phba->fc_ratov * 2)); /* Start heart beat timer */ mod_timer(&phba->hb_tmofunc, @@ -9027,7 +9069,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, - jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); /* * The port is ready, set the host's link state to LINK_DOWN @@ -9094,7 +9136,6 @@ out_free_iocblist: lpfc_free_iocb_list(phba); out_destroy_queue: lpfc_sli4_queue_destroy(phba); -out_stop_timers: lpfc_stop_hba_timers(phba); out_free_mbox: mempool_free(mboxq, phba->mbox_mem_pool); @@ -9116,7 +9157,7 @@ out_free_mbox: void lpfc_mbox_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, sli.mbox_tmo); + struct lpfc_hba *phba = timer_container_of(phba, t, sli.mbox_tmo); unsigned long iflag; uint32_t tmo_posted; @@ -9504,8 +9545,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, goto out_not_finished; } /* timeout active mbox command */ - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * - 1000); + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox)); mod_timer(&psli->mbox_tmo, jiffies + timeout); } @@ -9629,8 +9669,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, drvr_flag); goto out_not_finished; } - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * - 1000) + jiffies; + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox)) + jiffies; i = 0; /* Wait for command to complete */ while (((word0 & OWN_CHIP) == OWN_CHIP) || @@ -9756,9 +9795,8 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) * command to be gracefully completed by firmware. */ if (phba->sli.mbox_active) - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * - 1000) + jiffies; + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, + phba->sli.mbox_active)) + jiffies; spin_unlock_irq(&phba->hbalock); /* Make sure the mailbox is really active */ @@ -9881,8 +9919,7 @@ lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } } - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq)) + jiffies; do { bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); @@ -10230,7 +10267,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) /* Start timer for the mbox_tmo and log some mailbox post messages */ mod_timer(&psli->mbox_tmo, (jiffies + - msecs_to_jiffies(1000 * lpfc_mbox_tmo_val(phba, mboxq)))); + secs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq)))); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0355 Mailbox cmd x%x (x%x/x%x) issue Data: " @@ -12081,7 +12118,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) local_bh_enable(); /* Return any active mbox cmds */ - del_timer_sync(&psli->mbox_tmo); + timer_delete_sync(&psli->mbox_tmo); spin_lock_irqsave(&phba->pport->work_port_lock, flags); phba->pport->work_port_events &= ~WORKER_MBOX_TMO; @@ -12434,19 +12471,11 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } /* - * If we're unloading, don't abort iocb on the ELS ring, but change - * the callback so that nothing happens when it finishes. + * Always abort the outstanding WQE and set the IA bit correctly + * for the context. This is necessary for correctly removing + * outstanding ndlp reference counts when the CQE completes with + * the XB bit set. */ - if (test_bit(FC_UNLOADING, &vport->load_flag) && - pring->ringno == LPFC_ELS_RING) { - if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl; - return retval; - } - - /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) return IOCB_NORESOURCE; @@ -13159,7 +13188,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, SLI_IOCB_RET_IOCB); if (retval == IOCB_SUCCESS) { - timeout_req = msecs_to_jiffies(timeout * 1000); + timeout_req = secs_to_jiffies(timeout); timeleft = wait_event_timeout(done_q, lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); @@ -13275,8 +13304,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, /* now issue the command */ retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); if (retval == MBX_BUSY || retval == MBX_SUCCESS) { - wait_for_completion_timeout(&mbox_done, - msecs_to_jiffies(timeout * 1000)); + wait_for_completion_timeout(&mbox_done, secs_to_jiffies(timeout)); spin_lock_irqsave(&phba->hbalock, flag); pmboxq->ctx_u.mbox_wait = NULL; @@ -13336,9 +13364,8 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) * command to be gracefully completed by firmware. */ if (phba->sli.mbox_active) - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * - 1000) + jiffies; + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, + phba->sli.mbox_active)) + jiffies; spin_unlock_irq(&phba->hbalock); /* Enable softirqs again, done with phba->hbalock */ @@ -13809,7 +13836,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) phba->sli.mbox_active = NULL; spin_unlock_irqrestore(&phba->hbalock, iflag); phba->last_completion_time = jiffies; - del_timer(&phba->sli.mbox_tmo); + timer_delete(&phba->sli.mbox_tmo); if (pmb->mbox_cmpl) { lpfc_sli_pcimem_bcopy(mbox, pmbox, MAILBOX_CMD_SIZE); @@ -14295,13 +14322,15 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) /* Get the reference to the active mbox command */ spin_lock_irqsave(&phba->hbalock, iflags); pmb = phba->sli.mbox_active; + spin_unlock_irqrestore(&phba->hbalock, iflags); if (unlikely(!pmb)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "1832 No pending MBOX command to handle\n"); - spin_unlock_irqrestore(&phba->hbalock, iflags); + "1832 No pending MBOX command to handle, " + "mcqe: x%08x x%08x x%08x x%08x\n", + mcqe->word0, mcqe->mcqe_tag0, + mcqe->mcqe_tag1, mcqe->trailer); goto out_no_mqe_complete; } - spin_unlock_irqrestore(&phba->hbalock, iflags); mqe = &pmb->u.mqe; pmbox = (MAILBOX_t *)&pmb->u.mqe; mbox = phba->mbox; @@ -14309,7 +14338,7 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) /* Reset heartbeat timer */ phba->last_completion_time = jiffies; - del_timer(&phba->sli.mbox_tmo); + timer_delete(&phba->sli.mbox_tmo); /* Move mbox data to caller's mailbox region, do endian swapping */ if (pmb->mbox_cmpl && mbox) @@ -14676,11 +14705,22 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) atomic_read(&tgtp->rcv_fcp_cmd_out), atomic_read(&tgtp->xmt_fcp_release)); } + hrq->RQ_discard_frm++; fallthrough; - case FC_STATUS_INSUFF_BUF_NEED_BUF: + /* Unexpected event - bump the counter for support. */ hrq->RQ_no_posted_buf++; - /* Post more buffers if possible */ + + lpfc_log_msg(phba, KERN_WARNING, + LOG_ELS | LOG_DISCOVERY | LOG_SLI, + "6423 RQE completion Status x%x, needed x%x " + "discarded x%x\n", status, + hrq->RQ_no_posted_buf - hrq->RQ_discard_frm, + hrq->RQ_discard_frm); + + /* For SLI3, post more buffers if possible. No action for SLI4. + * SLI4 is reposting immediately after processing the RQE. + */ set_bit(HBA_POST_RECEIVE_BUFFER, &phba->hba_flag); workposted = true; break; @@ -15658,7 +15698,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) void lpfc_sli4_poll_hbtimer(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, cpuhp_poll_timer); struct lpfc_queue *eq; rcu_read_lock(); @@ -15696,7 +15736,7 @@ static inline void lpfc_sli4_remove_from_poll_list(struct lpfc_queue *eq) synchronize_rcu(); if (list_empty(&phba->poll_list)) - del_timer_sync(&phba->cpuhp_poll_timer); + timer_delete_sync(&phba->cpuhp_poll_timer); } void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba) @@ -15917,6 +15957,32 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset) return NULL; } +static __maybe_unused void __iomem * +lpfc_dpp_wc_map(struct lpfc_hba *phba, uint8_t dpp_barset) +{ + + /* DPP region is supposed to cover 64-bit BAR2 */ + if (dpp_barset != WQ_PCI_BAR_4_AND_5) { + lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, + "3273 dpp_barset x%x != WQ_PCI_BAR_4_AND_5\n", + dpp_barset); + return NULL; + } + + if (!phba->sli4_hba.dpp_regs_memmap_wc_p) { + void __iomem *dpp_map; + + dpp_map = ioremap_wc(phba->pci_bar2_map, + pci_resource_len(phba->pcidev, + PCI_64BIT_BAR4)); + + if (dpp_map) + phba->sli4_hba.dpp_regs_memmap_wc_p = dpp_map; + } + + return phba->sli4_hba.dpp_regs_memmap_wc_p; +} + /** * lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs * @phba: HBA structure that EQs are on. @@ -16474,10 +16540,10 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, case 4096: if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + bf_set(lpfc_mbx_cq_create_set_cqe_cnt_lo, &cq_set->u.request, - cq->entry_count); - bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + cq->entry_count); + bf_set(lpfc_mbx_cq_create_set_cqecnt, &cq_set->u.request, LPFC_CQ_CNT_WORD7); break; @@ -16493,15 +16559,15 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, } fallthrough; /* otherwise default to smallest */ case 256: - bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + bf_set(lpfc_mbx_cq_create_set_cqecnt, &cq_set->u.request, LPFC_CQ_CNT_256); break; case 512: - bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + bf_set(lpfc_mbx_cq_create_set_cqecnt, &cq_set->u.request, LPFC_CQ_CNT_512); break; case 1024: - bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + bf_set(lpfc_mbx_cq_create_set_cqecnt, &cq_set->u.request, LPFC_CQ_CNT_1024); break; } @@ -16880,9 +16946,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, uint8_t dpp_barset; uint32_t dpp_offset; uint8_t wq_create_version; -#ifdef CONFIG_X86 - unsigned long pg_addr; -#endif /* sanity check on queue memory */ if (!wq || !cq) @@ -17068,14 +17131,15 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, #ifdef CONFIG_X86 /* Enable combined writes for DPP aperture */ - pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK; - rc = set_memory_wc(pg_addr, 1); - if (rc) { + bar_memmap_p = lpfc_dpp_wc_map(phba, dpp_barset); + if (!bar_memmap_p) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3272 Cannot setup Combined " "Write on WQ[%d] - disable DPP\n", wq->queue_id); phba->cfg_enable_dpp = 0; + } else { + wq->dpp_regaddr = bar_memmap_p + dpp_offset; } #else phba->cfg_enable_dpp = 0; @@ -17083,7 +17147,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, } else wq->db_regaddr = phba->sli4_hba.WQDBregaddr; } - wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL); + wq->pring = kzalloc_obj(struct lpfc_sli_ring); if (wq->pring == NULL) { status = -ENOMEM; goto out; @@ -19402,7 +19466,7 @@ lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport, } /* Allocate buffer for command payload */ - pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + pcmd = kmalloc_obj(struct lpfc_dmabuf); if (pcmd) pcmd->virt = dma_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL, &pcmd->phys); @@ -19864,13 +19928,15 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba) } /** - * lpfc_sli4_resume_rpi - Remove the rpi bitmask region + * lpfc_sli4_resume_rpi - Resume traffic relative to an RPI * @ndlp: pointer to lpfc nodelist data structure. * @cmpl: completion call-back. * @iocbq: data to load as mbox ctx_u information * - * This routine is invoked to remove the memory region that - * provided rpi via a bitmask. + * Return codes + * 0 - successful + * -ENOMEM - No available memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, @@ -19900,7 +19966,6 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, return -EIO; } - /* Post all rpi memory regions to the port. */ lpfc_resume_rpi(mboxq, ndlp); if (cmpl) { mboxq->mbox_cmpl = cmpl; @@ -20367,62 +20432,36 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) { - uint16_t next_fcf_index; + uint16_t next; -initial_priority: - /* Search start from next bit of currently registered FCF index */ - next_fcf_index = phba->fcf.current_rec.fcf_indx; - -next_priority: - /* Determine the next fcf index to check */ - next_fcf_index = (next_fcf_index + 1) % LPFC_SLI4_FCF_TBL_INDX_MAX; - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, - next_fcf_index); + do { + for_each_set_bit_wrap(next, phba->fcf.fcf_rr_bmask, + LPFC_SLI4_FCF_TBL_INDX_MAX, phba->fcf.current_rec.fcf_indx) { + if (next == phba->fcf.current_rec.fcf_indx) + continue; - /* Wrap around condition on phba->fcf.fcf_rr_bmask */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - /* - * If we have wrapped then we need to clear the bits that - * have been tested so that we can detect when we should - * change the priority level. - */ - next_fcf_index = find_first_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX); - } + if (!(phba->fcf.fcf_pri[next].fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2845 Get next roundrobin failover FCF (x%x)\n", next); + return next; + } + if (list_is_singular(&phba->fcf.fcf_pri_list)) + return LPFC_FCOE_FCF_NEXT_NONE; + } - /* Check roundrobin failover list empty condition */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX || - next_fcf_index == phba->fcf.current_rec.fcf_indx) { /* * If next fcf index is not found check if there are lower * Priority level fcf's in the fcf_priority list. * Set up the rr_bmask with all of the avaiable fcf bits * at that level and continue the selection process. */ - if (lpfc_check_next_fcf_pri_level(phba)) - goto initial_priority; - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2844 No roundrobin failover FCF available\n"); + } while (lpfc_check_next_fcf_pri_level(phba)); - return LPFC_FCOE_FCF_NEXT_NONE; - } - - if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag & - LPFC_FCF_FLOGI_FAILED) { - if (list_is_singular(&phba->fcf.fcf_pri_list)) - return LPFC_FCOE_FCF_NEXT_NONE; - - goto next_priority; - } + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2844 No roundrobin failover FCF available\n"); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2845 Get next roundrobin failover FCF (x%x)\n", - next_fcf_index); - - return next_fcf_index; + return LPFC_FCOE_FCF_NEXT_NONE; } /** @@ -21370,7 +21409,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, struct lpfc_sglq *sglq; struct lpfc_sli_ring *pring; unsigned long iflags; - uint32_t ret = 0; + int ret = 0; /* NVME_LS and NVME_LS ABTS requests. */ if (pwqe->cmd_flag & LPFC_IO_NVME_LS) { @@ -22258,7 +22297,7 @@ lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap, read_object->u.request.rd_object_name[j] = cpu_to_le32(rd_object_name[j]); - pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); + pcmd = kmalloc_obj(*pcmd); if (pcmd) pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); if (!pcmd || !pcmd->virt) { diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 9be3da91c923..2744786d9c94 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -246,6 +246,8 @@ struct lpfc_queue { uint32_t q_cnt_2; uint32_t q_cnt_3; uint64_t q_cnt_4; + uint32_t q_cnt_5; + /* defines for EQ stats */ #define EQ_max_eqe q_cnt_1 #define EQ_no_entry q_cnt_2 @@ -268,6 +270,7 @@ struct lpfc_queue { #define RQ_no_buf_found q_cnt_2 #define RQ_buf_posted q_cnt_3 #define RQ_rcv_buf q_cnt_4 +#define RQ_discard_frm q_cnt_5 struct work_struct irqwork; struct work_struct spwork; @@ -575,8 +578,10 @@ struct lpfc_pc_sli4_params { #define LPFC_CQ_4K_PAGE_SZ 0x1 #define LPFC_CQ_16K_PAGE_SZ 0x4 +#define LPFC_CQ_32K_PAGE_SZ 0x8 #define LPFC_WQ_4K_PAGE_SZ 0x1 #define LPFC_WQ_16K_PAGE_SZ 0x4 +#define LPFC_WQ_32K_PAGE_SZ 0x8 struct lpfc_iov { uint32_t pf_number; @@ -783,6 +788,9 @@ struct lpfc_sli4_hba { void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for * dpp registers */ + void __iomem *dpp_regs_memmap_wc_p;/* Kernel memory mapped address for + * dpp registers with write combining + */ union { struct { /* IF Type 0, BAR 0 PCI cfg space reg mem map */ @@ -833,6 +841,7 @@ struct lpfc_sli4_hba { uint32_t ue_to_sr; uint32_t ue_to_rp; struct lpfc_register sli_intf; + struct lpfc_register asic_id; struct lpfc_pc_sli4_params pc_sli4_params; struct lpfc_bbscn_params bbscn_params; struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */ @@ -886,6 +895,10 @@ struct lpfc_sli4_hba { #define LPFC_FP_EQ_MAX_INTR_SEC 10000 uint32_t intr_enable; + + /* Indicates whether SLI Port supports FEDIF */ + bool encryption_support; + struct lpfc_bmbx bmbx; struct lpfc_max_cfg_param max_cfg_param; uint16_t extents_in_use; /* must allocate resource extents. */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c35f7225058e..d6e6e436fbfc 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-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2026 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 "14.4.0.7" +#define LPFC_DRIVER_VERSION "15.0.0.0" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -32,6 +32,6 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017-2024 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2026 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 3d70cc517573..f4eadc1028a9 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -246,7 +246,7 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) * fabric RA_TOV value and dev_loss tmo. The driver's * devloss_tmo is 10 giving this loop a 3x multiplier minimally. */ - wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); + wait_time_max = secs_to_jiffies((phba->fc_ratov * 3) + 3); wait_time_max += jiffies; start_time = jiffies; while (time_before(jiffies, wait_time_max)) { @@ -505,7 +505,7 @@ lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) wait_event_timeout(waitq, !test_bit(NLP_WAIT_FOR_LOGO, &ndlp->save_flags), - msecs_to_jiffies(phba->fc_ratov * 2000)); + secs_to_jiffies(phba->fc_ratov * 2)); if (!test_bit(NLP_WAIT_FOR_LOGO, &ndlp->save_flags)) goto logo_cmpl; @@ -666,7 +666,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) * Take early refcount for outstanding I/O requests we schedule during * delete processing for unreg_vpi. Always keep this before * scsi_remove_host() as we can no longer obtain a reference through - * scsi_host_get() after scsi_host_remove as shost is set to SHOST_DEL. + * scsi_host_get() after scsi_remove_host as shost is set to SHOST_DEL. */ if (!scsi_host_get(shost)) return VPORT_INVAL; @@ -703,7 +703,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) wait_event_timeout(waitq, !test_bit(NLP_WAIT_FOR_DA_ID, &ndlp->save_flags), - msecs_to_jiffies(phba->fc_ratov * 2000)); + secs_to_jiffies(phba->fc_ratov * 2)); } lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT | LOG_ELS, @@ -787,8 +787,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kcalloc(phba->max_vports + 1, sizeof(struct lpfc_vport *), - GFP_KERNEL); + vports = kzalloc_objs(struct lpfc_vport *, phba->max_vports + 1); if (vports == NULL) return NULL; spin_lock_irq(&phba->port_list_lock); diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 377dcab32cd8..de2bd860b9d7 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -66,7 +66,7 @@ static irqreturn_t do_mac53c94_interrupt(int, void *); static void cmd_done(struct fsc_state *, int result); static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); -static int mac53c94_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mac53c94_queue_lck(struct scsi_cmnd *cmd) { struct fsc_state *state; @@ -462,9 +462,8 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat * +1 to allow for aligning. * XXX FIXME: Use DMA consistent routines */ - dma_cmd_space = kmalloc_array(host->sg_tablesize + 2, - sizeof(struct dbdma_cmd), - GFP_KERNEL); + dma_cmd_space = kmalloc_objs(struct dbdma_cmd, + host->sg_tablesize + 2); if (!dma_cmd_space) { printk(KERN_ERR "mac53c94: couldn't allocate dma " "command space for %pOF\n", node); diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index ff0253d47a0e..a0ceaa2428c2 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -323,7 +323,7 @@ static int esp_mac_probe(struct platform_device *dev) host->this_id = esp->scsi_id; esp->scsi_id_mask = 1 << esp->scsi_id; - mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL); + mep = kzalloc_obj(struct mac_esp_priv); if (!mep) goto fail_free_command_block; mep->esp = esp; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index adab151663dd..9476a0d2c72d 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -372,11 +372,11 @@ mega_runpendq(adapter_t *adapter) * * The command queuing entry point for the mid-layer. */ -static int megaraid_queue_lck(struct scsi_cmnd *scmd) +static enum scsi_qc_status megaraid_queue_lck(struct scsi_cmnd *scmd) { adapter_t *adapter; scb_t *scb; - int busy=0; + enum scsi_qc_status busy = 0; unsigned long flags; adapter = (adapter_t *)scmd->device->host->hostdata; @@ -518,7 +518,8 @@ mega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel) * boot settings. */ static scb_t * -mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) +mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, + enum scsi_qc_status *busy) { mega_passthru *pthru; scb_t *scb; @@ -640,7 +641,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) } if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -688,7 +689,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } pthru = scb->pthru; @@ -730,7 +731,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } mbox = (mbox_t *)scb->raw_mbox; @@ -855,8 +856,8 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) return scb; #if MEGA_HAVE_CLUSTERING - case RESERVE: - case RELEASE: + case RESERVE_6: + case RELEASE_6: /* * Do we support clustering and is the support enabled @@ -870,12 +871,12 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } scb->raw_mbox[0] = MEGA_CLUSTER_CMD; - scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ? + scb->raw_mbox[2] = *cmd->cmnd == RESERVE_6 ? MEGA_RESERVE_LD : MEGA_RELEASE_LD; scb->raw_mbox[3] = ldrv_num; @@ -898,7 +899,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) else { /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1618,8 +1619,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) * failed or the input parameter is invalid */ if( status == 1 && - (cmd->cmnd[0] == RESERVE || - cmd->cmnd[0] == RELEASE) ) { + (cmd->cmnd[0] == RESERVE_6 || + cmd->cmnd[0] == RELEASE_6) ) { cmd->result |= (DID_ERROR << 16) | SAM_STAT_RESERVATION_CONFLICT; @@ -2780,7 +2781,7 @@ static inline void mega_create_proc_entry(int index, struct proc_dir_entry *pare * Return the disk geometry for a particular disk */ static int -megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, +megaraid_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { adapter_t *adapter; @@ -2813,7 +2814,7 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, geom[2] = cylinders; } else { - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; dev_info(&adapter->dev->dev, @@ -4253,8 +4254,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto out_host_put; } - adapter->scb_list = kmalloc_array(MAX_COMMANDS, sizeof(scb_t), - GFP_KERNEL); + adapter->scb_list = kmalloc_objs(scb_t, MAX_COMMANDS); if (!adapter->scb_list) { dev_warn(&pdev->dev, "out of RAM\n"); goto out_free_cmd_buffer; diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 013fbfb911b9..ecbaa0a0ab51 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -962,8 +962,10 @@ static int mega_query_adapter(adapter_t *); static int issue_scb(adapter_t *, scb_t *); static int mega_setup_mailbox(adapter_t *); -static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *); -static scb_t * mega_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *mega_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void __mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); @@ -975,7 +977,7 @@ static void mega_free_scb(adapter_t *, scb_t *); static int megaraid_abort(struct scsi_cmnd *); static int megaraid_reset(struct scsi_cmnd *); static int megaraid_abort_and_reset(adapter_t *, struct scsi_cmnd *, int); -static int megaraid_biosparam(struct scsi_device *, struct block_device *, +static int megaraid_biosparam(struct scsi_device *, struct gendisk *, sector_t, int []); static int mega_build_sglist (adapter_t *adapter, scb_t *scb, diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 60cc3372991f..06cf94ee4e36 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -109,8 +109,10 @@ static int megaraid_mbox_fire_sync_cmd(adapter_t *); static void megaraid_mbox_display_scb(adapter_t *, scb_t *); static void megaraid_mbox_setup_device_map(adapter_t *); -static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue_command(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void megaraid_mbox_runpendq(adapter_t *, scb_t *); static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, struct scsi_cmnd *); @@ -427,7 +429,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); // Allocate the per driver initialization structure - adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); + adapter = kzalloc_obj(adapter_t); if (adapter == NULL) { con_log(CL_ANN, (KERN_WARNING @@ -711,7 +713,7 @@ megaraid_init_mbox(adapter_t *adapter) * Allocate and initialize the init data structure for mailbox * controllers */ - raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); + raid_dev = kzalloc_obj(mraid_device_t); if (raid_dev == NULL) return -1; @@ -1015,7 +1017,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) * since the calling routine does not yet know the number of available * commands. */ - adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); + adapter->kscb_list = kzalloc_objs(scb_t, MBOX_MAX_SCSI_CMDS); if (adapter->kscb_list == NULL) { con_log(CL_ANN, (KERN_WARNING @@ -1434,12 +1436,12 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb) * * Queue entry point for mailbox based controllers. */ -static int megaraid_queue_command_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status megaraid_queue_command_lck(struct scsi_cmnd *scp) { void (*done)(struct scsi_cmnd *) = scsi_done; adapter_t *adapter; scb_t *scb; - int if_busy; + enum scsi_qc_status if_busy; adapter = SCP2ADAPTER(scp); scp->result = 0; @@ -1477,7 +1479,8 @@ static DEF_SCSI_QCMD(megaraid_queue_command) * firmware. We also complete certain commands without sending them to firmware. */ static scb_t * -megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) +megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, + enum scsi_qc_status *busy) { mraid_device_t *rdev = ADAP2RAIDDEV(adapter); int channel; @@ -1516,7 +1519,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1599,7 +1602,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) /* Allocate a SCB and initialize passthru */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1644,7 +1647,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; @@ -1725,8 +1728,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) return scb; - case RESERVE: - case RELEASE: + case RESERVE_6: + case RELEASE_6: /* * Do we support clustering and is the support enabled */ @@ -1740,7 +1743,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1748,7 +1751,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) scb->dev_channel = 0xFF; scb->dev_target = target; ccb->raw_mbox[0] = CLUSTER_CMD; - ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? + ccb->raw_mbox[2] = scp->cmnd[0] == RESERVE_6 ? RESERVE_LD : RELEASE_LD; ccb->raw_mbox[3] = target; @@ -1808,7 +1811,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) // Allocate a SCB and initialize passthru if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -2334,8 +2337,8 @@ megaraid_mbox_dpc(unsigned long devp) * Error code returned is 1 if Reserve or Release * failed or the input parameter is invalid */ - if (status == 1 && (scp->cmnd[0] == RESERVE || - scp->cmnd[0] == RELEASE)) { + if (status == 1 && (scp->cmnd[0] == RESERVE_6 || + scp->cmnd[0] == RELEASE_6)) { scp->result = DID_ERROR << 16 | SAM_STAT_RESERVATION_CONFLICT; @@ -3400,7 +3403,7 @@ megaraid_cmm_register(adapter_t *adapter) int i; // Allocate memory for the base list of scb for management module. - adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL); + adapter->uscb_list = kzalloc_objs(scb_t, MBOX_MAX_USER_CMDS); if (adapter->uscb_list == NULL) { con_log(CL_ANN, (KERN_WARNING @@ -3760,9 +3763,9 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter) mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); int rval = 0; - raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL); + raid_dev->sysfs_uioc = kmalloc_obj(uioc_t); - raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL); + raid_dev->sysfs_mbox64 = kmalloc_obj(mbox64_t); raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev, PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL); @@ -3836,7 +3839,7 @@ megaraid_sysfs_get_ldmap_done(uioc_t *uioc) static void megaraid_sysfs_get_ldmap_timeout(struct timer_list *t) { - struct uioc_timeout *timeout = from_timer(timeout, t, timer); + struct uioc_timeout *timeout = timer_container_of(timeout, t, timer); uioc_t *uioc = timeout->uioc; adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); @@ -3951,8 +3954,8 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter) } - del_timer_sync(&timeout.timer); - destroy_timer_on_stack(&timeout.timer); + timer_delete_sync(&timeout.timer); + timer_destroy_on_stack(&timeout.timer); mutex_unlock(&raid_dev->sysfs_mtx); diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index c509440bd161..538da0e98131 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -703,8 +703,8 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc) */ wait_event(wait_q, (kioc->status != -ENODATA)); if (timeout.timer.function) { - del_timer_sync(&timeout.timer); - destroy_timer_on_stack(&timeout.timer); + timer_delete_sync(&timeout.timer); + timer_destroy_on_stack(&timeout.timer); } /* @@ -783,7 +783,7 @@ ioctl_done(uioc_t *kioc) static void lld_timedout(struct timer_list *t) { - struct uioc_timeout *timeout = from_timer(timeout, t, timer); + struct uioc_timeout *timeout = timer_container_of(timeout, t, timer); uioc_t *kioc = timeout->uioc; kioc->status = -ETIME; @@ -913,7 +913,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) if (lld_adp->drvr_type != DRVRTYPE_MBOX) return (-EINVAL); - adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); + adapter = kzalloc_obj(mraid_mmadp_t); if (!adapter) return -ENOMEM; @@ -932,12 +932,8 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) * Allocate single blocks of memory for all required kiocs, * mailboxes and passthru structures. */ - adapter->kioc_list = kmalloc_array(lld_adp->max_kioc, - sizeof(uioc_t), - GFP_KERNEL); - adapter->mbox_list = kmalloc_array(lld_adp->max_kioc, - sizeof(mbox64_t), - GFP_KERNEL); + adapter->kioc_list = kmalloc_objs(uioc_t, lld_adp->max_kioc); + adapter->mbox_list = kmalloc_objs(mbox64_t, lld_adp->max_kioc); adapter->pthru_dma_pool = dma_pool_create("megaraid mm pthru pool", &adapter->pdev->dev, sizeof(mraid_passthru_t), diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 088cc40ae866..8ee2bfe47571 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -23,8 +23,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.727.03.00-rc1" -#define MEGASAS_RELDATE "Oct 03, 2023" +#define MEGASAS_VERSION "07.734.00.00-rc1" +#define MEGASAS_RELDATE "Apr 03, 2025" #define MEGASAS_MSIX_NAME_LEN 32 diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d85f990aec88..ecd365d78ae3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -93,7 +93,7 @@ static unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; module_param(scmd_timeout, int, 0444); MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer."); -int perf_mode = -1; +static int perf_mode = -1; module_param(perf_mode, int, 0444); MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" "0 - balanced: High iops and low latency queues are allocated &\n\t\t" @@ -105,15 +105,15 @@ MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options: "default mode is 'balanced'" ); -int event_log_level = MFI_EVT_CLASS_CRITICAL; +static int event_log_level = MFI_EVT_CLASS_CRITICAL; module_param(event_log_level, int, 0644); MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)"); -unsigned int enable_sdev_max_qd; +static unsigned int enable_sdev_max_qd; module_param(enable_sdev_max_qd, int, 0444); MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0"); -int poll_queues; +static int poll_queues; module_param(poll_queues, int, 0444); MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t" "This parameter is effective only if host_tagset_enable=1 &\n\t\t" @@ -122,7 +122,7 @@ MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode "High iops queues are not allocated &\n\t\t" ); -int host_tagset_enable = 1; +static int host_tagset_enable = 1; module_param(host_tagset_enable, int, 0444); MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); @@ -1781,8 +1781,8 @@ out_return_cmd: * @shost: adapter SCSI host * @scmd: SCSI command to be queued */ -static int -megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status megasas_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct megasas_instance *instance; struct MR_PRIV_DEVICE *mr_device_priv_data; @@ -2103,6 +2103,9 @@ static int megasas_sdev_configure(struct scsi_device *sdev, /* This sdev property may change post OCR */ megasas_set_dynamic_target_properties(sdev, lim, is_target_prop); + if (!MEGASAS_IS_LOGICAL(sdev)) + sdev->no_vpd_size = 1; + mutex_unlock(&instance->reset_mutex); return 0; @@ -2134,8 +2137,7 @@ static int megasas_sdev_init(struct scsi_device *sdev) } scan_target: - mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data), - GFP_KERNEL); + mr_device_priv_data = kzalloc_obj(*mr_device_priv_data); if (!mr_device_priv_data) return -ENOMEM; @@ -2721,7 +2723,7 @@ out: static void megasas_sriov_heartbeat_handler(struct timer_list *t) { struct megasas_instance *instance = - from_timer(instance, t, sriov_heartbeat_timer); + timer_container_of(instance, t, sriov_heartbeat_timer); if (instance->hb_host_mem->HB.fwCounter != instance->hb_host_mem->HB.driverCounter) { @@ -3134,12 +3136,12 @@ static int megasas_reset_target(struct scsi_cmnd *scmd) /** * megasas_bios_param - Returns disk geometry for a disk * @sdev: device handle - * @bdev: block device + * @unused: gendisk * @capacity: drive capacity * @geom: geometry parameters */ static int -megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, +megasas_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads; @@ -3252,7 +3254,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) ((instance->issuepend_done == 1))) { struct megasas_aen_event *ev; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc_obj(*ev, GFP_ATOMIC); if (!ev) { dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n"); } else { @@ -3662,8 +3664,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, case MFI_STAT_SCSI_IO_FAILED: case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = - (DID_ERROR << 16) | hdr->scsi_status; + if (hdr->scsi_status == 0xf0) + cmd->scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION; + else + cmd->scmd->result = (DID_ERROR << 16) | hdr->scsi_status; break; case MFI_STAT_SCSI_DONE_WITH_ERROR: @@ -4463,7 +4467,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance) * Allocate the dynamic array first and then allocate individual * commands. */ - instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL); + instance->cmd_list = kzalloc_objs(struct megasas_cmd *, max_cmd); if (!instance->cmd_list) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n"); @@ -4471,8 +4475,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance) } for (i = 0; i < max_cmd; i++) { - instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), - GFP_KERNEL); + instance->cmd_list[i] = kmalloc_obj(struct megasas_cmd); if (!instance->cmd_list[i]) { @@ -5905,7 +5908,11 @@ megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance) const struct cpumask *mask; if (instance->perf_mode == MR_BALANCED_PERF_MODE) { - mask = cpumask_of_node(dev_to_node(&instance->pdev->dev)); + int nid = dev_to_node(&instance->pdev->dev); + + if (nid == NUMA_NO_NODE) + nid = 0; + mask = cpumask_of_node(nid); for (i = 0; i < instance->low_latency_index_start; i++) { irq = pci_irq_vector(instance->pdev, i); @@ -5962,7 +5969,8 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance) else instance->iopoll_q_count = 0; - num_msix_req = num_online_cpus() + instance->low_latency_index_start; + num_msix_req = blk_mq_num_online_queues(0) + + instance->low_latency_index_start; instance->msix_vectors = min(num_msix_req, instance->msix_vectors); @@ -5978,7 +5986,8 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance) /* Disable Balanced IOPS mode and try realloc vectors */ instance->perf_mode = MR_LATENCY_PERF_MODE; instance->low_latency_index_start = 1; - num_msix_req = num_online_cpus() + instance->low_latency_index_start; + num_msix_req = blk_mq_num_online_queues(0) + + instance->low_latency_index_start; instance->msix_vectors = min(num_msix_req, instance->msix_vectors); @@ -6234,7 +6243,7 @@ static int megasas_init_fw(struct megasas_instance *instance) intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? true : false; if (intr_coalescing && - (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && + (blk_mq_num_online_queues(0) >= MR_HIGH_IOPS_QUEUE_COUNT) && (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) instance->perf_mode = MR_BALANCED_PERF_MODE; else @@ -6278,7 +6287,8 @@ static int megasas_init_fw(struct megasas_instance *instance) else instance->low_latency_index_start = 1; - num_msix_req = num_online_cpus() + instance->low_latency_index_start; + num_msix_req = blk_mq_num_online_queues(0) + + instance->low_latency_index_start; instance->msix_vectors = min(num_msix_req, instance->msix_vectors); @@ -6310,8 +6320,8 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_reply_map(instance); dev_info(&instance->pdev->dev, - "current msix/online cpus\t: (%d/%d)\n", - instance->msix_vectors, (unsigned int)num_online_cpus()); + "current msix/max num queues\t: (%d/%u)\n", + instance->msix_vectors, blk_mq_num_online_queues(0)); dev_info(&instance->pdev->dev, "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled"); @@ -6355,19 +6365,20 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_jbod_map(instance); - if (megasas_get_device_list(instance) != SUCCESS) { - dev_err(&instance->pdev->dev, - "%s: megasas_get_device_list failed\n", - __func__); - goto fail_get_ld_pd_list; + scoped_guard(mutex, &instance->reset_mutex) { + if (megasas_get_device_list(instance) != SUCCESS) { + dev_err(&instance->pdev->dev, + "%s: megasas_get_device_list failed\n", + __func__); + goto fail_get_ld_pd_list; + } } /* stream detection initialization */ if (instance->adapter_type >= VENTURA_SERIES) { fusion->stream_detect_by_ld = - kcalloc(MAX_LOGICAL_DRIVES_EXT, - sizeof(struct LD_STREAM_DETECT *), - GFP_KERNEL); + kzalloc_objs(struct LD_STREAM_DETECT *, + MAX_LOGICAL_DRIVES_EXT); if (!fusion->stream_detect_by_ld) { dev_err(&instance->pdev->dev, "unable to allocate stream detection for pool of LDs\n"); @@ -6375,8 +6386,7 @@ static int megasas_init_fw(struct megasas_instance *instance) } for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) { fusion->stream_detect_by_ld[i] = - kzalloc(sizeof(struct LD_STREAM_DETECT), - GFP_KERNEL); + kzalloc_obj(struct LD_STREAM_DETECT); if (!fusion->stream_detect_by_ld[i]) { dev_err(&instance->pdev->dev, "unable to allocate stream detect by LD\n"); @@ -6460,7 +6470,8 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (instance->snapdump_wait_time) { - megasas_get_snapdump_properties(instance); + scoped_guard(mutex, &instance->reset_mutex) + megasas_get_snapdump_properties(instance); dev_info(&instance->pdev->dev, "Snap dump wait time\t: %d\n", instance->snapdump_wait_time); } @@ -6521,7 +6532,7 @@ static int megasas_init_fw(struct megasas_instance *instance) fail_start_watchdog: if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); fail_get_ld_pd_list: instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); @@ -7603,7 +7614,7 @@ fail_io_attach: megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL; if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); @@ -7743,7 +7754,7 @@ megasas_suspend(struct device *dev) /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); /* Stop the FW fault detection watchdog */ if (instance->adapter_type != MFI_SERIES) @@ -7907,7 +7918,7 @@ megasas_resume(struct device *dev) fail_start_watchdog: if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); fail_init_mfi: megasas_free_ctrl_dma_buffers(instance); megasas_free_ctrl_mem(instance); @@ -7971,7 +7982,7 @@ static void megasas_detach_one(struct pci_dev *pdev) /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); /* Stop the FW fault detection watchdog */ if (instance->adapter_type != MFI_SERIES) @@ -8484,7 +8495,7 @@ megasas_compat_iocpacket_get_user(void __user *arg) int err = -EFAULT; int i; - ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + ioc = kzalloc_obj(*ioc); if (!ioc) return ERR_PTR(-ENOMEM); size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame); diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c index c69760775efa..81698cd83f5a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_debugfs.c +++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c @@ -65,7 +65,7 @@ megasas_debugfs_raidmap_open(struct inode *inode, struct file *file) fusion = instance->ctrl_context; - debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL); + debug = kzalloc_obj(struct megasas_debugfs_buffer); if (!debug) return -ENOMEM; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 1eec23da28e2..2699e4e09b5b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -598,8 +598,7 @@ megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) * commands. */ fusion->cmd_list = - kcalloc(max_mpt_cmd, sizeof(struct megasas_cmd_fusion *), - GFP_KERNEL); + kzalloc_objs(struct megasas_cmd_fusion *, max_mpt_cmd); if (!fusion->cmd_list) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); @@ -607,8 +606,7 @@ megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) } for (i = 0; i < max_mpt_cmd; i++) { - fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion), - GFP_KERNEL); + fusion->cmd_list[i] = kzalloc_obj(struct megasas_cmd_fusion); if (!fusion->cmd_list[i]) { for (j = 0; j < i; j++) kfree(fusion->cmd_list[j]); @@ -1744,7 +1742,7 @@ static int megasas_alloc_ioc_init_frame(struct megasas_instance *instance) fusion = instance->ctrl_context; - cmd = kzalloc(sizeof(struct megasas_cmd), GFP_KERNEL); + cmd = kzalloc_obj(struct megasas_cmd); if (!cmd) { dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n", @@ -2043,7 +2041,10 @@ map_cmd_status(struct fusion_context *fusion, case MFI_STAT_SCSI_IO_FAILED: case MFI_STAT_LD_INIT_IN_PROGRESS: - scmd->result = (DID_ERROR << 16) | ext_status; + if (ext_status == 0xf0) + scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION; + else + scmd->result = (DID_ERROR << 16) | ext_status; break; case MFI_STAT_SCSI_DONE_WITH_ERROR: @@ -4969,7 +4970,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); set_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags); atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING); @@ -5295,8 +5296,7 @@ megasas_alloc_fusion_context(struct megasas_instance *instance) { struct fusion_context *fusion; - instance->ctrl_context = kzalloc(sizeof(struct fusion_context), - GFP_KERNEL); + instance->ctrl_context = kzalloc_obj(struct fusion_context); if (!instance->ctrl_context) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index b677d80e5874..ddeea0ee2834 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1150,9 +1150,13 @@ typedef struct LOG_BLOCK_SPAN_INFO { } LD_SPAN_INFO, *PLD_SPAN_INFO; struct MR_FW_RAID_MAP_ALL { - struct MR_FW_RAID_MAP raidMap; - struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES]; + /* Must be last --ends in a flexible-array member. */ + TRAILING_OVERLAP(struct MR_FW_RAID_MAP, raidMap, ldSpanMap, + struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES]; + ); } __attribute__ ((packed)); +static_assert(offsetof(struct MR_FW_RAID_MAP_ALL, raidMap.ldSpanMap) == + offsetof(struct MR_FW_RAID_MAP_ALL, ldSpanMap)); struct MR_DRV_RAID_MAP { /* total size of this structure, including this field. @@ -1194,10 +1198,13 @@ struct MR_DRV_RAID_MAP { * And it is mainly for code re-use purpose. */ struct MR_DRV_RAID_MAP_ALL { - - struct MR_DRV_RAID_MAP raidMap; - struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_DYN]; + /* Must be last --ends in a flexible-array member. */ + TRAILING_OVERLAP(struct MR_DRV_RAID_MAP, raidMap, ldSpanMap, + struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_DYN]; + ); } __packed; +static_assert(offsetof(struct MR_DRV_RAID_MAP_ALL, raidMap.ldSpanMap) == + offsetof(struct MR_DRV_RAID_MAP_ALL, ldSpanMap)); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 1c15cac41d80..dc1402b321da 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1625,7 +1625,7 @@ static void cmd_complete(struct mesh_state *ms) * Called by midlayer with host locked to queue a new * request */ -static int mesh_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mesh_queue_lck(struct scsi_cmnd *cmd) { struct mesh_state *ms; @@ -1762,6 +1762,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) case PM_EVENT_SUSPEND: case PM_EVENT_HIBERNATE: case PM_EVENT_FREEZE: + case PM_EVENT_POWEROFF: break; default: return 0; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 00cd18edfad6..33dd303c97bb 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2017-2023 Broadcom Inc. All rights reserved. + * Copyright 2017-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_CNFG_H #define MPI30_CNFG_H 1 @@ -19,6 +19,7 @@ #define MPI3_CONFIG_PAGETYPE_PCIE_SWITCH (0x31) #define MPI3_CONFIG_PAGETYPE_PCIE_LINK (0x33) #define MPI3_CONFIG_PAGEATTR_MASK (0xf0) +#define MPI3_CONFIG_PAGEATTR_SHIFT (4) #define MPI3_CONFIG_PAGEATTR_READ_ONLY (0x00) #define MPI3_CONFIG_PAGEATTR_CHANGEABLE (0x10) #define MPI3_CONFIG_PAGEATTR_PERSISTENT (0x20) @@ -29,10 +30,13 @@ #define MPI3_CONFIG_ACTION_READ_PERSISTENT (0x04) #define MPI3_CONFIG_ACTION_WRITE_PERSISTENT (0x05) #define MPI3_DEVICE_PGAD_FORM_MASK (0xf0000000) +#define MPI3_DEVICE_PGAD_FORM_SHIFT (28) #define MPI3_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) #define MPI3_DEVICE_PGAD_FORM_HANDLE (0x20000000) #define MPI3_DEVICE_PGAD_HANDLE_MASK (0x0000ffff) +#define MPI3_DEVICE_PGAD_HANDLE_SHIFT (0) #define MPI3_SAS_EXPAND_PGAD_FORM_MASK (0xf0000000) +#define MPI3_SAS_EXPAND_PGAD_FORM_SHIFT (28) #define MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) #define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x10000000) #define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE (0x20000000) @@ -318,6 +322,9 @@ struct mpi3_man6_gpio_entry { #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_MASK (0x01) #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_EDGE (0x00) #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_LEVEL (0x01) +#define MPI3_MAN6_GPIO_OVER_TEMP_PARAM1_LEVEL_WARNING (0x00) +#define MPI3_MAN6_GPIO_OVER_TEMP_PARAM1_LEVEL_CRITICAL (0x01) +#define MPI3_MAN6_GPIO_OVER_TEMP_PARAM1_LEVEL_FATAL (0x02) #define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ALL_UP (0x00) #define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ONE_OR_MORE_UP (0x01) #define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_MODULE_PRESENT (0x00) @@ -1030,6 +1037,7 @@ struct mpi3_io_unit_page5 { #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_SHIFT (2) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_MASK (0x0003) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_SHIFT (0) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_ENABLE (0x8000) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_MASK (0x0c) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_NOT_SUPPORTED (0x00) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_OS_CONTROLLED (0x04) @@ -1067,7 +1075,8 @@ struct mpi3_io_unit_page8 { u8 current_key_encryption_algo; u8 key_digest_hash_algo; union mpi3_version_union current_svn; - __le32 reserved14; + __le16 pending_svn_time; + __le16 reserved16; __le32 current_key[128]; union mpi3_iounit8_digest digest[MPI3_IOUNIT8_DIGEST_MAX]; }; @@ -1246,6 +1255,37 @@ struct mpi3_io_unit_page17 { __le32 current_key[]; }; #define MPI3_IOUNIT17_PAGEVERSION (0x00) +struct mpi3_io_unit_page18 { + struct mpi3_config_page_header header; + u8 flags; + u8 poll_interval; + __le16 reserved0a; + __le32 reserved0c; +}; + +#define MPI3_IOUNIT18_PAGEVERSION (0x00) +#define MPI3_IOUNIT18_FLAGS_DIRECTATTACHED_ENABLE (0x01) +#define MPI3_IOUNIT18_POLLINTERVAL_DISABLE (0x00) +#ifndef MPI3_IOUNIT19_DEVICE_MAX +#define MPI3_IOUNIT19_DEVICE_MAX (1) +#endif +struct mpi3_iounit19_device { + __le16 temperature; + __le16 dev_handle; + __le16 persistent_id; + __le16 reserved06; +}; + +#define MPI3_IOUNIT19_DEVICE_TEMPERATURE_UNAVAILABLE (0x8000) +struct mpi3_io_unit_page19 { + struct mpi3_config_page_header header; + __le16 num_devices; + __le16 reserved0a; + __le32 reserved0c; + struct mpi3_iounit19_device device[MPI3_IOUNIT19_DEVICE_MAX]; +}; + +#define MPI3_IOUNIT19_PAGEVERSION (0x00) struct mpi3_ioc_page0 { struct mpi3_config_page_header header; __le32 reserved08; @@ -1368,6 +1408,7 @@ struct mpi3_driver_page1 { }; #define MPI3_DRIVER1_PAGEVERSION (0x00) +#define MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE (0x0001) #ifndef MPI3_DRIVER2_TRIGGER_MAX #define MPI3_DRIVER2_TRIGGER_MAX (1) #endif @@ -1523,7 +1564,9 @@ struct mpi3_security1_key_record { u8 consumer; __le16 key_data_size; __le32 additional_key_data; - __le32 reserved08[2]; + u8 library_version; + u8 reserved09[3]; + __le32 reserved0c; union mpi3_security1_key_data key_data; }; @@ -1576,6 +1619,85 @@ struct mpi3_security_page2 { u8 reserved9d[3]; struct mpi3_security2_trusted_root trusted_root[MPI3_SECURITY2_TRUSTED_ROOT_MAX]; }; + +struct mpi3_security_page3 { + struct mpi3_config_page_header header; + __le16 key_data_length; + __le16 reserved0a; + u8 key_number; + u8 reserved0d[3]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le32 reserved90[12]; + u8 flags; + u8 consumer; + __le16 key_data_size; + __le32 additional_key_data; + u8 library_version; + u8 reserved_c9[3]; + __le32 reserved_cc; + u8 key_data[]; +}; + +#define MPI3_SECURITY3_PAGEVERSION (0x00) +#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x0f) +#define MPI3_SECURITY3_FLAGS_TYPE_SHIFT (0) +#define MPI3_SECURITY3_FLAGS_TYPE_NOT_VALID (0) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PRIVATE (1) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PUBLIC (2) +struct mpi3_security_page10 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le64 current_token_nonce; + __le64 previous_token_nonce; + __le32 reserved_a0[8]; + u8 diagnostic_auth_id[64]; +}; +#define MPI3_SECURITY10_PAGEVERSION (0x00) + +struct mpi3_security_page11 { + struct mpi3_config_page_header header; + u8 flags; + u8 reserved09[3]; + __le32 reserved0c; + __le32 diagnostic_token_length; + __le32 reserved14[3]; + u8 diagnostic_token[]; +}; +#define MPI3_SECURITY11_PAGEVERSION (0x00) +#define MPI3_SECURITY11_FLAGS_TOKEN_ENABLED (0x01) + +struct mpi3_security12_diag_feature { + __le32 feature_identifier; + u8 feature_size; + u8 feature_type; + __le16 reserved06; + u8 status; + u8 section; + __le16 reserved0a; + __le32 reserved0c; + u8 feature_data[64]; +}; +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_MASK (0x03) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_SHIFT (0) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_UNKNOWN (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_DISABLED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_ENABLED (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PROTECTED (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_UNPROTECTED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PAYLOAD (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_SIGNATURE (0x03) +struct mpi3_security_page12 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + u8 num_diag_features; + u8 reserved11[3]; + __le32 reserved14[3]; + struct mpi3_security12_diag_feature diag_feature[]; +}; + #define MPI3_SECURITY2_PAGEVERSION (0x00) struct mpi3_sas_io_unit0_phy_data { u8 io_unit_port; @@ -2276,6 +2398,8 @@ struct mpi3_device0_sas_sata_format { u8 attached_phy_identifier; u8 max_port_connections; u8 zone_group; + u8 reserved10[3]; + u8 negotiated_link_rate; }; #define MPI3_DEVICE0_SASSATA_FLAGS_WRITE_SAME_UNMAP_NCQ (0x0400) @@ -2352,7 +2476,9 @@ struct mpi3_device0_vd_format { __le16 io_throttle_group; __le16 io_throttle_group_low; __le16 io_throttle_group_high; - __le32 reserved0c; + u8 vd_abort_to; + u8 vd_reset_to; + __le16 reserved0e; }; #define MPI3_DEVICE0_VD_STATE_OFFLINE (0x00) #define MPI3_DEVICE0_VD_STATE_PARTIALLY_DEGRADED (0x01) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h index 2c6e548cbd0f..62ddf094d46c 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2018-2023 Broadcom Inc. All rights reserved. + * Copyright 2018-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_IMAGE_H #define MPI30_IMAGE_H 1 @@ -66,7 +66,12 @@ struct mpi3_component_image_header { #define MPI3_IMAGE_HEADER_SIGNATURE1_SMM (0x204d4d53) #define MPI3_IMAGE_HEADER_SIGNATURE1_PSW (0x20575350) #define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546) +#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_MASK (0x00000300) +#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_SHIFT (8) +#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_MASK (0x000000c0) +#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_SHIFT (6) #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030) +#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_SHIFT (4) #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000) #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_DI (0x00000010) #define MPI3_IMAGE_HEADER_FLAGS_SIGNED_NVDATA (0x00000008) @@ -130,7 +135,7 @@ struct mpi3_ci_manifest_mpi { __le32 package_version_string_offset; __le32 package_build_date_string_offset; __le32 package_build_time_string_offset; - __le32 reserved4c; + __le32 diag_authorization_key_offset; __le32 diag_authorization_identifier[16]; struct mpi3_ci_manifest_mpi_comp_image_ref component_image_ref[MPI3_CI_MANIFEST_MPI_MAX]; }; @@ -143,16 +148,112 @@ struct mpi3_ci_manifest_mpi { #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_GCA (0x50) #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_POINT (0x60) #define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTHORIZATION (0x01) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_MASK (0x06) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_SHIFT (1) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_IDENTIFIER (0x00) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_KEY_OFFSET (0x02) #define MPI3_CI_MANIFEST_MPI_SUBSYSTEMID_IGNORED (0xffff) #define MPI3_CI_MANIFEST_MPI_PKG_VER_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_DATE_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_TIME_STR_OFF_UNSPECIFIED (0x00000000) + +struct mpi3_sb_manifest_ci_digest { + __le32 signature1; + __le32 reserved04[2]; + u8 hash_algorithm; + u8 reserved09[3]; + struct mpi3_comp_image_version component_image_version; + __le32 component_image_version_string_offset; + __le32 digest[16]; +}; + +struct mpi3_sb_manifest_ci_ref_element { + u8 num_ci_digests; + u8 reserved01[3]; + struct mpi3_sb_manifest_ci_digest ci_digest[]; +}; + +struct mpi3_sb_manifest_embedded_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 start_tag; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_STRT (0x00) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_K2GO (0x01) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_STRT (0x54525453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_K2GO (0x4f47324b) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_STOP (0x504f5453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_K2ST (0x5453324b) + +struct mpi3_sb_manifest_diag_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYSELECT_FW_KEY (0x04) +union mpi3_sb_manifest_element_data { + struct mpi3_sb_manifest_ci_ref_element ci_ref; + struct mpi3_sb_manifest_embedded_key_element embed_key; + struct mpi3_sb_manifest_diag_key_element diag_key; + __le32 dword; +}; +struct mpi3_sb_manifest_element { + u8 manifest_element_form; + u8 reserved01[3]; + union mpi3_sb_manifest_element_data form_specific[]; +}; +#define MPI3_SB_MANIFEST_ELEMENT_FORM_CI_REFS (0x01) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_EMBED_KEY (0x02) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_DIAG_KEY (0x03) +struct mpi3_sb_manifest_mpi { + u8 manifest_type; + u8 reserved01[3]; + __le32 reserved04[3]; + u8 reserved10; + u8 release_level; + __le16 reserved12; + __le16 reserved14; + __le16 flags; + __le32 reserved18[2]; + __le16 vendor_id; + __le16 device_id; + __le16 subsystem_vendor_id; + __le16 subsystem_id; + __le32 reserved28[2]; + union mpi3_version_union package_security_version; + __le32 reserved34; + struct mpi3_comp_image_version package_version; + __le32 package_version_string_offset; + __le32 package_build_date_string_offset; + __le32 package_build_time_string_offset; + __le32 component_image_references_offset; + __le32 embedded_key0offset; + __le32 embedded_key1offset; + __le32 diag_authorization_key_offset; + __le32 reserved5c[9]; + struct mpi3_sb_manifest_element manifest_elements[]; +}; + union mpi3_ci_manifest { struct mpi3_ci_manifest_mpi mpi; + struct mpi3_sb_manifest_mpi sb_mpi; __le32 dword[1]; }; -#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_SB_MANIFEST_APU_IMMEDIATE_DEFER_APU_ENABLE (0x01) + +#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_CI_MANIFEST_TYPE_SB (0x01) + struct mpi3_extended_image_header { u8 image_type; u8 reserved01[3]; @@ -214,11 +315,13 @@ struct mpi3_encrypted_hash_entry { #define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_1_OF_2 (0x04) #define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_2_OF_2 (0x05) #define MPI3_HASH_ALGORITHM_VERSION_MASK (0xe0) +#define MPI3_HASH_ALGORITHM_VERSION_SHIFT (5) #define MPI3_HASH_ALGORITHM_VERSION_NONE (0x00) #define MPI3_HASH_ALGORITHM_VERSION_SHA1 (0x20) #define MPI3_HASH_ALGORITHM_VERSION_SHA2 (0x40) #define MPI3_HASH_ALGORITHM_VERSION_SHA3 (0x60) #define MPI3_HASH_ALGORITHM_SIZE_MASK (0x1f) +#define MPI3_HASH_ALGORITHM_SIZE_SHIFT (0) #define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00) #define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01) #define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02) @@ -236,6 +339,7 @@ struct mpi3_encrypted_hash_entry { #define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_65 (0x0c) #define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_44 (0x0d) #define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_MASK (0x0f) +#define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_SHIFT (0) #ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX #define MPI3_ENCRYPTED_HASH_ENTRY_MAX (1) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h index af86d12c8e49..745e1101ebf4 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_INIT_H #define MPI30_INIT_H 1 @@ -38,23 +38,31 @@ struct mpi3_scsi_io_request { #define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80) #define MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE (0x40) #define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000) +#define MPI3_SCSIIO_FLAGS_LARGE_CDB_MASK (0x60000000) +#define MPI3_SCSIIO_FLAGS_LARGE_CDB_SHIFT (29) +#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_MASK (0x18000000) +#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_SHIFT (27) #define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000) #define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000) #define MPI3_SCSIIO_FLAGS_CDB_IN_SEPARATE_BUFFER (0x40000000) #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_MASK (0x07000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SHIFT (24) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_SHIFT (18) #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ (0x00000000) #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ (0x01000000) #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ (0x02000000) #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ (0x04000000) #define MPI3_SCSIIO_FLAGS_CMDPRI_MASK (0x00f00000) #define MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT (20) -#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000) #define MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER (0x00000000) #define MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE (0x00040000) #define MPI3_SCSIIO_FLAGS_DATADIRECTION_READ (0x00080000) #define MPI3_SCSIIO_FLAGS_DMAOPERATION_MASK (0x00030000) +#define MPI3_SCSIIO_FLAGS_DMAOPERATION_SHIFT (16) #define MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI (0x00010000) #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_MASK (0x000000f0) +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_SHIFT (4) #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING (0x00000010) #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE (0x00000020) #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_PROD_SPECIFIC (0x00000080) @@ -99,6 +107,7 @@ struct mpi3_scsi_io_reply { #define MPI3_SCSI_STATUS_ACA_ACTIVE (0x30) #define MPI3_SCSI_STATUS_TASK_ABORTED (0x40) #define MPI3_SCSI_STATE_SENSE_MASK (0x03) +#define MPI3_SCSI_STATE_SENSE_SHIFT (0) #define MPI3_SCSI_STATE_SENSE_VALID (0x00) #define MPI3_SCSI_STATE_SENSE_FAILED (0x01) #define MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY (0x02) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index c374867f9ba0..68efa0d51345 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -30,6 +30,7 @@ struct mpi3_ioc_init_request { #define MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED (0x08) #define MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED (0x04) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SHIFT (0) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_INLINE (0x02) @@ -40,6 +41,7 @@ struct mpi3_ioc_init_request { #define MPI3_WHOINIT_MANUFACTURER (0x04) #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_MASK (0x00000003) +#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_SHIFT (0) #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_GUIDANCE (0x00000000) #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_SPECIAL (0x00000001) #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_REPORT_AS_HDD (0x00000002) @@ -111,9 +113,11 @@ struct mpi3_ioc_facts_data { __le32 diag_tty_size; }; #define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_MASK (0x80000000) +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_SHIFT (31) #define MPI3_IOCFACTS_CAPABILITY_SUPERVISOR_IOC (0x00000000) #define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC (0x80000000) #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_MASK (0x00000600) +#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_SHIFT (9) #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_FIXED_THRESHOLD (0x00000000) #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_OUTSTANDING_IO (0x00000200) #define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_SUPPORTED (0x00000100) @@ -134,6 +138,7 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_EXCEPT_SAS_DISABLED (0x1000) #define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_SHIFT (8) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_MGMT (0x0100) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_MGMT (0x0200) @@ -149,6 +154,7 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_EXCEPT_BLOCKING_BOOT_EVENT (0x0004) #define MPI3_IOCFACTS_EXCEPT_SECURITY_SELFTEST_FAILURE (0x0002) #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x0001) +#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SHIFT (0) #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_PRIMARY (0x0000) #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SECONDARY (0x0001) #define MPI3_IOCFACTS_PROTOCOL_SAS (0x0010) @@ -160,11 +166,14 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) +#define MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT (0x00000040) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_IN_PROGRESS (0x00000010) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_COMPLETE (0x00000020) #define MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK (0x0000000f) +#define MPI3_IOCFACTS_FLAGS_PERSONALITY_SHIFT (0) #define MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA (0x00000000) #define MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR (0x00000002) #define MPI3_IOCFACTS_IO_THROTTLE_DATA_LENGTH_NOT_REQUIRED (0x0000) @@ -204,6 +213,7 @@ struct mpi3_create_request_queue_request { }; #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80) +#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SHIFT (7) #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) #define MPI3_CREATE_REQUEST_QUEUE_SIZE_MINIMUM (2) @@ -237,10 +247,12 @@ struct mpi3_create_reply_queue_request { }; #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_MASK (0x80) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SHIFT (7) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_COALESCE_DISABLE (0x02) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_SHIFT (0) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01) #define MPI3_CREATE_REPLY_QUEUE_SIZE_MINIMUM (2) @@ -326,9 +338,11 @@ struct mpi3_event_notification_reply { }; #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK (0x01) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_SHIFT (0) #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED (0x01) #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_NOT_REQUIRED (0x00) #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_MASK (0x02) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_SHIFT (1) #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_ORIGINAL (0x00) #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_REPLAY (0x02) struct mpi3_event_data_gpio_interrupt { @@ -487,6 +501,7 @@ struct mpi3_event_sas_topo_phy_entry { #define MPI3_EVENT_SAS_TOPO_PHY_STATUS_NO_EXIST (0x40) #define MPI3_EVENT_SAS_TOPO_PHY_STATUS_VACANT (0x80) #define MPI3_EVENT_SAS_TOPO_PHY_RC_MASK (0x0f) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_SHIFT (0) #define MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING (0x02) #define MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED (0x03) #define MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE (0x04) @@ -566,6 +581,7 @@ struct mpi3_event_pcie_topo_port_entry { #define MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05) #define MPI3_EVENT_PCIE_TOPO_PS_RESPONDING (0x06) #define MPI3_EVENT_PCIE_TOPO_PI_LANES_MASK (0xf0) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_SHIFT (4) #define MPI3_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00) #define MPI3_EVENT_PCIE_TOPO_PI_LANES_1 (0x10) #define MPI3_EVENT_PCIE_TOPO_PI_LANES_2 (0x20) @@ -573,6 +589,7 @@ struct mpi3_event_pcie_topo_port_entry { #define MPI3_EVENT_PCIE_TOPO_PI_LANES_8 (0x40) #define MPI3_EVENT_PCIE_TOPO_PI_LANES_16 (0x50) #define MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0f) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_SHIFT (0) #define MPI3_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00) #define MPI3_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01) #define MPI3_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02) @@ -645,6 +662,7 @@ struct mpi3_event_data_diag_buffer_status_change { #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED (0x01) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED (0x02) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED (0x03) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_CLEARED (0x04) #define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200) #define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100) #define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080) @@ -881,6 +899,7 @@ struct mpi3_pel_req_action_acknowledge { }; #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_MASK (0x03) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_SHIFT (0) #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_NO_GUIDANCE (0x00) #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_CONTINUE_OP (0x01) #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_TRANSITION_TO_FAULT (0x02) @@ -924,6 +943,7 @@ struct mpi3_ci_download_request { #define MPI3_CI_DOWNLOAD_MSGFLAGS_FORCE_FMC_ENABLE (0x40) #define MPI3_CI_DOWNLOAD_MSGFLAGS_SIGNED_NVDATA (0x20) #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MASK (0x03) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SHIFT (0) #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_FAST (0x00) #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MEDIUM (0x01) #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SLOW (0x02) @@ -953,6 +973,7 @@ struct mpi3_ci_download_reply { #define MPI3_CI_DOWNLOAD_FLAGS_OFFLINE_ACTIVATION_REQUIRED (0x20) #define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0e) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_SHIFT (1) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_AWAITING (0x02) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04) @@ -976,9 +997,11 @@ struct mpi3_ci_upload_request { }; #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_MASK (0x01) +#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SHIFT (0) #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY (0x00) #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SECONDARY (0x01) #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_MASK (0x02) +#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_SHIFT (1) #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_FLASH (0x00) #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_EXECUTABLE (0x02) #define MPI3_CTRL_OP_FORCE_FULL_DISCOVERY (0x01) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h index 7c15e5851ce4..3092dfe6d952 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. * */ #ifndef MPI30_PCI_H @@ -9,9 +9,11 @@ #define MPI3_NVME_ENCAP_CMD_MAX (1) #endif #define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_MASK (0x0002) +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_SHIFT (1) #define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_FAIL_ONLY (0x0000) #define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_ALL (0x0002) #define MPI3_NVME_FLAGS_SUBMISSIONQ_MASK (0x0001) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_SHIFT (0) #define MPI3_NVME_FLAGS_SUBMISSIONQ_IO (0x0000) #define MPI3_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0001) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h index 4a93c67d335f..f86da445df1e 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_SAS_H #define MPI30_SAS_H 1 @@ -11,6 +11,7 @@ #define MPI3_SAS_DEVICE_INFO_STP_INITIATOR (0x00000010) #define MPI3_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000008) #define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK (0x00000007) +#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_SHIFT (0) #define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE (0x00000000) #define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE (0x00000001) #define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER (0x00000002) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h index 3b960893870f..72d3e6bc52ec 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2024 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TOOL_H #define MPI30_TOOL_H 1 @@ -8,7 +8,12 @@ #define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01) #define MPI3_DIAG_BUFFER_TYPE_FW (0x02) #define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) +#define MPI3_DIAG_BUFFER_ACTION_PAUSE (0x02) +#define MPI3_DIAG_BUFFER_ACTION_RESUME (0x03) +#define MPI3_DIAG_BUFFER_ACTION_CLEAR (0x04) + +#define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01) struct mpi3_diag_buffer_post_request { __le16 host_tag; u8 ioc_use_only02; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h index b2ab25a1cfeb..290a1f5c2924 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TRANSPORT_H #define MPI30_TRANSPORT_H 1 @@ -18,7 +18,7 @@ union mpi3_version_union { #define MPI3_VERSION_MAJOR (3) #define MPI3_VERSION_MINOR (0) -#define MPI3_VERSION_UNIT (34) +#define MPI3_VERSION_UNIT (39) #define MPI3_VERSION_DEV (0) #define MPI3_DEVHANDLE_INVALID (0xffff) struct mpi3_sysif_oper_queue_indexes { @@ -80,6 +80,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20) #define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ (0x000f0000) #define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT (16) +#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_SHIFT (14) #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000c000) #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000) #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000) @@ -97,6 +98,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_IOC_STATUS_READY (0x00000001) #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET (0x00000024) #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_MASK (0x0fff) +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_SHIFT (0) #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_OFFSET (0x00000026) #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_MASK (0x0fff0000) #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_SHIFT (16) @@ -106,6 +108,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_HIGH_OFFSET (0x00000034) #define MPI3_SYSIF_COALESCE_CONTROL_OFFSET (0x00000040) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_MASK (0xc0000000) +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_SHIFT (30) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xc0000000) @@ -124,6 +127,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(N) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((N) - 1) * 8)) #define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001c04) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000f) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_SHIFT (0) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST (0xf) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND (0x4) @@ -133,6 +137,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH (0xd) #define MPI3_SYSIF_HOST_DIAG_OFFSET (0x00001c08) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SHIFT (8) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_HOST_CONTROL_BOOT_RESET (0x00000200) @@ -151,6 +156,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_FAULT_FUNC_AREA_SHIFT (24) #define MPI3_SYSIF_FAULT_FUNC_AREA_MPI_DEFINED (0x00000000) #define MPI3_SYSIF_FAULT_CODE_MASK (0x0000ffff) +#define MPI3_SYSIF_FAULT_CODE_SHIFT (0) #define MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET (0x0000f000) #define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000f001) #define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000f002) @@ -176,17 +182,20 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00001c5c) #define MPI3_SYSIF_DIAG_RW_CONTROL_OFFSET (0x00001c60) #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_MASK (0x00000030) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_SHIFT (4) #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_1BYTE (0x00000000) #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_2BYTES (0x00000010) #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_4BYTES (0x00000020) #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_8BYTES (0x00000030) #define MPI3_SYSIF_DIAG_RW_CONTROL_RESET (0x00000004) #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_MASK (0x00000002) +#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_SHIFT (1) #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_READ (0x00000000) #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_WRITE (0x00000002) #define MPI3_SYSIF_DIAG_RW_CONTROL_START (0x00000001) #define MPI3_SYSIF_DIAG_RW_STATUS_OFFSET (0x00001c62) #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_MASK (0x0000000e) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SHIFT (1) #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SUCCESS (0x00000000) #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_INV_ADDR (0x00000002) #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_ACC_ERR (0x00000004) @@ -207,7 +216,9 @@ struct mpi3_default_reply_descriptor { }; #define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK (0x0001) +#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_SHIFT (0) #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK (0xf000) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SHIFT (12) #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY (0x0000) #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS (0x1000) #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_TARGET_COMMAND_BUFFER (0x2000) @@ -301,6 +312,7 @@ union mpi3_sge_union { }; #define MPI3_SGE_FLAGS_ELEMENT_TYPE_MASK (0xf0) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SHIFT (4) #define MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE (0x00) #define MPI3_SGE_FLAGS_ELEMENT_TYPE_BIT_BUCKET (0x10) #define MPI3_SGE_FLAGS_ELEMENT_TYPE_CHAIN (0x20) @@ -309,6 +321,7 @@ union mpi3_sge_union { #define MPI3_SGE_FLAGS_END_OF_LIST (0x08) #define MPI3_SGE_FLAGS_END_OF_BUFFER (0x04) #define MPI3_SGE_FLAGS_DLAS_MASK (0x03) +#define MPI3_SGE_FLAGS_DLAS_SHIFT (0) #define MPI3_SGE_FLAGS_DLAS_SYSTEM (0x00) #define MPI3_SGE_FLAGS_DLAS_IOC_UDP (0x01) #define MPI3_SGE_FLAGS_DLAS_IOC_CTL (0x02) @@ -322,15 +335,18 @@ union mpi3_sge_union { #define MPI3_EEDPFLAGS_CHK_APP_TAG (0x0200) #define MPI3_EEDPFLAGS_CHK_GUARD (0x0100) #define MPI3_EEDPFLAGS_ESC_MODE_MASK (0x00c0) +#define MPI3_EEDPFLAGS_ESC_MODE_SHIFT (6) #define MPI3_EEDPFLAGS_ESC_MODE_DO_NOT_DISABLE (0x0040) #define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE (0x0080) #define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_REFTAG_DISABLE (0x00c0) #define MPI3_EEDPFLAGS_HOST_GUARD_MASK (0x0030) +#define MPI3_EEDPFLAGS_HOST_GUARD_SHIFT (4) #define MPI3_EEDPFLAGS_HOST_GUARD_T10_CRC (0x0000) #define MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM (0x0010) #define MPI3_EEDPFLAGS_HOST_GUARD_OEM_SPECIFIC (0x0020) #define MPI3_EEDPFLAGS_PT_REF_TAG (0x0008) #define MPI3_EEDPFLAGS_EEDP_OP_MASK (0x0007) +#define MPI3_EEDPFLAGS_EEDP_OP_SHIFT (0) #define MPI3_EEDPFLAGS_EEDP_OP_CHECK (0x0001) #define MPI3_EEDPFLAGS_EEDP_OP_STRIP (0x0002) #define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE (0x0003) @@ -403,6 +419,7 @@ struct mpi3_default_reply { #define MPI3_IOCSTATUS_LOG_INFO_AVAIL_MASK (0x8000) #define MPI3_IOCSTATUS_LOG_INFO_AVAILABLE (0x8000) #define MPI3_IOCSTATUS_STATUS_MASK (0x7fff) +#define MPI3_IOCSTATUS_STATUS_SHIFT (0) #define MPI3_IOCSTATUS_SUCCESS (0x0000) #define MPI3_IOCSTATUS_INVALID_FUNCTION (0x0001) #define MPI3_IOCSTATUS_BUSY (0x0002) @@ -469,4 +486,5 @@ struct mpi3_default_reply { #define MPI3_IOCLOGINFO_TYPE_NONE (0x0) #define MPI3_IOCLOGINFO_TYPE_SAS (0x3) #define MPI3_IOCLOGINFO_LOG_DATA_MASK (0x0fffffff) +#define MPI3_IOCLOGINFO_LOG_DATA_SHIFT (0) #endif diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 0d72b5f1b69d..c25525fe0671 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.12.0.3.50" -#define MPI3MR_DRIVER_RELDATE "11-November-2024" +#define MPI3MR_DRIVER_VERSION "8.17.0.3.50" +#define MPI3MR_DRIVER_RELDATE "09-January-2026" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" @@ -80,13 +80,14 @@ extern atomic64_t event_counter; /* Admin queue management definitions */ #define MPI3MR_ADMIN_REQ_Q_SIZE (2 * MPI3MR_PAGE_SIZE_4K) -#define MPI3MR_ADMIN_REPLY_Q_SIZE (4 * MPI3MR_PAGE_SIZE_4K) +#define MPI3MR_ADMIN_REPLY_Q_SIZE (8 * MPI3MR_PAGE_SIZE_4K) #define MPI3MR_ADMIN_REQ_FRAME_SZ 128 #define MPI3MR_ADMIN_REPLY_FRAME_SZ 16 /* Operational queue management definitions */ #define MPI3MR_OP_REQ_Q_QD 512 #define MPI3MR_OP_REP_Q_QD 1024 +#define MPI3MR_OP_REP_Q_QD2K 2048 #define MPI3MR_OP_REP_Q_QD4K 4096 #define MPI3MR_OP_REQ_Q_SEG_SIZE 4096 #define MPI3MR_OP_REP_Q_SEG_SIZE 4096 @@ -158,6 +159,7 @@ extern atomic64_t event_counter; /* Controller Reset related definitions */ #define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT 5 #define MPI3MR_MAX_RESET_RETRY_COUNT 3 +#define MPI3MR_MAX_SHUTDOWN_RETRY_COUNT 2 /* ResponseCode definitions */ #define MPI3MR_RI_MASK_RESPCODE (0x000000FF) @@ -322,12 +324,14 @@ enum mpi3mr_reset_reason { MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29, MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30, MPI3MR_RESET_FROM_TRIGGER = 31, + MPI3MR_RESET_FROM_INVALID_COMPLETION = 32, }; #define MPI3MR_RESET_REASON_OSTYPE_LINUX 1 #define MPI3MR_RESET_REASON_OSTYPE_SHIFT 28 #define MPI3MR_RESET_REASON_IOCNUM_SHIFT 20 + /* Queue type definitions */ enum queue_type { MPI3MR_DEFAULT_QUEUE = 0, @@ -387,6 +391,7 @@ struct mpi3mr_ioc_facts { u16 max_msix_vectors; u8 personality; u8 dma_mask; + bool max_req_limit; u8 protocol_flags; u8 sge_mod_mask; u8 sge_mod_value; @@ -425,6 +430,14 @@ struct segments { * @q_segments: Segment descriptor pointer * @q_segment_list: Segment list base virtual address * @q_segment_list_dma: Segment list base DMA address + * @last_full_host_tag: Hosttag of last IO returned to SML + * due to queue full + * @qfull_io_count: Number of IOs returned back to SML + * due to queue full + * @qfull_instances: Total queue full occurrences.One occurrence + * starts with queue full detection and ends + * with queue full breaks. + * */ struct op_req_qinfo { u16 ci; @@ -438,6 +451,10 @@ struct op_req_qinfo { struct segments *q_segments; void *q_segment_list; dma_addr_t q_segment_list_dma; + u16 last_full_host_tag; + u64 qfull_io_count; + u32 qfull_instances; + }; /** @@ -456,6 +473,8 @@ struct op_req_qinfo { * @enable_irq_poll: Flag to indicate polling is enabled * @in_use: Queue is handled by poll/ISR * @qtype: Type of queue (types defined in enum queue_type) + * @qfull_watermark: Watermark defined in reply queue to avoid + * reply queue full */ struct op_reply_qinfo { u16 ci; @@ -471,6 +490,7 @@ struct op_reply_qinfo { bool enable_irq_poll; atomic_t in_use; enum queue_type qtype; + u16 qfull_watermark; }; /** @@ -637,6 +657,7 @@ struct mpi3mr_enclosure_node { * @dev_info: Device information bits * @phy_id: Phy identifier provided in device page 0 * @attached_phy_id: Attached phy identifier provided in device page 0 + * @negotiated_link_rate: Negotiated link rate from device page 0 * @sas_transport_attached: Is this device exposed to transport * @pend_sas_rphy_add: Flag to check device is in process of add * @hba_port: HBA port entry @@ -648,6 +669,7 @@ struct tgt_dev_sas_sata { u16 dev_info; u8 phy_id; u8 attached_phy_id; + u8 negotiated_link_rate; u8 sas_transport_attached; u8 pend_sas_rphy_add; struct mpi3mr_hba_port *hba_port; @@ -691,6 +713,8 @@ struct tgt_dev_vd { u16 tg_id; u32 tg_high; u32 tg_low; + u8 abort_to; + u8 reset_to; struct mpi3mr_throttle_group_info *tg; }; @@ -732,6 +756,8 @@ enum mpi3mr_dev_state { * @wwid: World wide ID * @enclosure_logical_id: Enclosure logical identifier * @dev_spec: Device type specific information + * @abort_to: Timeout for abort TM + * @reset_to: Timeout for Target/LUN reset TM * @ref_count: Reference count * @state: device state */ @@ -928,6 +954,8 @@ struct trigger_event_data { * @size: Buffer size * @addr: Virtual address * @dma_addr: Buffer DMA address + * @is_segmented: The buffer is segmented or not + * @disabled_after_reset: The buffer is disabled after reset */ struct diag_buffer_desc { u8 type; @@ -937,6 +965,8 @@ struct diag_buffer_desc { u32 size; void *addr; dma_addr_t dma_addr; + bool is_segmented; + bool disabled_after_reset; }; /** @@ -1022,6 +1052,8 @@ struct scmd_priv { * @admin_reply_base: Admin reply queue base virtual address * @admin_reply_dma: Admin reply queue base dma address * @admin_reply_q_in_use: Queue is handled by poll/ISR + * @admin_pend_isr: Count of unprocessed admin ISR/poll calls + * due to another thread processing replies * @ready_timeout: Controller ready timeout * @intr_info: Interrupt cookie pointer * @intr_info_count: Number of interrupt cookies @@ -1060,7 +1092,6 @@ struct scmd_priv { * @fwevt_worker_thread: Firmware event worker thread * @fwevt_lock: Firmware event lock * @fwevt_list: Firmware event list - * @watchdog_work_q_name: Fault watchdog worker thread name * @watchdog_work_q: Fault watchdog worker thread * @watchdog_work: Fault watchdog work * @watchdog_lock: Fault watchdog lock @@ -1090,6 +1121,7 @@ struct scmd_priv { * @ts_update_interval: Timestamp update interval * @reset_in_progress: Reset in progress flag * @unrecoverable: Controller unrecoverable flag + * @io_admin_reset_sync: Manage state of I/O ops during an admin reset process * @prev_reset_result: Result of previous reset * @reset_mutex: Controller reset mutex * @reset_waitq: Controller reset wait queue @@ -1118,12 +1150,18 @@ struct scmd_priv { * @default_qcount: Total Default queues * @active_poll_qcount: Currently active poll queue count * @requested_poll_qcount: User requested poll queue count + * @fault_during_init: Indicates a firmware fault occurred during initialization + * @saved_fault_code: Firmware fault code captured at the time of failure + * @saved_fault_info: Additional firmware-provided fault information + * @fwfault_counter: Count of firmware faults detected by the driver * @bsg_dev: BSG device structure * @bsg_queue: Request queue for BSG device * @stop_bsgs: Stop BSG request flag * @logdata_buf: Circular buffer to store log data entries * @logdata_buf_idx: Index of entry in buffer to store * @logdata_entry_sz: log data entry size + * @adm_req_q_bar_writeq_lock: Admin request queue lock + * @adm_reply_q_bar_writeq_lock: Admin reply queue lock * @pend_large_data_sz: Counter to track pending large data * @io_throttle_data_length: I/O size to track in 512b blocks * @io_throttle_high: I/O size to start throttle in 512b blocks @@ -1153,6 +1191,13 @@ struct scmd_priv { * @snapdump_trigger_active: Snapdump trigger active flag * @pci_err_recovery: PCI error recovery in progress * @block_on_pci_err: Block IO during PCI error recovery + * @reply_qfull_count: Occurences of reply queue full avoidance kicking-in + * @prevent_reply_qfull: Enable reply queue prevention + * @seg_tb_support: Segmented trace buffer support + * @num_tb_segs: Number of Segments in Trace buffer + * @trace_buf_pool: DMA pool for Segmented trace buffer segments + * @trace_buf: Trace buffer segments memory descriptor + * @invalid_io_comp: Invalid IO completion */ struct mpi3mr_ioc { struct list_head list; @@ -1166,7 +1211,7 @@ struct mpi3mr_ioc { char name[MPI3MR_NAME_LENGTH]; char driver_name[MPI3MR_NAME_LENGTH]; - volatile struct mpi3_sysif_registers __iomem *sysif_regs; + struct mpi3_sysif_registers __iomem *sysif_regs; resource_size_t sysif_regs_phys; int bars; u64 dma_mask; @@ -1189,6 +1234,7 @@ struct mpi3mr_ioc { void *admin_reply_base; dma_addr_t admin_reply_dma; atomic_t admin_reply_q_in_use; + atomic_t admin_pend_isr; u32 ready_timeout; @@ -1239,7 +1285,6 @@ struct mpi3mr_ioc { spinlock_t fwevt_lock; struct list_head fwevt_list; - char watchdog_work_q_name[50]; struct workqueue_struct *watchdog_work_q; struct delayed_work watchdog_work; spinlock_t watchdog_lock; @@ -1276,6 +1321,7 @@ struct mpi3mr_ioc { u16 ts_update_interval; u8 reset_in_progress; u8 unrecoverable; + u8 io_admin_reset_sync; int prev_reset_result; struct mutex reset_mutex; wait_queue_head_t reset_waitq; @@ -1311,6 +1357,10 @@ struct mpi3mr_ioc { u16 default_qcount; u16 active_poll_qcount; u16 requested_poll_qcount; + u8 fault_during_init; + u32 saved_fault_code; + u32 saved_fault_info[3]; + u64 fwfault_counter; struct device bsg_dev; struct request_queue *bsg_queue; @@ -1318,6 +1368,8 @@ struct mpi3mr_ioc { u8 *logdata_buf; u16 logdata_buf_idx; u16 logdata_entry_sz; + spinlock_t adm_req_q_bar_writeq_lock; + spinlock_t adm_reply_q_bar_writeq_lock; atomic_t pend_large_data_sz; u32 io_throttle_data_length; @@ -1351,6 +1403,14 @@ struct mpi3mr_ioc { bool fw_release_trigger_active; bool pci_err_recovery; bool block_on_pci_err; + atomic_t reply_qfull_count; + bool prevent_reply_qfull; + bool seg_tb_support; + u32 num_tb_segs; + struct dma_pool *trace_buf_pool; + struct segments *trace_buf; + u8 invalid_io_comp; + }; /** @@ -1472,7 +1532,7 @@ void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size); struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle( struct mpi3mr_ioc *mrioc, u16 handle); diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 7589f48aebc8..1353a8ff9c85 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -12,23 +12,98 @@ #include <uapi/scsi/scsi_bsg_mpi3mr.h> /** - * mpi3mr_alloc_trace_buffer: Allocate trace buffer + * mpi3mr_alloc_trace_buffer: Allocate segmented trace buffer * @mrioc: Adapter instance reference * @trace_size: Trace buffer size * - * Allocate trace buffer + * Allocate either segmented memory pools or contiguous buffer + * based on the controller capability for the host trace + * buffer. + * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_alloc_trace_buffer(struct mpi3mr_ioc *mrioc, u32 trace_size) { struct diag_buffer_desc *diag_buffer = &mrioc->diag_buffers[0]; + int i, sz; + u64 *diag_buffer_list = NULL; + dma_addr_t diag_buffer_list_dma; + u32 seg_count; + + if (mrioc->seg_tb_support) { + seg_count = (trace_size) / MPI3MR_PAGE_SIZE_4K; + trace_size = seg_count * MPI3MR_PAGE_SIZE_4K; + + diag_buffer_list = dma_alloc_coherent(&mrioc->pdev->dev, + sizeof(u64) * seg_count, + &diag_buffer_list_dma, GFP_KERNEL); + if (!diag_buffer_list) + return -1; + + mrioc->num_tb_segs = seg_count; + + sz = sizeof(struct segments) * seg_count; + mrioc->trace_buf = kzalloc(sz, GFP_KERNEL); + if (!mrioc->trace_buf) + goto trace_buf_failed; + + mrioc->trace_buf_pool = dma_pool_create("trace_buf pool", + &mrioc->pdev->dev, MPI3MR_PAGE_SIZE_4K, MPI3MR_PAGE_SIZE_4K, + 0); + if (!mrioc->trace_buf_pool) { + ioc_err(mrioc, "trace buf pool: dma_pool_create failed\n"); + goto trace_buf_pool_failed; + } + + for (i = 0; i < seg_count; i++) { + mrioc->trace_buf[i].segment = + dma_pool_zalloc(mrioc->trace_buf_pool, GFP_KERNEL, + &mrioc->trace_buf[i].segment_dma); + diag_buffer_list[i] = + (u64) mrioc->trace_buf[i].segment_dma; + if (!diag_buffer_list[i]) + goto tb_seg_alloc_failed; + } - diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, - trace_size, &diag_buffer->dma_addr, GFP_KERNEL); - if (diag_buffer->addr) { - dprint_init(mrioc, "trace diag buffer is allocated successfully\n"); + diag_buffer->addr = diag_buffer_list; + diag_buffer->dma_addr = diag_buffer_list_dma; + diag_buffer->is_segmented = true; + + dprint_init(mrioc, "segmented trace diag buffer\n" + "is allocated successfully seg_count:%d\n", seg_count); return 0; + } else { + diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, + trace_size, &diag_buffer->dma_addr, GFP_KERNEL); + if (diag_buffer->addr) { + dprint_init(mrioc, "trace diag buffer is allocated successfully\n"); + return 0; + } + return -1; } + +tb_seg_alloc_failed: + if (mrioc->trace_buf_pool) { + for (i = 0; i < mrioc->num_tb_segs; i++) { + if (mrioc->trace_buf[i].segment) { + dma_pool_free(mrioc->trace_buf_pool, + mrioc->trace_buf[i].segment, + mrioc->trace_buf[i].segment_dma); + mrioc->trace_buf[i].segment = NULL; + } + mrioc->trace_buf[i].segment = NULL; + } + dma_pool_destroy(mrioc->trace_buf_pool); + mrioc->trace_buf_pool = NULL; + } +trace_buf_pool_failed: + kfree(mrioc->trace_buf); + mrioc->trace_buf = NULL; +trace_buf_failed: + if (diag_buffer_list) + dma_free_coherent(&mrioc->pdev->dev, + sizeof(u64) * mrioc->num_tb_segs, + diag_buffer_list, diag_buffer_list_dma); return -1; } @@ -100,8 +175,9 @@ retry_trace: dprint_init(mrioc, "trying to allocate trace diag buffer of size = %dKB\n", trace_size / 1024); - if (get_order(trace_size) > MAX_PAGE_ORDER || + if ((!mrioc->seg_tb_support && (get_order(trace_size) > MAX_PAGE_ORDER)) || mpi3mr_alloc_trace_buffer(mrioc, trace_size)) { + retry = true; trace_size -= trace_dec_size; dprint_init(mrioc, "trace diag buffer allocation failed\n" @@ -161,6 +237,12 @@ int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, u8 prev_status; int retval = 0; + if (diag_buffer->disabled_after_reset) { + dprint_bsg_err(mrioc, "%s: skipping diag buffer posting\n" + "as it is disabled after reset\n", __func__); + return -1; + } + memset(&diag_buf_post_req, 0, sizeof(diag_buf_post_req)); mutex_lock(&mrioc->init_cmds.mutex); if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { @@ -177,8 +259,12 @@ int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, diag_buf_post_req.address = le64_to_cpu(diag_buffer->dma_addr); diag_buf_post_req.length = le32_to_cpu(diag_buffer->size); - dprint_bsg_info(mrioc, "%s: posting diag buffer type %d\n", __func__, - diag_buffer->type); + if (diag_buffer->is_segmented) + diag_buf_post_req.msg_flags |= MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED; + + dprint_bsg_info(mrioc, "%s: posting diag buffer type %d segmented:%d\n", __func__, + diag_buffer->type, diag_buffer->is_segmented); + prev_status = diag_buffer->status; diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED; init_completion(&mrioc->init_cmds.done); @@ -709,9 +795,8 @@ void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action) * * @hdb: HDB pointer * @type: Trigger type - * @data: Trigger data - * @force: Trigger overwrite flag * @trigger_data: Pointer to trigger data information + * @force: Trigger overwrite flag * * Updates trigger type and trigger data based on parameter * passed to this function @@ -736,9 +821,8 @@ void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb, * * @mrioc: Adapter instance reference * @type: Trigger type - * @data: Trigger data - * @force: Trigger overwrite flag * @trigger_data: Pointer to trigger data information + * @force: Trigger overwrite flag * * Updates trigger type and trigger data based on parameter * passed to this function @@ -2339,6 +2423,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) } if (!mrioc->ioctl_sges_allocated) { + mutex_unlock(&mrioc->bsg_cmds.mutex); dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", __func__); return -ENOMEM; @@ -2835,7 +2920,7 @@ out: } /** - * mpi3mr_app_save_logdata - Save Log Data events + * mpi3mr_app_save_logdata_th - Save Log Data events * @mrioc: Adapter instance reference * @event_data: event data associated with log data event * @event_data_size: event data size to copy @@ -2847,7 +2932,7 @@ out: * * Return:Nothing */ -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size) { u32 index = mrioc->logdata_buf_idx, sz; @@ -3061,6 +3146,29 @@ reply_queue_count_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(reply_queue_count); /** + * reply_qfull_count_show - Show reply qfull count + * @dev: class device + * @attr: Device attributes + * @buf: Buffer to copy + * + * Retrieves the current value of the reply_qfull_count from the mrioc structure and + * formats it as a string for display. + * + * Return: sysfs_emit() return + */ +static ssize_t +reply_qfull_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct mpi3mr_ioc *mrioc = shost_priv(shost); + + return sysfs_emit(buf, "%u\n", atomic_read(&mrioc->reply_qfull_count)); +} + +static DEVICE_ATTR_RO(reply_qfull_count); + +/** * logging_level_show - Show controller debug level * @dev: class device * @attr: Device attributes @@ -3147,13 +3255,38 @@ adp_state_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(adp_state); +/** + * fwfault_count_show() - SysFS callback to show firmware fault count + * @dev: class device + * @attr: Device attribute + * @buf: Buffer to copy data into + * + * Displays the total number of firmware faults detected by the driver + * since the controller was initialized. + * + * Return: Number of bytes written to @buf + */ + +static ssize_t +fwfault_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct mpi3mr_ioc *mrioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%llu\n", mrioc->fwfault_counter); +} +static DEVICE_ATTR_RO(fwfault_count); + static struct attribute *mpi3mr_host_attrs[] = { &dev_attr_version_fw.attr, &dev_attr_fw_queue_depth.attr, &dev_attr_op_req_q_count.attr, &dev_attr_reply_queue_count.attr, + &dev_attr_reply_qfull_count.attr, &dev_attr_logging_level.attr, &dev_attr_adp_state.attr, + &dev_attr_fwfault_count.attr, NULL, }; @@ -3277,6 +3410,8 @@ static DEVICE_ATTR_RO(persistent_id); * @buf: the buffer returned * * A sysfs 'read-only' sdev attribute, only works with SATA devices + * + * Returns: the number of characters written to @buf */ static ssize_t sas_ncq_prio_supported_show(struct device *dev, @@ -3295,6 +3430,8 @@ static DEVICE_ATTR_RO(sas_ncq_prio_supported); * @buf: the buffer returned * * A sysfs 'read/write' sdev attribute, only works with SATA devices + * + * Returns: the number of characters written to @buf */ static ssize_t sas_ncq_prio_enable_show(struct device *dev, diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 5ed31fe57474..31b19ed1528e 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -17,23 +17,32 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data); static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); - +static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc); static int poll_queues; module_param(poll_queues, int, 0444); MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); +static bool threaded_isr_poll = true; +module_param(threaded_isr_poll, bool, 0444); +MODULE_PARM_DESC(threaded_isr_poll, + "Enablement of IRQ polling thread (default=true)"); #if defined(writeq) && defined(CONFIG_64BIT) -static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) +static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, + spinlock_t *write_queue_lock) { writeq(b, addr); } #else -static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) +static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, + spinlock_t *write_queue_lock) { __u64 data_out = b; + unsigned long flags; + spin_lock_irqsave(write_queue_lock, flags); writel((u32)(data_out), addr); writel((u32)(data_out >> 32), (addr + 4)); + spin_unlock_irqrestore(write_queue_lock, flags); } #endif @@ -174,6 +183,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, char *desc = NULL; u16 event; + if (!(mrioc->logging_level & MPI3_DEBUG_EVENT)) + return; + event = event_reply->event; switch (event) { @@ -425,8 +437,8 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, MPI3MR_SENSE_BUF_SZ); } if (cmdptr->is_waiting) { - complete(&cmdptr->done); cmdptr->is_waiting = 0; + complete(&cmdptr->done); } else if (cmdptr->callback) cmdptr->callback(mrioc, cmdptr); } @@ -446,9 +458,12 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) u16 threshold_comps = 0; struct mpi3_default_reply_descriptor *reply_desc; - if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) + if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) { + atomic_inc(&mrioc->admin_pend_isr); return 0; + } + atomic_set(&mrioc->admin_pend_isr, 0); reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + admin_reply_ci; @@ -459,7 +474,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) } do { - if (mrioc->unrecoverable) + if (mrioc->unrecoverable || mrioc->io_admin_reset_sync) break; mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); @@ -554,7 +569,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, } do { - if (mrioc->unrecoverable) + if (mrioc->unrecoverable || mrioc->io_admin_reset_sync) break; req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; @@ -563,7 +578,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci)); mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma, reply_qidx); - atomic_dec(&op_reply_q->pend_ios); + if (reply_dma) mpi3mr_repost_reply_buf(mrioc, reply_dma); num_op_reply++; @@ -584,7 +599,8 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, * Exit completion loop to avoid CPU lockup * Ensure remaining completion happens from threaded ISR. */ - if (num_op_reply > mrioc->max_host_ios) { + if ((num_op_reply > mrioc->max_host_ios) && + (threaded_isr_poll == true)) { op_reply_q->enable_irq_poll = true; break; } @@ -681,7 +697,7 @@ static irqreturn_t mpi3mr_isr(int irq, void *privdata) * If more IOs are expected, schedule IRQ polling thread. * Otherwise exit from ISR. */ - if (!intr_info->op_reply_q) + if ((threaded_isr_poll == false) || !intr_info->op_reply_q) return ret; if (!intr_info->op_reply_q->enable_irq_poll || @@ -760,8 +776,8 @@ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) intr_info->msix_index = index; intr_info->op_reply_q = NULL; - snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", - mrioc->driver_name, mrioc->id, index); + scnprintf(intr_info->name, MPI3MR_NAME_LENGTH, + "%.32s%d-msix%u", mrioc->driver_name, mrioc->id, index); #ifndef CONFIG_PREEMPT_RT retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, @@ -980,6 +996,7 @@ static const struct { { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" }, { MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"}, { MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" }, + { MPI3MR_RESET_FROM_INVALID_COMPLETION, "invalid cmd completion" }, }; /** @@ -1093,6 +1110,31 @@ void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) } /** + * mpi3mr_save_fault_info - Save fault information + * @mrioc: Adapter instance reference + * + * Save the controller fault information if there is a + * controller fault. + * + * Return: Nothing. + */ +static void mpi3mr_save_fault_info(struct mpi3mr_ioc *mrioc) +{ + u32 ioc_status, i; + + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + mrioc->saved_fault_code = readl(&mrioc->sysif_regs->fault) & + MPI3_SYSIF_FAULT_CODE_MASK; + for (i = 0; i < 3; i++) { + mrioc->saved_fault_info[i] = + readl(&mrioc->sysif_regs->fault_info[i]); + } + } +} + +/** * mpi3mr_get_iocstate - Get IOC State * @mrioc: Adapter instance reference * @@ -1234,6 +1276,60 @@ out_failed: } /** + * mpi3mr_fault_uevent_emit - Emit uevent for any controller + * fault + * @mrioc: Pointer to the mpi3mr_ioc structure for the controller instance + * + * This function is invoked when the controller undergoes any + * type of fault. + */ + +static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc) +{ + struct kobj_uevent_env *env; + int ret; + + env = kzalloc_obj(*env); + if (!env) + return; + + ret = add_uevent_var(env, "DRIVER=%s", mrioc->driver_name); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "IOC_ID=%u", mrioc->id); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_CODE=0x%08x", + mrioc->saved_fault_code); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO0=0x%08x", + mrioc->saved_fault_info[0]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO1=0x%08x", + mrioc->saved_fault_info[1]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO2=0x%08x", + mrioc->saved_fault_info[2]); + if (ret) + goto out_free; + + kobject_uevent_env(&mrioc->shost->shost_gendev.kobj, + KOBJ_CHANGE, env->envp); + +out_free: + kfree(env); + +} + +/** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference * @@ -1302,7 +1398,7 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) retval = 0; - ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", + ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%08x)/(0x%08x)\n", (!retval) ? "successful" : "failed", ioc_status, ioc_config); return retval; } @@ -1355,6 +1451,19 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) "\tcontroller while sas transport support is enabled at the\n" "\tdriver, please reboot the system or reload the driver\n"); + if (mrioc->seg_tb_support) { + if (!(mrioc->facts.ioc_capabilities & + MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED)) { + ioc_err(mrioc, + "critical error: previously enabled segmented trace\n" + " buffer capability is disabled after reset. Please\n" + " update the firmware or reboot the system or\n" + " reload the driver to enable trace diag buffer\n"); + mrioc->diag_buffers[0].disabled_after_reset = true; + } else + mrioc->diag_buffers[0].disabled_after_reset = false; + } + if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) { removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle, GFP_KERNEL); @@ -1451,6 +1560,10 @@ retry_bring_ioc_ready: if (ioc_state == MRIOC_STATE_FAULT) { timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; + do { host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); @@ -1506,6 +1619,7 @@ retry_bring_ioc_ready: ioc_info(mrioc, "successfully transitioned to %s state\n", mpi3mr_iocstate_name(ioc_state)); + mpi3mr_clear_reset_history(mrioc); return 0; } ioc_status = readl(&mrioc->sysif_regs->ioc_status); @@ -1525,6 +1639,15 @@ retry_bring_ioc_ready: elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000; } while (elapsed_time_sec < mrioc->ready_timeout); + ioc_state = mpi3mr_get_iocstate(mrioc); + if (ioc_state == MRIOC_STATE_READY) { + ioc_info(mrioc, + "successfully transitioned to %s state after %llu seconds\n", + mpi3mr_iocstate_name(ioc_state), elapsed_time_sec); + mpi3mr_clear_reset_history(mrioc); + return 0; + } + out_failed: elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000; if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) { @@ -1677,7 +1800,9 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX << MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num << MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason); - writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); + writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]); + if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) + mpi3mr_set_diagsave(mrioc); writel(host_diagnostic | reset_type, &mrioc->sysif_regs->host_diagnostic); switch (reset_type) { @@ -1717,7 +1842,7 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); ioc_status = readl(&mrioc->sysif_regs->ioc_status); ioc_info(mrioc, - "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", + "ioc_status/ioc_config after %s reset is (0x%08x)/(0x%08x)\n", (!retval)?"successful":"failed", ioc_status, ioc_config); if (retval) @@ -1996,8 +2121,8 @@ static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies, op_reply_q->segment_qd); - op_reply_q->q_segments = kcalloc(op_reply_q->num_segments, - sizeof(struct segments), GFP_KERNEL); + op_reply_q->q_segments = kzalloc_objs(struct segments, + op_reply_q->num_segments); if (!op_reply_q->q_segments) return -ENOMEM; @@ -2054,8 +2179,8 @@ static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests, op_req_q->segment_qd); - op_req_q->q_segments = kcalloc(op_req_q->num_segments, - sizeof(struct segments), GFP_KERNEL); + op_req_q->q_segments = kzalloc_objs(struct segments, + op_req_q->num_segments); if (!op_req_q->q_segments) return -ENOMEM; @@ -2104,15 +2229,22 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) } reply_qid = qidx + 1; - op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; - if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && - !mrioc->pdev->revision) - op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; + + if (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) { + if (mrioc->pdev->revision) + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; + else + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; + } else + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD2K; + op_reply_q->ci = 0; op_reply_q->ephase = 1; atomic_set(&op_reply_q->pend_ios, 0); atomic_set(&op_reply_q->in_use, 0); op_reply_q->enable_irq_poll = false; + op_reply_q->qfull_watermark = + op_reply_q->num_replies - (MPI3MR_THRESHOLD_REPLY_COUNT * 2); if (!op_reply_q->q_segments) { retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); @@ -2240,6 +2372,9 @@ static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, op_req_q->ci = 0; op_req_q->pi = 0; op_req_q->reply_qid = reply_qid; + op_req_q->last_full_host_tag = MPI3MR_HOSTTAG_INVALID; + op_req_q->qfull_io_count = 0; + op_req_q->qfull_instances = 0; spin_lock_init(&op_req_q->q_lock); if (!op_req_q->q_segments) { @@ -2322,6 +2457,8 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) { int retval = 0; u16 num_queues = 0, i = 0, msix_count_op_q = 1; + u32 ioc_status; + enum mpi3mr_iocstate ioc_state; num_queues = min_t(int, mrioc->facts.max_op_reply_q, mrioc->facts.max_op_req_q); @@ -2340,8 +2477,7 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) num_queues); if (!mrioc->req_qinfo) { - mrioc->req_qinfo = kcalloc(num_queues, - sizeof(struct op_req_qinfo), GFP_KERNEL); + mrioc->req_qinfo = kzalloc_objs(struct op_req_qinfo, num_queues); if (!mrioc->req_qinfo) { retval = -1; goto out_failed; @@ -2377,6 +2513,14 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) retval = -1; goto out_failed; } + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + ioc_state = mpi3mr_get_iocstate(mrioc); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || + ioc_state != MRIOC_STATE_READY) { + mpi3mr_print_fault_info(mrioc); + retval = -1; + goto out_failed; + } mrioc->num_op_reply_q = mrioc->num_op_req_q = i; ioc_info(mrioc, "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n", @@ -2416,8 +2560,12 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, void *segment_base_addr; u16 req_sz = mrioc->facts.op_req_sz; struct segments *segments = op_req_q->q_segments; + struct op_reply_qinfo *op_reply_q = NULL; + struct mpi3_scsi_io_request *scsiio_req = + (struct mpi3_scsi_io_request *)req; reply_qidx = op_req_q->reply_qid - 1; + op_reply_q = mrioc->op_reply_qinfo + reply_qidx; if (mrioc->unrecoverable) return -EFAULT; @@ -2432,11 +2580,21 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q); if (mpi3mr_check_req_qfull(op_req_q)) { + + if (op_req_q->last_full_host_tag == + MPI3MR_HOSTTAG_INVALID) + op_req_q->qfull_instances++; + + op_req_q->last_full_host_tag = scsiio_req->host_tag; + op_req_q->qfull_io_count++; retval = -EAGAIN; goto out; } } + if (op_req_q->last_full_host_tag != MPI3MR_HOSTTAG_INVALID) + op_req_q->last_full_host_tag = MPI3MR_HOSTTAG_INVALID; + if (mrioc->reset_in_progress) { ioc_err(mrioc, "OpReqQ submit reset in progress\n"); retval = -EAGAIN; @@ -2448,6 +2606,15 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, goto out; } + /* Reply queue is nearing to get full, push back IOs to SML */ + if ((mrioc->prevent_reply_qfull == true) && + (atomic_read(&op_reply_q->pend_ios) > + (op_reply_q->qfull_watermark))) { + atomic_inc(&mrioc->reply_qfull_count); + retval = -EAGAIN; + goto out; + } + segment_base_addr = segments[pi / op_req_q->segment_qd].segment; req_entry = (u8 *)segment_base_addr + ((pi % op_req_q->segment_qd) * req_sz); @@ -2518,6 +2685,9 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; return; } @@ -2535,13 +2705,17 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; } /** * mpi3mr_sync_timestamp - Issue time stamp sync request * @mrioc: Adapter reference * - * Issue IO unit control MPI request to synchornize firmware + * Issue IO unit control MPI request to synchronize firmware * timestamp with host time. * * Return: 0 on success, non-zero on failure. @@ -2711,6 +2885,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work) union mpi3mr_trigger_data trigger_data; u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; + if (mrioc->fault_during_init) { + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fault_during_init = 0; + } + if (mrioc->reset_in_progress || mrioc->pci_err_recovery) return; @@ -2726,7 +2905,21 @@ static void mpi3mr_watchdog_work(struct work_struct *work) return; } - if (mrioc->ts_update_counter++ >= mrioc->ts_update_interval) { + if (mrioc->invalid_io_comp) { + mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_INVALID_COMPLETION, 1); + return; + } + + if (atomic_read(&mrioc->admin_pend_isr)) { + ioc_err(mrioc, "Unprocessed admin ISR instance found\n" + "flush admin replies\n"); + mpi3mr_process_admin_reply_q(mrioc); + } + + if (!(mrioc->facts.ioc_capabilities & + MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) && + (mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) { + mrioc->ts_update_counter = 0; mpi3mr_sync_timestamp(mrioc); } @@ -2774,6 +2967,10 @@ static void mpi3mr_watchdog_work(struct work_struct *work) goto schedule_work; } + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; + switch (trigger_data.fault) { case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: @@ -2817,11 +3014,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) return; INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); - snprintf(mrioc->watchdog_work_q_name, - sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, - mrioc->id); mrioc->watchdog_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name); + "watchdog_%s%d", WQ_MEM_RECLAIM, mrioc->name, mrioc->id); if (!mrioc->watchdog_work_q) { ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; @@ -2883,6 +3077,7 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) mrioc->admin_reply_ci = 0; mrioc->admin_reply_ephase = 1; atomic_set(&mrioc->admin_reply_q_in_use, 0); + atomic_set(&mrioc->admin_pend_isr, 0); if (!mrioc->admin_req_base) { mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev, @@ -2907,9 +3102,11 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) (mrioc->num_admin_req); writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); mpi3mr_writeq(mrioc->admin_req_dma, - &mrioc->sysif_regs->admin_request_queue_address); + &mrioc->sysif_regs->admin_request_queue_address, + &mrioc->adm_req_q_bar_writeq_lock); mpi3mr_writeq(mrioc->admin_reply_dma, - &mrioc->sysif_regs->admin_reply_queue_address); + &mrioc->sysif_regs->admin_reply_queue_address, + &mrioc->adm_reply_q_bar_writeq_lock); writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); return retval; @@ -3091,6 +3288,11 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.dma_mask = (facts_flags & MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + mrioc->facts.dma_mask = (facts_flags & + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + mrioc->facts.max_req_limit = (facts_flags & + MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT); mrioc->facts.protocol_flags = facts_data->protocol_flags; mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); @@ -4214,6 +4416,13 @@ retry_init: mrioc->shost->transportt = mpi3mr_transport_template; } + if (mrioc->facts.max_req_limit) + mrioc->prevent_reply_qfull = true; + + if (mrioc->facts.ioc_capabilities & + MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED) + mrioc->seg_tb_support = true; + mrioc->reply_sz = mrioc->facts.reply_sz; retval = mpi3mr_check_reset_dma_mask(mrioc); @@ -4370,6 +4579,7 @@ retry_init: goto out_failed_noretry; } + mrioc->io_admin_reset_sync = 0; if (is_resume || mrioc->block_on_pci_err) { dprint_reset(mrioc, "setting up single ISR\n"); retval = mpi3mr_setup_isr(mrioc, 1); @@ -4600,6 +4810,7 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) if (mrioc->admin_reply_base) memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); atomic_set(&mrioc->admin_reply_q_in_use, 0); + atomic_set(&mrioc->admin_pend_isr, 0); if (mrioc->init_cmds.reply) { memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); @@ -4627,21 +4838,26 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) } for (i = 0; i < mrioc->num_queues; i++) { - mrioc->op_reply_qinfo[i].qid = 0; - mrioc->op_reply_qinfo[i].ci = 0; - mrioc->op_reply_qinfo[i].num_replies = 0; - mrioc->op_reply_qinfo[i].ephase = 0; - atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); - atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0); - mpi3mr_memset_op_reply_q_buffers(mrioc, i); - - mrioc->req_qinfo[i].ci = 0; - mrioc->req_qinfo[i].pi = 0; - mrioc->req_qinfo[i].num_requests = 0; - mrioc->req_qinfo[i].qid = 0; - mrioc->req_qinfo[i].reply_qid = 0; - spin_lock_init(&mrioc->req_qinfo[i].q_lock); - mpi3mr_memset_op_req_q_buffers(mrioc, i); + if (mrioc->op_reply_qinfo) { + mrioc->op_reply_qinfo[i].qid = 0; + mrioc->op_reply_qinfo[i].ci = 0; + mrioc->op_reply_qinfo[i].num_replies = 0; + mrioc->op_reply_qinfo[i].ephase = 0; + atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); + atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0); + mpi3mr_memset_op_reply_q_buffers(mrioc, i); + } + + if (mrioc->req_qinfo) { + mrioc->req_qinfo[i].ci = 0; + mrioc->req_qinfo[i].pi = 0; + mrioc->req_qinfo[i].num_requests = 0; + mrioc->req_qinfo[i].qid = 0; + mrioc->req_qinfo[i].reply_qid = 0; + spin_lock_init(&mrioc->req_qinfo[i].q_lock); + mrioc->req_qinfo[i].last_full_host_tag = 0; + mpi3mr_memset_op_req_q_buffers(mrioc, i); + } } atomic_set(&mrioc->pend_large_data_sz, 0); @@ -4671,7 +4887,7 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) */ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) { - u16 i; + u16 i, j; struct mpi3mr_intr_info *intr_info; struct diag_buffer_desc *diag_buffer; @@ -4806,6 +5022,26 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { diag_buffer = &mrioc->diag_buffers[i]; + if ((i == 0) && mrioc->seg_tb_support) { + if (mrioc->trace_buf_pool) { + for (j = 0; j < mrioc->num_tb_segs; j++) { + if (mrioc->trace_buf[j].segment) { + dma_pool_free(mrioc->trace_buf_pool, + mrioc->trace_buf[j].segment, + mrioc->trace_buf[j].segment_dma); + mrioc->trace_buf[j].segment = NULL; + } + + mrioc->trace_buf[j].segment = NULL; + } + dma_pool_destroy(mrioc->trace_buf_pool); + mrioc->trace_buf_pool = NULL; + } + + kfree(mrioc->trace_buf); + mrioc->trace_buf = NULL; + diag_buffer->size = sizeof(u64) * mrioc->num_tb_segs; + } if (diag_buffer->addr) { dma_free_coherent(&mrioc->pdev->dev, diag_buffer->size, diag_buffer->addr, @@ -4836,9 +5072,9 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) */ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) { - u32 ioc_config, ioc_status; - u8 retval = 1; - u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; + u32 ioc_config, ioc_status, shutdown_action; + u8 retval = 1, retry = 0; + u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10, timeout_remaining = 0; ioc_info(mrioc, "Issuing shutdown Notification\n"); if (mrioc->unrecoverable) { @@ -4853,14 +5089,16 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) return; } + shutdown_action = MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL | + MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); - ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; - ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; + ioc_config |= shutdown_action; writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); if (mrioc->facts.shutdown_timeout) timeout = mrioc->facts.shutdown_timeout * 10; + timeout_remaining = timeout; do { ioc_status = readl(&mrioc->sysif_regs->ioc_status); @@ -4869,8 +5107,26 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) retval = 0; break; } + if (mrioc->unrecoverable) + break; + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + mpi3mr_print_fault_info(mrioc); + if (retry >= MPI3MR_MAX_SHUTDOWN_RETRY_COUNT) + break; + if (mpi3mr_issue_reset(mrioc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, + MPI3MR_RESET_FROM_CTLR_CLEANUP)) + break; + ioc_config = + readl(&mrioc->sysif_regs->ioc_configuration); + ioc_config |= shutdown_action; + writel(ioc_config, + &mrioc->sysif_regs->ioc_configuration); + timeout_remaining = timeout; + retry++; + } msleep(100); - } while (--timeout); + } while (--timeout_remaining); ioc_status = readl(&mrioc->sysif_regs->ioc_status); ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); @@ -4883,7 +5139,7 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) } ioc_info(mrioc, - "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", + "Base IOC Sts/Config after %s shutdown is (0x%08x)/(0x%08x)\n", (!retval) ? "successful" : "failed", ioc_status, ioc_config); } @@ -5229,6 +5485,55 @@ cleanup_drv_cmd: } /** + * mpi3mr_check_op_admin_proc - + * @mrioc: Adapter instance reference + * + * Check if any of the operation reply queues + * or the admin reply queue are currently in use. + * If any queue is in use, this function waits for + * a maximum of 10 seconds for them to become available. + * + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc) +{ + + u16 timeout = 10 * 10; + u16 elapsed_time = 0; + bool op_admin_in_use = false; + + do { + op_admin_in_use = false; + + /* Check admin_reply queue first to exit early */ + if (atomic_read(&mrioc->admin_reply_q_in_use) == 1) + op_admin_in_use = true; + else { + /* Check op_reply queues */ + int i; + + for (i = 0; i < mrioc->num_queues; i++) { + if (atomic_read(&mrioc->op_reply_qinfo[i].in_use) == 1) { + op_admin_in_use = true; + break; + } + } + } + + if (!op_admin_in_use) + break; + + msleep(100); + + } while (++elapsed_time < timeout); + + if (op_admin_in_use) + return 1; + + return 0; +} + +/** * mpi3mr_soft_reset_handler - Reset the controller * @mrioc: Adapter instance reference * @reset_reason: Reset reason code @@ -5254,6 +5559,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, { int retval = 0, i; unsigned long flags; + enum mpi3mr_iocstate ioc_state; u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; union mpi3mr_trigger_data trigger_data; @@ -5285,6 +5591,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mpi3mr_reset_rc_name(reset_reason)); mrioc->device_refresh_on = 0; + scsi_block_requests(mrioc->shost); mrioc->reset_in_progress = 1; mrioc->stop_bsgs = 1; mrioc->prev_reset_result = -1; @@ -5308,9 +5615,9 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); mpi3mr_ioc_disable_intr(mrioc); + mrioc->io_admin_reset_sync = 1; if (snapdump) { - mpi3mr_set_diagsave(mrioc); retval = mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); if (!retval) { @@ -5324,6 +5631,10 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); } @@ -5335,6 +5646,16 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); goto out; } + + retval = mpi3mr_check_op_admin_proc(mrioc); + if (retval) { + ioc_err(mrioc, "Soft reset failed due to an Admin or I/O queue polling\n" + "thread still processing replies even after a 10 second\n" + "timeout. Marking the controller as unrecoverable!\n"); + + goto out; + } + if (mrioc->num_io_throttle_group != mrioc->facts.max_io_throttle_group) { ioc_err(mrioc, @@ -5379,9 +5700,11 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME); out: + mrioc->invalid_io_comp = 0; if (!retval) { mrioc->diagsave_timeout = 0; mrioc->reset_in_progress = 0; + scsi_unblock_requests(mrioc->shost); mrioc->pel_abort_requested = 0; if (mrioc->pel_enabled) { mrioc->pel_cmds.retry_count = 0; @@ -5401,11 +5724,17 @@ out: if (mrioc->pel_enabled) atomic64_inc(&event_counter); } else { - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); + dprint_reset(mrioc, + "soft_reset_handler failed, marking controller as unrecoverable\n"); + ioc_state = mpi3mr_get_iocstate(mrioc); + + if (ioc_state != MRIOC_STATE_FAULT) + mpi3mr_issue_reset(mrioc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); mrioc->device_refresh_on = 0; mrioc->unrecoverable = 1; mrioc->reset_in_progress = 0; + scsi_unblock_requests(mrioc->shost); mrioc->stop_bsgs = 0; retval = -1; mpi3mr_flush_cmds_for_unrecovered_controller(mrioc); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b9a51d3f2024..402d1f35d214 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -49,6 +49,13 @@ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, #define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH (0xFFFE) +/* + * SAS Log info code for a NCQ collateral abort after an NCQ error: + * IOC_LOGINFO_PREFIX_PL | PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR + * See: drivers/message/fusion/lsi/mpi_log_sas.h + */ +#define IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR 0x31080000 + /** * mpi3mr_host_tag_for_scmd - Get host tag for a scmd * @mrioc: Adapter instance reference @@ -669,7 +676,7 @@ static struct mpi3mr_tgt_dev *mpi3mr_alloc_tgtdev(void) { struct mpi3mr_tgt_dev *tgtdev; - tgtdev = kzalloc(sizeof(*tgtdev), GFP_ATOMIC); + tgtdev = kzalloc_obj(*tgtdev, GFP_ATOMIC); if (!tgtdev) return NULL; kref_init(&tgtdev->ref_count); @@ -985,6 +992,10 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc, goto out; } } + dprint_event_bh(mrioc, + "exposed target device with handle(0x%04x), perst_id(%d)\n", + tgtdev->dev_handle, perst_id); + goto out; } else mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev); out: @@ -1128,6 +1139,89 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) } /** + * mpi3mr_debug_dump_devpg0 - Dump device page0 + * @mrioc: Adapter instance reference + * @dev_pg0: Device page 0. + * + * Prints pertinent details of the device page 0. + * + * Return: Nothing. + */ +static void +mpi3mr_debug_dump_devpg0(struct mpi3mr_ioc *mrioc, struct mpi3_device_page0 *dev_pg0) +{ + ioc_info(mrioc, + "device_pg0: handle(0x%04x), perst_id(%d), wwid(0x%016llx), encl_handle(0x%04x), slot(%d)\n", + le16_to_cpu(dev_pg0->dev_handle), + le16_to_cpu(dev_pg0->persistent_id), + le64_to_cpu(dev_pg0->wwid), le16_to_cpu(dev_pg0->enclosure_handle), + le16_to_cpu(dev_pg0->slot)); + ioc_info(mrioc, "device_pg0: access_status(0x%02x), flags(0x%04x), device_form(0x%02x), queue_depth(%d)\n", + dev_pg0->access_status, le16_to_cpu(dev_pg0->flags), + dev_pg0->device_form, le16_to_cpu(dev_pg0->queue_depth)); + ioc_info(mrioc, "device_pg0: parent_handle(0x%04x), iounit_port(%d)\n", + le16_to_cpu(dev_pg0->parent_dev_handle), dev_pg0->io_unit_port); + + switch (dev_pg0->device_form) { + case MPI3_DEVICE_DEVFORM_SAS_SATA: + { + + struct mpi3_device0_sas_sata_format *sasinf = + &dev_pg0->device_specific.sas_sata_format; + ioc_info(mrioc, + "device_pg0: sas_sata: sas_address(0x%016llx),flags(0x%04x),\n" + "device_info(0x%04x), phy_num(%d), attached_phy_id(%d),negotiated_link_rate(0x%02x)\n", + le64_to_cpu(sasinf->sas_address), + le16_to_cpu(sasinf->flags), + le16_to_cpu(sasinf->device_info), sasinf->phy_num, + sasinf->attached_phy_identifier, sasinf->negotiated_link_rate); + break; + } + case MPI3_DEVICE_DEVFORM_PCIE: + { + + struct mpi3_device0_pcie_format *pcieinf = + &dev_pg0->device_specific.pcie_format; + ioc_info(mrioc, + "device_pg0: pcie: port_num(%d), device_info(0x%04x), mdts(%d), page_sz(0x%02x)\n", + pcieinf->port_num, le16_to_cpu(pcieinf->device_info), + le32_to_cpu(pcieinf->maximum_data_transfer_size), + pcieinf->page_size); + ioc_info(mrioc, + "device_pg0: pcie: abort_timeout(%d), reset_timeout(%d) capabilities (0x%08x)\n", + pcieinf->nvme_abort_to, pcieinf->controller_reset_to, + le32_to_cpu(pcieinf->capabilities)); + break; + } + case MPI3_DEVICE_DEVFORM_VD: + { + + struct mpi3_device0_vd_format *vdinf = + &dev_pg0->device_specific.vd_format; + + ioc_info(mrioc, + "device_pg0: vd: state(0x%02x), raid_level(%d), flags(0x%04x),\n" + "device_info(0x%04x) abort_timeout(%d), reset_timeout(%d)\n", + vdinf->vd_state, vdinf->raid_level, + le16_to_cpu(vdinf->flags), + le16_to_cpu(vdinf->device_info), + vdinf->vd_abort_to, vdinf->vd_reset_to); + ioc_info(mrioc, + "device_pg0: vd: tg_id(%d), high(%dMiB), low(%dMiB), qd_reduction_factor(%d)\n", + vdinf->io_throttle_group, + le16_to_cpu(vdinf->io_throttle_group_high), + le16_to_cpu(vdinf->io_throttle_group_low), + ((le16_to_cpu(vdinf->flags) & + MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_MASK) >> 12)); + break; + + } + default: + break; + } +} + +/** * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf * @mrioc: Adapter instance reference * @tgtdev: Target device internal structure @@ -1148,6 +1242,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, struct mpi3mr_enclosure_node *enclosure_dev = NULL; u8 prot_mask = 0; + if (mrioc->logging_level & + (MPI3_DEBUG_EVENT | MPI3_DEBUG_EVENT_WORK_TASK)) + mpi3mr_debug_dump_devpg0(mrioc, dev_pg0); + tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id); tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle); tgtdev->dev_type = dev_pg0->device_form; @@ -1173,6 +1271,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if (is_added == true) tgtdev->io_throttle_enabled = (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + if (!mrioc->sas_transport_enabled) + tgtdev->non_stl = 1; switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: @@ -1224,6 +1324,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num; tgtdev->dev_spec.sas_sata_inf.attached_phy_id = sasinf->attached_phy_identifier; + tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate = + sasinf->negotiated_link_rate; if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) != MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE) tgtdev->is_hidden = 1; @@ -1297,6 +1399,12 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE) tgtdev->is_hidden = 1; tgtdev->non_stl = 1; + tgtdev->dev_spec.vd_inf.reset_to = + max_t(u8, vdinf->vd_reset_to, + MPI3MR_INTADMCMD_TIMEOUT); + tgtdev->dev_spec.vd_inf.abort_to = + max_t(u8, vdinf->vd_abort_to, + MPI3MR_INTADMCMD_TIMEOUT); tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group; tgtdev->dev_spec.vd_inf.tg_high = le16_to_cpu(vdinf->io_throttle_group_high) * 2048; @@ -1344,9 +1452,9 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc, (struct mpi3_event_data_device_status_change *)fwevt->event_data; dev_handle = le16_to_cpu(evtdata->dev_handle); - ioc_info(mrioc, - "%s :device status change: handle(0x%04x): reason code(0x%x)\n", - __func__, dev_handle, evtdata->reason_code); + dprint_event_bh(mrioc, + "processing device status change event bottom half for handle(0x%04x), rc(0x%02x)\n", + dev_handle, evtdata->reason_code); switch (evtdata->reason_code) { case MPI3_EVENT_DEV_STAT_RC_HIDDEN: delete = 1; @@ -1365,8 +1473,13 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc, } tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); - if (!tgtdev) + if (!tgtdev) { + dprint_event_bh(mrioc, + "processing device status change event bottom half,\n" + "cannot identify target device for handle(0x%04x), rc(0x%02x)\n", + dev_handle, evtdata->reason_code); goto out; + } if (uhide) { tgtdev->is_hidden = 0; if (!tgtdev->host_exposed) @@ -1406,12 +1519,17 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc, perst_id = le16_to_cpu(dev_pg0->persistent_id); dev_handle = le16_to_cpu(dev_pg0->dev_handle); - ioc_info(mrioc, - "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n", - __func__, dev_handle, perst_id); + dprint_event_bh(mrioc, + "processing device info change event bottom half for handle(0x%04x), perst_id(%d)\n", + dev_handle, perst_id); tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); - if (!tgtdev) + if (!tgtdev) { + dprint_event_bh(mrioc, + "cannot identify target device for device info\n" + "change event handle(0x%04x), perst_id(%d)\n", + dev_handle, perst_id); goto out; + } mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false); if (!tgtdev->is_hidden && !tgtdev->host_exposed) mpi3mr_report_tgtdev_to_host(mrioc, perst_id); @@ -1592,8 +1710,7 @@ static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc, encl_handle); if (!enclosure_dev && present) { enclosure_dev = - kzalloc(sizeof(struct mpi3mr_enclosure_node), - GFP_KERNEL); + kzalloc_obj(struct mpi3mr_enclosure_node); if (!enclosure_dev) return; list_add_tail(&enclosure_dev->list, @@ -1933,7 +2050,7 @@ static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc, static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc, struct mpi3mr_fwevt *fwevt) { - mpi3mr_app_save_logdata(mrioc, fwevt->event_data, + mpi3mr_app_save_logdata_th(mrioc, fwevt->event_data, fwevt->event_data_size); } @@ -2012,8 +2129,11 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, mpi3mr_fwevt_del_from_list(mrioc, fwevt); mrioc->current_event = fwevt; - if (mrioc->stop_drv_processing) + if (mrioc->stop_drv_processing) { + dprint_event_bh(mrioc, "ignoring event(0x%02x) in the bottom half handler\n" + "due to stop_drv_processing\n", fwevt->event_id); goto out; + } if (mrioc->unrecoverable) { dprint_event_bh(mrioc, @@ -2025,6 +2145,9 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, if (!fwevt->process_evt) goto evt_ack; + dprint_event_bh(mrioc, "processing event(0x%02x) -(0x%08x) in the bottom half handler\n", + fwevt->event_id, fwevt->evt_ctx); + switch (fwevt->event_id) { case MPI3_EVENT_DEVICE_ADDED: { @@ -2411,8 +2534,7 @@ static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle, } while (retrycount--); if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) { - delayed_dev_rmhs = kzalloc(sizeof(*delayed_dev_rmhs), - GFP_ATOMIC); + delayed_dev_rmhs = kzalloc_obj(*delayed_dev_rmhs, GFP_ATOMIC); if (!delayed_dev_rmhs) return; INIT_LIST_HEAD(&delayed_dev_rmhs->list); @@ -2553,8 +2675,7 @@ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, } while (retrycount--); if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) { - delayed_evtack = kzalloc(sizeof(*delayed_evtack), - GFP_ATOMIC); + delayed_evtack = kzalloc_obj(*delayed_evtack, GFP_ATOMIC); if (!delayed_evtack) return; INIT_LIST_HEAD(&delayed_evtack->list); @@ -2763,6 +2884,9 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc, goto out; dev_handle = le16_to_cpu(evtdata->dev_handle); + dprint_event_th(mrioc, + "device status change event top half with rc(0x%02x) for handle(0x%04x)\n", + evtdata->reason_code, dev_handle); switch (evtdata->reason_code) { case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT: @@ -2786,8 +2910,12 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc, } tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); - if (!tgtdev) + if (!tgtdev) { + dprint_event_th(mrioc, + "processing device status change event could not identify device for handle(0x%04x)\n", + dev_handle); goto out; + } if (hide) tgtdev->is_hidden = hide; if (tgtdev->starget && tgtdev->starget->hostdata) { @@ -2832,12 +2960,14 @@ static void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc, "prepare for reset event top half with rc=start\n"); if (mrioc->prepare_for_reset) return; + scsi_block_requests(mrioc->shost); mrioc->prepare_for_reset = 1; mrioc->prepare_for_reset_timeout_counter = 0; } else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) { dprint_event_th(mrioc, "prepare for reset top half with rc=abort\n"); mrioc->prepare_for_reset = 0; + scsi_unblock_requests(mrioc->shost); mrioc->prepare_for_reset_timeout_counter = 0; } if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) @@ -2863,13 +2993,13 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc, u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout); if (shutdown_timeout <= 0) { - ioc_warn(mrioc, + dprint_event_th(mrioc, "%s :Invalid Shutdown Timeout received = %d\n", __func__, shutdown_timeout); return; } - ioc_info(mrioc, + dprint_event_th(mrioc, "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n", __func__, mrioc->facts.shutdown_timeout, shutdown_timeout); mrioc->facts.shutdown_timeout = shutdown_timeout; @@ -2945,9 +3075,9 @@ void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc) * @mrioc: Adapter instance reference * @event_reply: event data * - * Identify whteher the event has to handled and acknowledged - * and either process the event in the tophalf and/or schedule a - * bottom half through mpi3mr_fwevt_worker. + * Identifies whether the event has to be handled and acknowledged, + * and either processes the event in the top-half and/or schedule a + * bottom-half through mpi3mr_fwevt_worker(). * * Return: Nothing */ @@ -2974,9 +3104,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, struct mpi3_device_page0 *dev_pg0 = (struct mpi3_device_page0 *)event_reply->event_data; if (mpi3mr_create_tgtdev(mrioc, dev_pg0)) - ioc_err(mrioc, - "%s :Failed to add device in the device add event\n", - __func__); + dprint_event_th(mrioc, + "failed to process device added event for handle(0x%04x),\n" + "perst_id(%d) in the event top half handler\n", + le16_to_cpu(dev_pg0->dev_handle), + le16_to_cpu(dev_pg0->persistent_id)); else process_evt_bh = 1; break; @@ -3012,6 +3144,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, } case MPI3_EVENT_DEVICE_INFO_CHANGED: case MPI3_EVENT_LOG_DATA: + + sz = event_reply->event_data_length * 4; + mpi3mr_app_save_logdata_th(mrioc, + (char *)event_reply->event_data, sz); + break; case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: case MPI3_EVENT_ENCL_DEVICE_ADDED: { @@ -3039,11 +3176,15 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, break; } if (process_evt_bh || ack_req) { + dprint_event_th(mrioc, + "scheduling bottom half handler for event(0x%02x) - (0x%08x), ack_required=%d\n", + evt_type, le32_to_cpu(event_reply->event_context), ack_req); sz = event_reply->event_data_length * 4; fwevt = mpi3mr_alloc_fwevt(sz); if (!fwevt) { - ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n", - __func__, __FILE__, __LINE__, __func__); + dprint_event_th(mrioc, + "failed to schedule bottom half handler for\n" + "event(0x%02x), ack_required=%d\n", evt_type, ack_req); return; } @@ -3318,8 +3459,15 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, } scmd = mpi3mr_scmd_from_host_tag(mrioc, host_tag, qidx); if (!scmd) { - panic("%s: Cannot Identify scmd for host_tag 0x%x\n", - mrioc->name, host_tag); + ioc_err(mrioc, "Cannot Identify scmd for host_tag 0x%x", host_tag); + ioc_err(mrioc, + "reply_desc_type(%d) host_tag(%d(0x%04x)): qid(%d): command issued to\n" + "handle(0x%04x) returned with ioc_status(0x%04x), log_info(0x%08x),\n" + "scsi_state(0x%02x), scsi_status(0x%02x), xfer_count(%d), resp_data(0x%08x)\n", + reply_desc_type, host_tag, host_tag, qidx+1, dev_handle, ioc_status, + ioc_loginfo, scsi_state, scsi_status, xfer_count, + resp_data); + mrioc->invalid_io_comp = 1; goto out; } priv = scsi_cmd_priv(scmd); @@ -3397,7 +3545,18 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, scmd->result = DID_NO_CONNECT << 16; break; case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: - scmd->result = DID_SOFT_ERROR << 16; + if (ioc_loginfo == IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR) { + /* + * This is a ATA NCQ command aborted due to another NCQ + * command failure. We must retry this command + * immediately but without incrementing its retry + * counter. + */ + WARN_ON_ONCE(xfer_count != 0); + scmd->result = DID_IMM_RETRY << 16; + } else { + scmd->result = DID_SOFT_ERROR << 16; + } break; case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED: case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED: @@ -3839,6 +3998,18 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); if (scmd) { + if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + cmd_priv = scsi_cmd_priv(scmd); + if (!cmd_priv) + goto out_unlock; + + struct op_req_qinfo *op_req_q; + + op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx]; + tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag); + tm_req.task_request_queue_id = + cpu_to_le16(op_req_q->qid); + } sdev = scmd->device; sdev_priv_data = sdev->hostdata; scsi_tgt_priv_data = ((sdev_priv_data) ? @@ -3852,11 +4023,13 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, if (scsi_tgt_priv_data) atomic_inc(&scsi_tgt_priv_data->block_io); - if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) { - if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to) - timeout = tgtdev->dev_spec.pcie_inf.abort_to; - else if (!cmd_priv && tgtdev->dev_spec.pcie_inf.reset_to) - timeout = tgtdev->dev_spec.pcie_inf.reset_to; + if (tgtdev) { + if (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) + timeout = cmd_priv ? tgtdev->dev_spec.pcie_inf.abort_to + : tgtdev->dev_spec.pcie_inf.reset_to; + else if (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_VD) + timeout = cmd_priv ? tgtdev->dev_spec.vd_inf.abort_to + : tgtdev->dev_spec.vd_inf.reset_to; } init_completion(&drv_cmd->done); @@ -3968,7 +4141,7 @@ out: /** * mpi3mr_bios_param - BIOS param callback * @sdev: SCSI device reference - * @bdev: Block device reference + * @unused: gendisk reference * @capacity: Capacity in logical sectors * @params: Parameter array * @@ -3977,7 +4150,7 @@ out: * Return: 0 always */ static int mpi3mr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int params[]) + struct gendisk *unused, sector_t capacity, int params[]) { int heads; int sectors; @@ -4388,6 +4561,92 @@ out: } /** + * mpi3mr_eh_abort - Callback function for abort error handling + * @scmd: SCSI command reference + * + * Issues Abort Task Management if the command is in LLD scope + * and verifies if it is aborted successfully, and return status + * accordingly. + * + * Return: SUCCESS if the abort was successful, otherwise FAILED + */ +static int mpi3mr_eh_abort(struct scsi_cmnd *scmd) +{ + struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); + struct mpi3mr_stgt_priv_data *stgt_priv_data; + struct mpi3mr_sdev_priv_data *sdev_priv_data; + struct scmd_priv *cmd_priv; + u16 dev_handle, timeout = MPI3MR_ABORTTM_TIMEOUT; + u8 resp_code = 0; + int retval = FAILED, ret = 0; + struct request *rq = scsi_cmd_to_rq(scmd); + unsigned long scmd_age_ms = jiffies_to_msecs(jiffies - scmd->jiffies_at_alloc); + unsigned long scmd_age_sec = scmd_age_ms / HZ; + + sdev_printk(KERN_INFO, scmd->device, + "%s: attempting abort task for scmd(%p)\n", mrioc->name, scmd); + + sdev_printk(KERN_INFO, scmd->device, + "%s: scmd(0x%p) is outstanding for %lus %lums, timeout %us, retries %d, allowed %d\n", + mrioc->name, scmd, scmd_age_sec, scmd_age_ms % HZ, rq->timeout / HZ, + scmd->retries, scmd->allowed); + + scsi_print_command(scmd); + + sdev_priv_data = scmd->device->hostdata; + if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { + sdev_printk(KERN_INFO, scmd->device, + "%s: Device not available, Skip issuing abort task\n", + mrioc->name); + retval = SUCCESS; + goto out; + } + + stgt_priv_data = sdev_priv_data->tgt_priv_data; + dev_handle = stgt_priv_data->dev_handle; + + cmd_priv = scsi_cmd_priv(scmd); + if (!cmd_priv->in_lld_scope || + cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID) { + sdev_printk(KERN_INFO, scmd->device, + "%s: scmd (0x%p) not in LLD scope, Skip issuing Abort Task\n", + mrioc->name, scmd); + retval = SUCCESS; + goto out; + } + + if (stgt_priv_data->dev_removed) { + sdev_printk(KERN_INFO, scmd->device, + "%s: Device (handle = 0x%04x) removed, Skip issuing Abort Task\n", + mrioc->name, dev_handle); + retval = FAILED; + goto out; + } + + ret = mpi3mr_issue_tm(mrioc, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + dev_handle, sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, + timeout, &mrioc->host_tm_cmds, &resp_code, scmd); + + if (ret) + goto out; + + if (cmd_priv->in_lld_scope) { + sdev_printk(KERN_INFO, scmd->device, + "%s: Abort task failed. scmd (0x%p) was not terminated\n", + mrioc->name, scmd); + goto out; + } + + retval = SUCCESS; +out: + sdev_printk(KERN_INFO, scmd->device, + "%s: Abort Task %s for scmd (0x%p)\n", mrioc->name, + ((retval == SUCCESS) ? "SUCCEEDED" : "FAILED"), scmd); + + return retval; +} + +/** * mpi3mr_scan_start - Scan start callback handler * @shost: SCSI host reference * @@ -4645,7 +4904,7 @@ static int mpi3mr_sdev_init(struct scsi_device *sdev) spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); - scsi_dev_priv_data = kzalloc(sizeof(*scsi_dev_priv_data), GFP_KERNEL); + scsi_dev_priv_data = kzalloc_obj(*scsi_dev_priv_data); if (!scsi_dev_priv_data) return -ENOMEM; @@ -4676,7 +4935,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) int retval = 0; struct sas_rphy *rphy = NULL; - scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL); + scsi_tgt_priv_data = kzalloc_obj(*scsi_tgt_priv_data); if (!scsi_tgt_priv_data) return -ENOMEM; @@ -4685,7 +4944,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) spin_lock_irqsave(&mrioc->tgtdev_lock, flags); if (starget->channel == mrioc->scsi_device_channel) { tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); - if (tgt_dev && !tgt_dev->is_hidden) { + if (tgt_dev && !tgt_dev->is_hidden && tgt_dev->non_stl) { scsi_tgt_priv_data->starget = starget; scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; @@ -4868,8 +5127,8 @@ inline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd) * SCSI_MLQUEUE_DEVICE_BUSY when the device is busy. * SCSI_MLQUEUE_HOST_BUSY when the host queue is full. */ -static int mpi3mr_qcmd(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mpi3mr_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mpi3mr_ioc *mrioc = shost_priv(shost); struct mpi3mr_stgt_priv_data *stgt_priv_data; @@ -5069,6 +5328,7 @@ static const struct scsi_host_template mpi3mr_driver_template = { .scan_finished = mpi3mr_scan_finished, .scan_start = mpi3mr_scan_start, .change_queue_depth = mpi3mr_change_queue_depth, + .eh_abort_handler = mpi3mr_eh_abort, .eh_device_reset_handler = mpi3mr_eh_dev_reset, .eh_target_reset_handler = mpi3mr_eh_target_reset, .eh_bus_reset_handler = mpi3mr_eh_bus_reset, @@ -5219,8 +5479,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (retval < 0) goto id_alloc_failed; mrioc->id = (u8)retval; - sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME); - sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id); + strscpy(mrioc->driver_name, MPI3MR_DRIVER_NAME, + sizeof(mrioc->driver_name)); + scnprintf(mrioc->name, sizeof(mrioc->name), + "%s%u", mrioc->driver_name, mrioc->id); INIT_LIST_HEAD(&mrioc->list); spin_lock(&mrioc_list_lock); list_add_tail(&mrioc->list, &mrioc_list); @@ -5233,6 +5495,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&mrioc->tgtdev_lock); spin_lock_init(&mrioc->watchdog_lock); spin_lock_init(&mrioc->chain_buf_lock); + spin_lock_init(&mrioc->adm_req_q_bar_writeq_lock); + spin_lock_init(&mrioc->adm_reply_q_bar_writeq_lock); spin_lock_init(&mrioc->sas_node_lock); spin_lock_init(&mrioc->trigger_lock); @@ -5803,7 +6067,7 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = { }; MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table); -static struct pci_error_handlers mpi3mr_err_handler = { +static const struct pci_error_handlers mpi3mr_err_handler = { .error_detected = mpi3mr_pcierr_error_detected, .mmio_enabled = mpi3mr_pcierr_mmio_enabled, .slot_reset = mpi3mr_pcierr_slot_reset, @@ -5819,7 +6083,10 @@ static struct pci_driver mpi3mr_pci_driver = { .remove = mpi3mr_remove, .shutdown = mpi3mr_shutdown, .err_handler = &mpi3mr_err_handler, - .driver.pm = &mpi3mr_pm_ops, + .driver = { + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &mpi3mr_pm_ops, + }, }; static ssize_t event_counter_show(struct device_driver *dd, char *buf) diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index 0ba9e6a6a13c..240f67a8e2e3 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -105,10 +105,10 @@ struct rep_manu_reply { u8 reserved0[2]; u8 sas_format; u8 reserved2[3]; - u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; - u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; - u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; - u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] __nonstring; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN] __nonstring; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] __nonstring; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] __nonstring; u16 component_id; u8 component_revision_id; u8 reserved3; @@ -413,9 +413,11 @@ static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc, sas_address, hba_port); if (tgtdev) { if (!list_empty(&tgtdev->list)) { - list_del_init(&tgtdev->list); was_on_tgtdev_list = 1; - mpi3mr_tgtdev_put(tgtdev); + if (tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) { + list_del_init(&tgtdev->list); + mpi3mr_tgtdev_put(tgtdev); + } } } spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); @@ -1020,8 +1022,7 @@ mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id) { struct mpi3mr_hba_port *hba_port; - hba_port = kzalloc(sizeof(struct mpi3mr_hba_port), - GFP_KERNEL); + hba_port = kzalloc_obj(struct mpi3mr_hba_port); if (!hba_port) return NULL; hba_port->port_id = port_id; @@ -1219,8 +1220,7 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc) mrioc->sas_hba.host_node = 1; INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list); mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev; - mrioc->sas_hba.phy = kcalloc(num_phys, - sizeof(struct mpi3mr_sas_phy), GFP_KERNEL); + mrioc->sas_hba.phy = kzalloc_objs(struct mpi3mr_sas_phy, num_phys); if (!mrioc->sas_hba.phy) return; @@ -1342,7 +1342,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, return NULL; } - mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL); + mr_sas_port = kzalloc_obj(struct mpi3mr_sas_port); if (!mr_sas_port) return NULL; @@ -1719,7 +1719,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_io_unit_pg0) return; - h_port = kcalloc(64, sizeof(struct host_port), GFP_KERNEL); + h_port = kzalloc_objs(struct host_port, 64); if (!h_port) goto out; @@ -2079,6 +2079,8 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle) link_rate = (expander_pg1.negotiated_link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5) + link_rate = MPI3_SAS_NEG_LINK_RATE_1_5; mpi3mr_update_links(mrioc, sas_address_parent, handle, i, link_rate, hba_port); } @@ -2094,8 +2096,7 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle) if (sas_expander) return 0; - sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node), - GFP_KERNEL); + sas_expander = kzalloc_obj(struct mpi3mr_sas_node); if (!sas_expander) return -ENOMEM; @@ -2114,8 +2115,8 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle) rc = -1; goto out_fail; } - sas_expander->phy = kcalloc(sas_expander->num_phys, - sizeof(struct mpi3mr_sas_phy), GFP_KERNEL); + sas_expander->phy = kzalloc_objs(struct mpi3mr_sas_phy, + sas_expander->num_phys); if (!sas_expander->phy) { rc = -1; goto out_fail; @@ -2280,11 +2281,11 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, * @mrioc: Adapter instance reference * @tgtdev: Target device * - * This function identifies whether the target device is - * attached directly or through expander and issues sas phy - * page0 or expander phy page1 and gets the link rate, if there - * is any failure in reading the pages then this returns link - * rate of 1.5. + * This function first tries to use the link rate from DevicePage0 + * (populated by firmware during device discovery). If the cached + * value is not available or invalid, it falls back to reading from + * sas phy page0 or expander phy page1. + * * * Return: logical link rate. */ @@ -2297,6 +2298,14 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, u32 phynum_handle; u16 ioc_status; + /* First, try to use link rate from DevicePage0 (populated by firmware) */ + if (tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate >= + MPI3_SAS_NEG_LINK_RATE_1_5) { + link_rate = tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate; + goto out; + } + + /* Fallback to reading from phy pages if DevicePage0 value not available */ phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id; if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) { phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) @@ -2314,9 +2323,7 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, __FILE__, __LINE__, __func__); goto out; } - link_rate = (expander_pg1.negotiated_link_rate & - MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = expander_pg1.negotiated_link_rate; goto out; } if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0, @@ -2331,11 +2338,11 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, __FILE__, __LINE__, __func__); goto out; } - link_rate = (phy_pg0.negotiated_link_rate & - MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = phy_pg0.negotiated_link_rate; + out: - return link_rate; + return ((link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> + MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT); } /** @@ -2388,6 +2395,9 @@ int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc, link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev); + if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5) + link_rate = MPI3_SAS_NEG_LINK_RATE_1_5; + mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle, parent_phy_number, link_rate, hba_port); diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index 6de35b32223c..b181b113fc80 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -125,6 +125,12 @@ * 06-24-19 02.00.55 Bumped MPI2_HEADER_VERSION_UNIT * 08-01-19 02.00.56 Bumped MPI2_HEADER_VERSION_UNIT * 10-02-19 02.00.57 Bumped MPI2_HEADER_VERSION_UNIT + * 07-20-20 02.00.58 Bumped MPI2_HEADER_VERSION_UNIT + * 03-30-21 02.00.59 Bumped MPI2_HEADER_VERSION_UNIT + * 06-03-22 02.00.60 Bumped MPI2_HEADER_VERSION_UNIT + * 09-20-23 02.00.61 Bumped MPI2_HEADER_VERSION_UNIT + * 09-13-24 02.00.62 Bumped MPI2_HEADER_VERSION_UNIT + * Added MPI2_FUNCTION_MCTP_PASSTHROUGH * -------------------------------------------------------------------------- */ @@ -165,7 +171,7 @@ /* Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x39) +#define MPI2_HEADER_VERSION_UNIT (0x3E) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -669,6 +675,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { #define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) #define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) #define MPI2_FUNCTION_NVME_ENCAPSULATED (0x33) +#define MPI2_FUNCTION_MCTP_PASSTHROUGH (0x34) #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) #define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 587f7d248219..02bf26ca976e 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -251,6 +251,7 @@ * 12-17-18 02.00.47 Swap locations of Slotx2 and Slotx4 in ManPage 7. * 08-01-19 02.00.49 Add MPI26_MANPAGE7_FLAG_X2_X4_SLOT_INFO_VALID * Add MPI26_IOUNITPAGE1_NVME_WRCACHE_SHIFT + * 09-13-24 02.00.50 Added PCIe 32 GT/s link rate */ #ifndef MPI2_CNFG_H @@ -606,7 +607,7 @@ typedef struct _MPI2_CONFIG_REPLY { typedef struct _MPI2_CONFIG_PAGE_MAN_0 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ - U8 ChipName[16]; /*0x04 */ + U8 ChipName[16] __nonstring; /*0x04 */ U8 ChipRevision[8]; /*0x14 */ U8 BoardName[16]; /*0x1C */ U8 BoardAssembly[16]; /*0x2C */ @@ -1121,6 +1122,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) #define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) #define MPI2_IOUNITPAGE7_PCIE_SPEED_16_0_GBPS (0x03) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_32_0_GBPS (0x04) /*defines for IO Unit Page 7 ProcessorState field */ #define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) @@ -2301,6 +2303,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { #define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) /*values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI2_SASIOUNIT1_ACONTROL_PROD_SPECIFIC_1 (0x8000) #define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100) #define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) #define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) @@ -3591,6 +3594,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { #define MPI26_PCIE_NEG_LINK_RATE_5_0 (0x03) #define MPI26_PCIE_NEG_LINK_RATE_8_0 (0x04) #define MPI26_PCIE_NEG_LINK_RATE_16_0 (0x05) +#define MPI26_PCIE_NEG_LINK_RATE_32_0 (0x06) /**************************************************************************** @@ -3700,6 +3704,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { #define MPI26_PCIEIOUNIT1_MAX_RATE_5_0 (0x30) #define MPI26_PCIEIOUNIT1_MAX_RATE_8_0 (0x40) #define MPI26_PCIEIOUNIT1_MAX_RATE_16_0 (0x50) +#define MPI26_PCIEIOUNIT1_MAX_RATE_32_0 (0x60) /*values for PCIe IO Unit Page 1 DMDReportPCIe */ #define MPI26_PCIEIOUNIT1_DMDRPT_UNIT_MASK (0x80) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index d92852591134..1a279c6e1a9f 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -179,6 +179,7 @@ * Added MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED * Added MPI2_FW_DOWNLOAD_ITYPE_COREDUMP * Added MPI2_FW_UPLOAD_ITYPE_COREDUMP + * 9-13-24 02.00.39 Added MPI26_MCTP_PASSTHROUGH messages * -------------------------------------------------------------------------- */ @@ -382,6 +383,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY { /*ProductID field uses MPI2_FW_HEADER_PID_ */ /*IOCCapabilities */ +#define MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU (0x00800000) #define MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED (0x00200000) #define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000) #define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000) @@ -1798,5 +1800,57 @@ typedef struct _MPI26_IOUNIT_CONTROL_REPLY { Mpi26IoUnitControlReply_t, *pMpi26IoUnitControlReply_t; +/**************************************************************************** + * MCTP Passthrough messages (MPI v2.6 and later only.) + ****************************************************************************/ + +/* MCTP Passthrough Request Message */ +typedef struct _MPI26_MCTP_PASSTHROUGH_REQUEST { + U8 MsgContext; /* 0x00 */ + U8 Reserved1[2]; /* 0x01 */ + U8 Function; /* 0x03 */ + U8 Reserved2[3]; /* 0x04 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + U8 Flags; /* 0x10 */ + U8 Reserved5[3]; /* 0x11 */ + U32 Reserved6; /* 0x14 */ + U32 H2DLength; /* 0x18 */ + U32 D2HLength; /* 0x1C */ + MPI25_SGE_IO_UNION H2DSGL; /* 0x20 */ + MPI25_SGE_IO_UNION D2HSGL; /* 0x30 */ +} MPI26_MCTP_PASSTHROUGH_REQUEST, + *PTR_MPI26_MCTP_PASSTHROUGH_REQUEST, + Mpi26MctpPassthroughRequest_t, + *pMpi26MctpPassthroughRequest_t; + +/* values for the MsgContext field */ +#define MPI26_MCTP_MSG_CONEXT_UNUSED (0x00) + +/* values for the Flags field */ +#define MPI26_MCTP_FLAGS_MSG_FORMAT_MPT (0x01) + +/* MCTP Passthrough Reply Message */ +typedef struct _MPI26_MCTP_PASSTHROUGH_REPLY { + U8 MsgContext; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2[3]; /* 0x04 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ResponseDataLength; /* 0x14 */ +} MPI26_MCTP_PASSTHROUGH_REPLY, + *PTR_MPI26_MCTP_PASSTHROUGH_REPLY, + Mpi26MctpPassthroughReply_t, + *pMpi26MctpPassthroughReply_t; #endif diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index dc43cfa83088..79052f2accbd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -843,11 +843,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) /* initialize fault polling */ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", - ioc->driver_name, ioc->id); ioc->fault_reset_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, ioc->fault_reset_work_q_name); + "poll_%s%d_status", WQ_MEM_RECLAIM, ioc->driver_name, ioc->id); if (!ioc->fault_reset_work_q) { ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; @@ -1202,6 +1199,11 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, ioc->sge_size; func_str = "nvme_encapsulated"; break; + case MPI2_FUNCTION_MCTP_PASSTHROUGH: + frame_sz = sizeof(Mpi26MctpPassthroughRequest_t) + + ioc->sge_size; + func_str = "mctp_passthru"; + break; default: frame_sz = 32; func_str = "unknown"; @@ -1415,7 +1417,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); - _base_sas_log_info(ioc, loginfo); + if (ioc->logging_level & MPT_DEBUG_REPLY) + _base_sas_log_info(ioc, loginfo); + else { + if (!((ioc_status & MPI2_IOCSTATUS_MASK) & + MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) + _base_sas_log_info(ioc, loginfo); + } } if (ioc_status || loginfo) { @@ -1489,8 +1497,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) goto out; smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); if (!smid) { - delayed_event_ack = kzalloc(sizeof(*delayed_event_ack), - GFP_ATOMIC); + delayed_event_ack = kzalloc_obj(*delayed_event_ack, GFP_ATOMIC); if (!delayed_event_ack) goto out; INIT_LIST_HEAD(&delayed_event_ack->list); @@ -1553,6 +1560,8 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) int i; u16 ctl_smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; u8 cb_idx = 0xFF; + u16 discovery_smid = + ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; if (smid < ioc->hi_priority_smid) { struct scsiio_tracker *st; @@ -1561,8 +1570,10 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) st = _get_st_from_smid(ioc, smid); if (st) cb_idx = st->cb_idx; - } else if (smid == ctl_smid) + } else if (smid < discovery_smid) cb_idx = ioc->ctl_cb_idx; + else + cb_idx = ioc->scsih_cb_idx; } else if (smid < ioc->internal_smid) { i = smid - ioc->hi_priority_smid; cb_idx = ioc->hpr_lookup[i].cb_idx; @@ -3150,7 +3161,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) struct adapter_reply_queue *reply_q; int r, qid; - reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); + reply_q = kzalloc_obj(struct adapter_reply_queue); if (!reply_q) { ioc_err(ioc, "unable to allocate memory %zu!\n", sizeof(struct adapter_reply_queue)); @@ -3163,7 +3174,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (index >= ioc->iopoll_q_start_index) { qid = index - ioc->iopoll_q_start_index; - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", ioc->driver_name, ioc->id, qid); reply_q->is_iouring_poll_q = 1; ioc->io_uring_poll_queues[qid].reply_q = reply_q; @@ -3172,10 +3183,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", ioc->driver_name, ioc->id, index); else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", ioc->driver_name, ioc->id); r = request_irq(pci_irq_vector(pdev, index), _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); @@ -3450,8 +3461,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) iopoll_q_count = poll_queues; if (iopoll_q_count) { - ioc->io_uring_poll_queues = kcalloc(iopoll_q_count, - sizeof(struct io_uring_poll_queue), GFP_KERNEL); + ioc->io_uring_poll_queues = kzalloc_objs(struct io_uring_poll_queue, + iopoll_q_count); if (!ioc->io_uring_poll_queues) iopoll_q_count = 0; } @@ -3715,9 +3726,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) * each register is at offset bytes of * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one. */ - ioc->replyPostRegisterIndex = kcalloc( - ioc->combined_reply_index_count, - sizeof(resource_size_t *), GFP_KERNEL); + ioc->replyPostRegisterIndex = kzalloc_objs(resource_size_t *, + ioc->combined_reply_index_count); if (!ioc->replyPostRegisterIndex) { ioc_err(ioc, "allocation for replyPostRegisterIndex failed!\n"); @@ -4874,6 +4884,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) i++; } + if (ioc->facts.IOCCapabilities & + MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { + pr_cont("%sMCTP Passthru", i ? "," : ""); + i++; + } + iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { pr_cont("%sNCQ", i ? "," : ""); @@ -6200,8 +6216,7 @@ base_alloc_rdpq_dma_pool(struct MPT3SAS_ADAPTER *ioc, int sz) sizeof(Mpi2DefaultReplyDescriptor_t); int count = ioc->rdpq_array_enable ? ioc->reply_queue_count : 1; - ioc->reply_post = kcalloc(count, sizeof(struct reply_post_struct), - GFP_KERNEL); + ioc->reply_post = kzalloc_objs(struct reply_post_struct, count); if (!ioc->reply_post) return -ENOMEM; /* @@ -6544,8 +6559,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) } /* initialize hi-priority queue smid's */ - ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, - sizeof(struct request_tracker), GFP_KERNEL); + ioc->hpr_lookup = kzalloc_objs(struct request_tracker, + ioc->hi_priority_depth); if (!ioc->hpr_lookup) { ioc_err(ioc, "hpr_lookup: kcalloc failed\n"); goto out; @@ -6557,8 +6572,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->hi_priority_depth, ioc->hi_priority_smid)); /* initialize internal queue smid's */ - ioc->internal_lookup = kcalloc(ioc->internal_depth, - sizeof(struct request_tracker), GFP_KERNEL); + ioc->internal_lookup = kzalloc_objs(struct request_tracker, + ioc->internal_depth); if (!ioc->internal_lookup) { ioc_err(ioc, "internal_lookup: kcalloc failed\n"); goto out; @@ -8018,7 +8033,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) mutex_lock(&ioc->hostdiag_unlock_mutex); if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) - goto out; + goto unlock; hcb_size = ioc->base_readl(&ioc->chip->HCBSize); drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n")); @@ -8038,7 +8053,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "Invalid host diagnostic register value\n"); _base_dump_reg_set(ioc); - goto out; + goto unlock; } if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) break; @@ -8074,17 +8089,19 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", __func__, ioc_state); _base_dump_reg_set(ioc); - goto out; + goto fail; } pci_cfg_access_unlock(ioc->pdev); ioc_info(ioc, "diag reset: SUCCESS\n"); return 0; - out: +unlock: + mutex_unlock(&ioc->hostdiag_unlock_mutex); + +fail: pci_cfg_access_unlock(ioc->pdev); ioc_err(ioc, "diag reset: FAILED\n"); - mutex_unlock(&ioc->hostdiag_unlock_mutex); return -EFAULT; } @@ -8410,8 +8427,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) } if (ioc->is_warpdrive) { - ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, - sizeof(resource_size_t *), GFP_KERNEL); + ioc->reply_post_host_index = kzalloc_objs(resource_size_t *, + ioc->cpu_msix_table_sz); if (!ioc->reply_post_host_index) { ioc_info(ioc, "Allocation for reply_post_host_index failed!!!\n"); r = -ENOMEM; @@ -8500,8 +8517,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; - ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(struct mpt3sas_port_facts), GFP_KERNEL); + ioc->pfacts = kzalloc_objs(struct mpt3sas_port_facts, + ioc->facts.NumberOfPorts); if (!ioc->pfacts) { r = -ENOMEM; goto out_free_resources; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index d8d1a64b4764..d4597d058705 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -77,8 +77,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "51.100.00.00" -#define MPT3SAS_MAJOR_VERSION 51 +#define MPT3SAS_DRIVER_VERSION "54.100.00.00" +#define MPT3SAS_MAJOR_VERSION 54 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 00 #define MPT3SAS_RELEASE_VERSION 00 @@ -147,6 +147,7 @@ #define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ /* reserved for issuing internally framed scsi io cmds */ #define INTERNAL_SCSIIO_CMDS_COUNT 3 +#define INTERNAL_SCSIIO_FOR_DISCOVERY 2 #define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/ @@ -480,6 +481,7 @@ struct MPT3SAS_DEVICE { u32 flags; u8 configured_lun; u8 block; + u8 deleted; u8 tlr_snoop_check; u8 ignore_delay_remove; /* Iopriority Command Handling */ @@ -577,7 +579,9 @@ struct _sas_device { u8 chassis_slot; u8 is_chassis_slot_valid; u8 connector_name[5]; + u8 ssd_device; struct kref refcount; + u8 port_type; struct hba_port *port; struct sas_rphy *rphy; @@ -1159,9 +1163,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @mask_interrupts: ignore interrupt * @pci_access_mutex: Mutex to synchronize ioctl, sysfs show path and * pci resource handling - * @fault_reset_work_q_name: fw fault work queue - * @fault_reset_work_q: "" - * @fault_reset_work: "" + * @fault_reset_work_q: fw fault workqueue + * @fault_reset_work: fw fault work * @firmware_event_thread: fw event work queue * @fw_event_lock: * @fw_event_list: list of fw events @@ -1345,7 +1348,6 @@ struct MPT3SAS_ADAPTER { u8 mask_interrupts; /* fw fault handler */ - char fault_reset_work_q_name[20]; struct workqueue_struct *fault_reset_work_q; struct delayed_work fault_reset_work; @@ -1858,9 +1860,6 @@ int mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, int mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage1_t *config_page); -int mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, - u16 sz); int mpt3sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, struct Mpi2ManufacturingPage10_t *config_page); @@ -1887,9 +1886,6 @@ int mpt3sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t int mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle); -int mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, - u32 form, u32 handle); int mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, u32 form, u32 handle); diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 2e88f456fc34..45ac853e1289 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -577,44 +577,6 @@ mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc, } /** - * mpt3sas_config_get_manufacturing_pg7 - obtain manufacturing page 7 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Return: 0 for success, non-zero for failure. - */ -int -mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, - u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; - mpi_request.Header.PageNumber = 7; - mpi_request.Header.PageVersion = MPI2_MANUFACTURING7_PAGEVERSION; - ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sz); - out: - return r; -} - -/** * mpt3sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware @@ -1214,47 +1176,6 @@ mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, } /** - * mpt3sas_config_get_sas_device_pg1 - obtain sas device page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: device handle - * Context: sleep. - * - * Return: 0 for success, non-zero for failure. - */ -int -mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, - u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; - mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; - mpi_request.Header.PageNumber = 1; - ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** * mpt3sas_config_get_pcie_device_pg0 - obtain pcie device page 0 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 87784c96249a..8bb947004885 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -186,6 +186,9 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, case MPI2_FUNCTION_NVME_ENCAPSULATED: desc = "nvme_encapsulated"; break; + case MPI2_FUNCTION_MCTP_PASSTHROUGH: + desc = "mctp_passthrough"; + break; } if (!desc) @@ -653,6 +656,40 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, } /** + * _ctl_send_mctp_passthru_req - Send an MCTP passthru request + * @ioc: per adapter object + * @mctp_passthru_req: MPI mctp passhthru request from caller + * @psge: pointer to the H2DSGL + * @data_out_dma: DMA buffer for H2D SGL + * @data_out_sz: H2D length + * @data_in_dma: DMA buffer for D2H SGL + * @data_in_sz: D2H length + * @smid: SMID to submit the request + * + */ +static void +_ctl_send_mctp_passthru_req( + struct MPT3SAS_ADAPTER *ioc, + Mpi26MctpPassthroughRequest_t *mctp_passthru_req, void *psge, + dma_addr_t data_out_dma, int data_out_sz, + dma_addr_t data_in_dma, int data_in_sz, + u16 smid) +{ + mctp_passthru_req->H2DLength = data_out_sz; + mctp_passthru_req->D2HLength = data_in_sz; + + /* Build the H2D SGL from the data out buffer */ + ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, 0, 0); + + psge += ioc->sge_size_ieee; + + /* Build the D2H SGL for the data in buffer */ + ioc->build_sg(ioc, psge, 0, 0, data_in_dma, data_in_sz); + + ioc->put_smid_default(ioc, smid); +} + +/** * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode * @ioc: per adapter object * @karg: (struct mpt3_ioctl_command) @@ -679,6 +716,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, size_t data_in_sz = 0; long ret; u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; + int tm_ret; issue_reset = 0; @@ -792,6 +830,23 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, init_completion(&ioc->ctl_cmds.done); switch (mpi_request->Function) { + case MPI2_FUNCTION_MCTP_PASSTHROUGH: + { + Mpi26MctpPassthroughRequest_t *mctp_passthru_req = + (Mpi26MctpPassthroughRequest_t *)request; + + if (!(ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU)) { + ioc_err(ioc, "%s: MCTP Passthrough request not supported\n", + __func__); + mpt3sas_base_free_smid(ioc, smid); + ret = -EINVAL; + goto out; + } + + _ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma, + data_out_sz, data_in_dma, data_in_sz, smid); + break; + } case MPI2_FUNCTION_NVME_ENCAPSULATED: { nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request; @@ -1120,18 +1175,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, if (pcie_device && (!ioc->tm_custom_handling) && (!(mpt3sas_scsih_is_pcie_scsi_device( pcie_device->device_info)))) - mpt3sas_scsih_issue_locked_tm(ioc, + tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0, pcie_device->reset_timeout, MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); else - mpt3sas_scsih_issue_locked_tm(ioc, + tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET); + + if (tm_ret != SUCCESS) { + ioc_info(ioc, + "target reset failed, issue hard reset: handle (0x%04x)\n", + le16_to_cpu(mpi_request->FunctionDependent1)); + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); + } } else mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); } @@ -1200,6 +1262,8 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) } karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); + karg.driver_capability |= MPT3_IOCTL_IOCINFO_DRIVER_CAP_MCTP_PASSTHRU; + if (copy_to_user(arg, &karg, sizeof(karg))) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -1267,8 +1331,8 @@ _ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg) /* initialize event_log */ ioc->event_context = 0; ioc->aen_event_read_flag = 0; - ioc->event_log = kcalloc(MPT3SAS_CTL_EVENT_LOG_SIZE, - sizeof(struct MPT3_IOCTL_EVENTS), GFP_KERNEL); + ioc->event_log = kzalloc_objs(struct MPT3_IOCTL_EVENTS, + MPT3SAS_CTL_EVENT_LOG_SIZE); if (!ioc->event_log) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -2787,6 +2851,215 @@ out_unlock_pciaccess: } /** + * _ctl_get_mpt_mctp_passthru_adapter - Traverse the IOC list and return the IOC at + * dev_index positionthat support MCTP passhtru + * @dev_index: position in the mpt3sas_ioc_list to search for + * Return pointer to the IOC on success + * NULL if device not found error + */ +static struct MPT3SAS_ADAPTER * +_ctl_get_mpt_mctp_passthru_adapter(int dev_index) +{ + struct MPT3SAS_ADAPTER *ioc = NULL; + int count = 0; + + spin_lock(&gioc_lock); + /* Traverse ioc list and return number of IOC that support MCTP passthru */ + list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { + if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { + if (count == dev_index) { + spin_unlock(&gioc_lock); + return ioc; + } + count++; + } + } + spin_unlock(&gioc_lock); + + return NULL; +} + +/** + * mpt3sas_get_device_count - Retrieve the count of MCTP passthrough + * capable devices managed by the driver. + * + * Returns number of devices that support MCTP passthrough. + */ +int +mpt3sas_get_device_count(void) +{ + int count = 0; + struct MPT3SAS_ADAPTER *ioc = NULL; + + spin_lock(&gioc_lock); + /* Traverse ioc list and return number of IOC that support MCTP passthru */ + list_for_each_entry(ioc, &mpt3sas_ioc_list, list) + if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) + count++; + + spin_unlock(&gioc_lock); + + return count; +} +EXPORT_SYMBOL(mpt3sas_get_device_count); + +/** + * mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to + * firmware + * @command: The MPI MCTP passthrough command to send to firmware + * + * Returns 0 on success, anything else is error. + */ +int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command) +{ + struct MPT3SAS_ADAPTER *ioc; + MPI2RequestHeader_t *mpi_request = NULL, *request; + Mpi26MctpPassthroughRequest_t *mctp_passthru_req; + u16 smid; + unsigned long timeout; + u8 issue_reset = 0; + u32 sz; + void *psge; + void *data_out = NULL; + dma_addr_t data_out_dma = 0; + size_t data_out_sz = 0; + void *data_in = NULL; + dma_addr_t data_in_dma = 0; + size_t data_in_sz = 0; + long ret; + + /* Retrieve ioc from dev_index */ + ioc = _ctl_get_mpt_mctp_passthru_adapter(command->dev_index); + if (!ioc) + return -ENODEV; + + mutex_lock(&ioc->pci_access_mutex); + if (ioc->shost_recovery || + ioc->pci_error_recovery || ioc->is_driver_loading || + ioc->remove_host) { + ret = -EAGAIN; + goto unlock_pci_access; + } + + /* Lock the ctl_cmds mutex to ensure a single ctl cmd is pending */ + if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { + ret = -ERESTARTSYS; + goto unlock_pci_access; + } + + if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); + ret = -EAGAIN; + goto unlock_ctl_cmds; + } + + ret = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT); + if (ret) + goto unlock_ctl_cmds; + + mpi_request = (MPI2RequestHeader_t *)command->mpi_request; + if (mpi_request->Function != MPI2_FUNCTION_MCTP_PASSTHROUGH) { + ioc_err(ioc, "%s: Invalid request received, Function 0x%x\n", + __func__, mpi_request->Function); + ret = -EINVAL; + goto unlock_ctl_cmds; + } + + /* Use first reserved smid for passthrough commands */ + smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; + ret = 0; + ioc->ctl_cmds.status = MPT3_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + request = mpt3sas_base_get_msg_frame(ioc, smid); + memset(request, 0, ioc->request_sz); + memcpy(request, command->mpi_request, sizeof(Mpi26MctpPassthroughRequest_t)); + ioc->ctl_cmds.smid = smid; + data_out_sz = command->data_out_size; + data_in_sz = command->data_in_size; + + /* obtain dma-able memory for data transfer */ + if (data_out_sz) /* WRITE */ { + data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz, + &data_out_dma, GFP_ATOMIC); + if (!data_out) { + ret = -ENOMEM; + mpt3sas_base_free_smid(ioc, smid); + goto out; + } + memcpy(data_out, command->data_out_buf_ptr, data_out_sz); + + } + + if (data_in_sz) /* READ */ { + data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz, + &data_in_dma, GFP_ATOMIC); + if (!data_in) { + ret = -ENOMEM; + mpt3sas_base_free_smid(ioc, smid); + goto out; + } + } + + psge = &((Mpi26MctpPassthroughRequest_t *)request)->H2DSGL; + + init_completion(&ioc->ctl_cmds.done); + + mctp_passthru_req = (Mpi26MctpPassthroughRequest_t *)request; + + _ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma, + data_out_sz, data_in_dma, data_in_sz, smid); + + timeout = command->timeout; + if (timeout < MPT3_IOCTL_DEFAULT_TIMEOUT) + timeout = MPT3_IOCTL_DEFAULT_TIMEOUT; + + wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ); + if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { + mpt3sas_check_cmd_timeout(ioc, + ioc->ctl_cmds.status, mpi_request, + sizeof(Mpi26MctpPassthroughRequest_t) / 4, issue_reset); + goto issue_host_reset; + } + + /* copy out xdata to user */ + if (data_in_sz) + memcpy(command->data_in_buf_ptr, data_in, data_in_sz); + + /* copy out reply message frame to user */ + if (command->max_reply_bytes) { + sz = min_t(u32, command->max_reply_bytes, ioc->reply_sz); + memcpy(command->reply_frame_buf_ptr, ioc->ctl_cmds.reply, sz); + } + +issue_host_reset: + if (issue_reset) { + ret = -ENODATA; + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); + } + +out: + /* free memory associated with sg buffers */ + if (data_in) + dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in, + data_in_dma); + + if (data_out) + dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out, + data_out_dma); + + ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; + +unlock_ctl_cmds: + mutex_unlock(&ioc->ctl_cmds.mutex); + +unlock_pci_access: + mutex_unlock(&ioc->pci_access_mutex); + return ret; + +} +EXPORT_SYMBOL(mpt3sas_send_mctp_passthru_req); + +/** * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked) * @file: (struct file) * @cmd: ioctl opcode @@ -3608,8 +3881,7 @@ diag_trigger_master_store(struct device *cdev, rc = min(sizeof(struct SL_WH_MASTER_TRIGGER_T), count); if (ioc->supports_trigger_pages) { - master_tg = kzalloc(sizeof(struct SL_WH_MASTER_TRIGGER_T), - GFP_KERNEL); + master_tg = kzalloc_obj(struct SL_WH_MASTER_TRIGGER_T); if (!master_tg) return -ENOMEM; @@ -3683,8 +3955,7 @@ diag_trigger_event_store(struct device *cdev, sz = min(sizeof(struct SL_WH_EVENT_TRIGGERS_T), count); if (ioc->supports_trigger_pages) { - event_tg = kzalloc(sizeof(struct SL_WH_EVENT_TRIGGERS_T), - GFP_KERNEL); + event_tg = kzalloc_obj(struct SL_WH_EVENT_TRIGGERS_T); if (!event_tg) return -ENOMEM; @@ -3758,8 +4029,7 @@ diag_trigger_scsi_store(struct device *cdev, sz = min(sizeof(struct SL_WH_SCSI_TRIGGERS_T), count); if (ioc->supports_trigger_pages) { - scsi_tg = kzalloc(sizeof(struct SL_WH_SCSI_TRIGGERS_T), - GFP_KERNEL); + scsi_tg = kzalloc_obj(struct SL_WH_SCSI_TRIGGERS_T); if (!scsi_tg) return -ENOMEM; @@ -3832,8 +4102,7 @@ diag_trigger_mpi_store(struct device *cdev, sz = min(sizeof(struct SL_WH_MPI_TRIGGERS_T), count); if (ioc->supports_trigger_pages) { - mpi_tg = kzalloc(sizeof(struct SL_WH_MPI_TRIGGERS_T), - GFP_KERNEL); + mpi_tg = kzalloc_obj(struct SL_WH_MPI_TRIGGERS_T); if (!mpi_tg) return -ENOMEM; diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index 171709e91006..483e0549c02f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -160,6 +160,9 @@ struct mpt3_ioctl_pci_info { #define MPT3_IOCTL_INTERFACE_SAS35 (0x07) #define MPT2_IOCTL_VERSION_LENGTH (32) +/* Bits set for mpt3_ioctl_iocinfo.driver_cap */ +#define MPT3_IOCTL_IOCINFO_DRIVER_CAP_MCTP_PASSTHRU 0x1 + /** * struct mpt3_ioctl_iocinfo - generic controller info * @hdr - generic header @@ -175,6 +178,7 @@ struct mpt3_ioctl_pci_info { * @driver_version - driver version - 32 ASCII characters * @rsvd1 - reserved * @scsi_id - scsi id of adapter 0 + * @driver_capability - driver capabilities * @rsvd2 - reserved * @pci_information - pci info (2nd revision) */ @@ -192,7 +196,8 @@ struct mpt3_ioctl_iocinfo { uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; uint8_t rsvd1; uint8_t scsi_id; - uint16_t rsvd2; + uint8_t driver_capability; + uint8_t rsvd2; struct mpt3_ioctl_pci_info pci_information; }; @@ -458,4 +463,46 @@ struct mpt3_enable_diag_sbr_reload { struct mpt3_ioctl_header hdr; }; +/** + * struct mpt3_passthru_command - generic mpt firmware passthru command + * @dev_index - device index + * @timeout - command timeout in seconds. (if zero then use driver default + * value). + * @reply_frame_buf_ptr - MPI reply location + * @data_in_buf_ptr - destination for read + * @data_out_buf_ptr - data source for write + * @max_reply_bytes - maximum number of reply bytes to be sent to app. + * @data_in_size - number bytes for data transfer in (read) + * @data_out_size - number bytes for data transfer out (write) + * @mpi_request - request frame + */ +struct mpt3_passthru_command { + u8 dev_index; + uint32_t timeout; + void *reply_frame_buf_ptr; + void *data_in_buf_ptr; + void *data_out_buf_ptr; + uint32_t max_reply_bytes; + uint32_t data_in_size; + uint32_t data_out_size; + Mpi26MctpPassthroughRequest_t *mpi_request; +}; + +/* + * mpt3sas_get_device_count - Retrieve the count of MCTP passthrough + * capable devices managed by the driver. + * + * Returns number of devices that support MCTP passthrough. + */ +int mpt3sas_get_device_count(void); + +/* + * mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to + * firmware + * @command: The MPI MCTP passthrough command to send to firmware + * + * Returns 0 on success, anything else is error . + */ +int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command); + #endif /* MPT3SAS_CTL_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_debugfs.c b/drivers/scsi/mpt3sas/mpt3sas_debugfs.c index a6ab1db81167..183391f6b8d1 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_debugfs.c +++ b/drivers/scsi/mpt3sas/mpt3sas_debugfs.c @@ -58,7 +58,7 @@ _debugfs_iocdump_open(struct inode *inode, struct file *file) struct MPT3SAS_ADAPTER *ioc = inode->i_private; struct mpt3sas_debugfs_buffer *debug; - debug = kzalloc(sizeof(struct mpt3sas_debugfs_buffer), GFP_KERNEL); + debug = kzalloc_obj(struct mpt3sas_debugfs_buffer); if (!debug) return -ENOMEM; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index a456e5ec74d8..12caffeed3a0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -61,6 +61,8 @@ #define PCIE_CHANNEL 2 +#define MPT3_MAX_LUNS (255) + /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander); @@ -70,13 +72,24 @@ static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device); static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd); -static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); +static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count); static void _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device); static void _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); static void _scsih_complete_devices_scanning(struct MPT3SAS_ADAPTER *ioc); +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 *is_ssd_device, + u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method); +static void _firmware_event_work_delayed(struct work_struct *work); /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); @@ -159,6 +172,15 @@ module_param(enable_sdev_max_qd, bool, 0444); MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue, def=disabled(0)"); +/* + * permit overriding the SCSI command issuing capability of + * the driver to bring the drive to READY state + */ +static int issue_scsi_cmd_to_bringup_drive = 1; +module_param(issue_scsi_cmd_to_bringup_drive, int, 0444); +MODULE_PARM_DESC(issue_scsi_cmd_to_bringup_drive, "allow host driver to\n" + "issue SCSI commands to bring the drive to READY state, default=1 "); + static int multipath_on_hba = -1; module_param(multipath_on_hba, int, 0); MODULE_PARM_DESC(multipath_on_hba, @@ -173,10 +195,33 @@ module_param(host_tagset_enable, int, 0444); MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); +static int command_retry_count = 144; +module_param(command_retry_count, int, 0444); +MODULE_PARM_DESC(command_retry_count, "Device discovery TUR command retry\n" + "count: (default=144)"); + /* raid transport support */ static struct raid_template *mpt3sas_raid_template; static struct raid_template *mpt2sas_raid_template; +/** + * enum device_responsive_state - responsive state + * @DEVICE_READY: device is ready to be added + * @DEVICE_RETRY: device can be retried later + * @DEVICE_RETRY_UA: retry unit attentions + * @DEVICE_START_UNIT: requires start unit + * @DEVICE_STOP_UNIT: requires stop unit + * @DEVICE_ERROR: device reported some fatal error + * + */ +enum device_responsive_state { + DEVICE_READY, + DEVICE_RETRY, + DEVICE_RETRY_UA, + DEVICE_START_UNIT, + DEVICE_STOP_UNIT, + DEVICE_ERROR, +}; /** * struct sense_info - common structure for obtaining sense keys @@ -195,8 +240,19 @@ struct sense_info { #define MPT3SAS_PORT_ENABLE_COMPLETE (0xFFFD) #define MPT3SAS_ABRT_TASK_SET (0xFFFE) #define MPT3SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) + +/* + * SAS Log info code for a NCQ collateral abort after an NCQ error: + * IOC_LOGINFO_PREFIX_PL | PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR + * See: drivers/message/fusion/lsi/mpi_log_sas.h + */ +#define IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR 0x31080000 + /** * struct fw_event_work - firmware event struct + * @retries: retry count for processing the event + * @delayed_work_active: flag indicating if delayed work is active + * @delayed_work: delayed work item for deferred event handling * @list: link list framework * @work: work object (ioc->fault_reset_work_q) * @ioc: per adapter object @@ -211,6 +267,9 @@ struct sense_info { * This object stored on ioc->fw_event_list. */ struct fw_event_work { + u8 *retries; + u8 delayed_work_active; + struct delayed_work delayed_work; struct list_head list; struct work_struct work; @@ -222,11 +281,16 @@ struct fw_event_work { u16 event; struct kref refcount; char event_data[] __aligned(4); + }; static void fw_event_work_free(struct kref *r) { - kfree(container_of(r, struct fw_event_work, refcount)); + struct fw_event_work *fw_work; + + fw_work = container_of(r, struct fw_event_work, refcount); + kfree(fw_work->retries); + kfree(fw_work); } static void fw_event_work_get(struct fw_event_work *fw_work) @@ -412,7 +476,7 @@ mpt3sas_get_port_by_id(struct MPT3SAS_ADAPTER *ioc, * And add this object to port_table_list. */ if (!ioc->multipath_on_hba) { - port = kzalloc(sizeof(struct hba_port), GFP_ATOMIC); + port = kzalloc_obj(struct hba_port, GFP_ATOMIC); if (!port) return NULL; @@ -947,6 +1011,7 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } /** @@ -1875,8 +1940,7 @@ scsih_target_alloc(struct scsi_target *starget) unsigned long flags; struct sas_rphy *rphy; - sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data), - GFP_KERNEL); + sas_target_priv_data = kzalloc_obj(*sas_target_priv_data); if (!sas_target_priv_data) return -ENOMEM; @@ -2044,8 +2108,7 @@ scsih_sdev_init(struct scsi_device *sdev) struct _pcie_device *pcie_device; unsigned long flags; - sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data), - GFP_KERNEL); + sas_device_priv_data = kzalloc_obj(*sas_device_priv_data); if (!sas_device_priv_data) return -ENOMEM; @@ -2520,6 +2583,8 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) char *r_level = ""; u16 handle, volume_handle = 0; u64 volume_wwid = 0; + enum device_responsive_state retval; + u8 count = 0; qdepth = 1; sas_device_priv_data = sdev->hostdata; @@ -2673,11 +2738,24 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) pcie_device->enclosure_level, pcie_device->connector_name); + /* + * The HBA firmware passes the NVMe drive's MDTS + * (Maximum Data Transfer Size) up to the driver. However, + * the driver hardcodes a 4K buffer size for the PRP list, + * accommodating at most 512 entries. This strictly limits + * the maximum supported NVMe I/O transfer to 2 MiB. + * + * Cap max_hw_sectors to the smaller of the drive's reported + * MDTS or the 2 MiB driver limit to prevent kernel oopses. + */ + lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT; if (pcie_device->nvme_mdts) - lim->max_hw_sectors = pcie_device->nvme_mdts / 512; + lim->max_hw_sectors = min(lim->max_hw_sectors, + pcie_device->nvme_mdts >> SECTOR_SHIFT); pcie_device_put(pcie_device); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); lim->virt_boundary_mask = ioc->page_size - 1; return 0; @@ -2703,7 +2781,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) ssp_target = 1; if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SEP) { - sdev_printk(KERN_WARNING, sdev, + sdev_printk(KERN_INFO, sdev, "set ignore_delay_remove for handle(0x%04x)\n", sas_device_priv_data->sas_target->handle); sas_device_priv_data->ignore_delay_remove = 1; @@ -2729,9 +2807,16 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!ssp_target) + if (!ssp_target) { _scsih_display_sata_capabilities(ioc, handle, sdev); + do { + retval = _scsih_ata_pass_thru_idd(ioc, handle, + &sas_device->ssd_device, 30, 0); + } while ((retval == DEVICE_RETRY || retval == DEVICE_RETRY_UA) + && count++ < 3); + } + mpt3sas_scsih_change_queue_depth(sdev, qdepth); @@ -2746,7 +2831,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) /** * scsih_bios_param - fetch head, sector, cylinder info for a disk * @sdev: scsi device struct - * @bdev: pointer to block device context + * @unused: pointer to gendisk * @capacity: device size (in 512 byte sectors) * @params: three element array to place output: * params[0] number of heads (max 255) @@ -2754,7 +2839,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * params[2] number of cylinders */ static int -scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, +scsih_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int params[]) { int heads; @@ -3587,6 +3672,37 @@ _scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } +/** + * _scsih_fw_event_requeue - requeue an event + * @ioc: per adapter object + * @fw_event: object describing the event + * @delay: time in milliseconds to wait before retrying the event + * + * Context: This function will acquire ioc->fw_event_lock. + * + * Return nothing. + */ +static void +_scsih_fw_event_requeue(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work + *fw_event, unsigned long delay) +{ + unsigned long flags; + + if (ioc->firmware_event_thread == NULL) + return; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + if (!fw_event->delayed_work_active) { + fw_event->delayed_work_active = 1; + INIT_DELAYED_WORK(&fw_event->delayed_work, + _firmware_event_work_delayed); + } + queue_delayed_work(ioc->firmware_event_thread, &fw_event->delayed_work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} /** * mpt3sas_send_trigger_data_event - send event for processing trigger data @@ -3817,29 +3933,235 @@ _scsih_internal_device_unblock(struct scsi_device *sdev, /** * _scsih_ublock_io_all_device - unblock every device * @ioc: per adapter object + * @no_turs: flag to disable TEST UNIT READY checks during device unblocking * * change the device state from block to running */ static void -_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) +_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; + int count = 0; + u8 tr_method = 0; + u8 tr_timeout = 30; + shost_for_each_device(sdev, ioc->shost) { sas_device_priv_data = sdev->hostdata; if (!sas_device_priv_data) continue; + + sas_target = sas_device_priv_data->sas_target; + if (!sas_target || sas_target->deleted) + continue; + if (!sas_device_priv_data->block) continue; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - "device_running, handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); + if ((no_turs) || (!issue_scsi_cmd_to_bringup_drive)) { + sdev_printk(KERN_WARNING, sdev, "device_unblocked handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + continue; + } + + do { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { + tr_timeout = pcie_device->reset_timeout; + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + ssleep(1); + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ < command_retry_count); + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, "%s: device_offlined,\n" + "handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + scsi_device_set_state(sdev, SDEV_OFFLINE); + sas_device = mpt3sas_get_sdev_by_addr(ioc, + sas_device_priv_data->sas_target->sas_address, + sas_device_priv_data->sas_target->port); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_wwid(ioc, + sas_device_priv_data->sas_target->sas_address); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, "enclosure logical id\n" + "(0x%016llx), slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, "enclosure level(0x%04x),\n" + " connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + } else + sdev_printk(KERN_WARNING, sdev, "device_unblocked,\n" + "handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); } } +/** + * _scsih_ublock_io_device_wait - unblock IO for target + * @ioc: per adapter object + * @sas_address: sas address + * @port: hba port entry + * + * make sure device is reponsponding before unblocking + */ +static void +_scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port) +{ + struct MPT3SAS_DEVICE *sas_device_priv_data; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct scsi_device *sdev; + int host_reset_completion_count; + struct _sas_device *sas_device; + struct _pcie_device *pcie_device; + u8 tr_timeout = 30; + u8 tr_method = 0; + int count = 0; + + /* moving devices from SDEV_OFFLINE to SDEV_BLOCK */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (sdev->sdev_state == SDEV_OFFLINE) { + sas_device_priv_data->block = 1; + sas_device_priv_data->deleted = 0; + scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_internal_device_block_nowait(sdev); + } + } + + /* moving devices from SDEV_BLOCK to SDEV_RUNNING state */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (!sas_device_priv_data->block) + continue; + + do { + host_reset_completion_count = 0; + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { + tr_timeout = pcie_device->reset_timeout; + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) { + do { + msleep(500); + host_reset_completion_count++; + } while (rc == DEVICE_RETRY && + ioc->shost_recovery); + if (host_reset_completion_count > 1) { + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, + tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + msleep(500); + } + continue; + } + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ <= command_retry_count); + + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, + "%s: device_offlined, handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + + sas_device = mpt3sas_get_sdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "device_offlined, enclosure logical id(0x%016llx),\n" + " slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_WARNING, sdev, + "device_offlined, enclosure level(0x%04x),\n" + "connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + scsi_device_set_state(sdev, SDEV_OFFLINE); + } else { + sdev_printk(KERN_WARNING, sdev, + "device_unblocked, handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + } + } +} /** * _scsih_ublock_io_device - prepare device to be deleted @@ -4158,7 +4480,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + delayed_tr = kzalloc_obj(*delayed_tr, GFP_ATOMIC); if (!delayed_tr) goto out; INIT_LIST_HEAD(&delayed_tr->list); @@ -4256,7 +4578,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); if (!smid_sas_ctrl) { - delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC); + delayed_sc = kzalloc_obj(*delayed_sc, GFP_ATOMIC); if (!delayed_sc) return _scsih_check_for_pending_tm(ioc, smid); INIT_LIST_HEAD(&delayed_sc->list); @@ -4382,7 +4704,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + delayed_tr = kzalloc_obj(*delayed_tr, GFP_ATOMIC); if (!delayed_tr) return; INIT_LIST_HEAD(&delayed_tr->list); @@ -4903,7 +5225,7 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, if (!volume_handle) _scsih_tm_tr_send(ioc, handle); else if (volume_handle == a || volume_handle == b) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + delayed_tr = kzalloc_obj(*delayed_tr, GFP_ATOMIC); BUG_ON(!delayed_tr); INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; @@ -5110,8 +5432,8 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ -static int -scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status scsih_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct MPT3SAS_DEVICE *sas_device_priv_data; @@ -5814,6 +6136,17 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_TRANSPORT_DISRUPTED << 16; goto out; } + if (log_info == IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR) { + /* + * This is a ATA NCQ command aborted due to another NCQ + * command failure. We must retry this command + * immediately but without incrementing its retry + * counter. + */ + WARN_ON_ONCE(xfer_cnt != 0); + scmd->result = DID_IMM_RETRY << 16; + break; + } if (log_info == 0x31110630) { if (scmd->retries > 2) { scmd->result = DID_NO_CONNECT << 16; @@ -6055,8 +6388,7 @@ _scsih_update_vphys_after_reset(struct MPT3SAS_ADAPTER *ioc) port_id = sas_iounit_pg0->PhyData[i].Port; mport = mpt3sas_get_port_by_id(ioc, port_id, 1); if (!mport) { - mport = kzalloc( - sizeof(struct hba_port), GFP_KERNEL); + mport = kzalloc_obj(struct hba_port); if (!mport) break; mport->port_id = port_id; @@ -6426,8 +6758,7 @@ _scsih_sas_port_refresh(struct MPT3SAS_ADAPTER *ioc) } ioc->sas_hba.num_phys = num_phys; - port_table = kcalloc(ioc->sas_hba.num_phys, - sizeof(struct hba_port), GFP_KERNEL); + port_table = kzalloc_objs(struct hba_port, ioc->sas_hba.num_phys); if (!port_table) return; @@ -6518,7 +6849,7 @@ _scsih_alloc_vphy(struct MPT3SAS_ADAPTER *ioc, u8 port_id, u8 phy_num) vphy = mpt3sas_get_vphy_by_phy(ioc, port, phy_num); if (!vphy) { - vphy = kzalloc(sizeof(struct virtual_phy), GFP_KERNEL); + vphy = kzalloc_obj(struct virtual_phy); if (!vphy) return NULL; @@ -6588,7 +6919,7 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) sas_iounit_pg0->PhyData[0].ControllerDevHandle); port_id = sas_iounit_pg0->PhyData[i].Port; if (!(mpt3sas_get_port_by_id(ioc, port_id, 0))) { - port = kzalloc(sizeof(struct hba_port), GFP_KERNEL); + port = kzalloc_obj(struct hba_port); if (!port) goto out; @@ -6708,8 +7039,8 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) ioc->sas_hba.nr_phys_allocated = max_t(u8, MPT_MAX_HBA_NUM_PHYS, num_phys); - ioc->sas_hba.phy = kcalloc(ioc->sas_hba.nr_phys_allocated, - sizeof(struct _sas_phy), GFP_KERNEL); + ioc->sas_hba.phy = kzalloc_objs(struct _sas_phy, + ioc->sas_hba.nr_phys_allocated); if (!ioc->sas_hba.phy) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -6794,7 +7125,7 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) port_id = sas_iounit_pg0->PhyData[i].Port; if (!(mpt3sas_get_port_by_id(ioc, port_id, 0))) { - port = kzalloc(sizeof(struct hba_port), GFP_KERNEL); + port = kzalloc_obj(struct hba_port); if (!port) goto out; @@ -6935,8 +7266,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (sas_expander) return 0; - sas_expander = kzalloc(sizeof(struct _sas_node), - GFP_KERNEL); + sas_expander = kzalloc_obj(struct _sas_node); if (!sas_expander) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -6963,8 +7293,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) rc = -1; goto out_fail; } - sas_expander->phy = kcalloc(sas_expander->num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); + sas_expander->phy = kzalloc_objs(struct _sas_phy, + sas_expander->num_phys); if (!sas_expander->phy) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -7089,10 +7419,769 @@ _scsih_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) return 1; } +/** + * _scsi_send_scsi_io - send internal SCSI_IO to target + * @ioc: per adapter object + * @transfer_packet: packet describing the transfer + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns 0 for success, non-zero for failure. + */ +static int +_scsi_send_scsi_io(struct MPT3SAS_ADAPTER *ioc, struct _scsi_io_transfer + *transfer_packet, u8 tr_timeout, u8 tr_method) +{ + Mpi2SCSIIOReply_t *mpi_reply; + Mpi2SCSIIORequest_t *mpi_request; + u16 smid; + u8 issue_reset = 0; + int rc; + void *priv_sense; + u32 mpi_control; + void *psge; + dma_addr_t data_out_dma = 0; + dma_addr_t data_in_dma = 0; + size_t data_in_sz = 0; + size_t data_out_sz = 0; + u16 handle; + u8 retry_count = 0, host_reset_count = 0; + int tm_return_code; + if (ioc->pci_error_recovery) { + pr_info("%s: pci error recovery in progress!\n", __func__); + return -EFAULT; + } + if (ioc->shost_recovery) { + pr_info("%s: host recovery in progress!\n", __func__); + return -EAGAIN; + } -#define MPT3_MAX_LUNS (255) + handle = transfer_packet->handle; + if (handle == MPT3SAS_INVALID_DEVICE_HANDLE) { + pr_info("%s: no device!\n", __func__); + return -EFAULT; + } + + mutex_lock(&ioc->scsih_cmds.mutex); + + if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { + pr_err("%s: scsih_cmd in use\n", __func__); + rc = -EAGAIN; + goto out; + } + + retry_loop: + if (test_bit(handle, ioc->device_remove_in_progress)) { + pr_info("%s: device removal in progress\n", __func__); + rc = -EFAULT; + goto out; + } + + ioc->scsih_cmds.status = MPT3_CMD_PENDING; + + rc = mpt3sas_wait_for_ioc(ioc, 10); + if (rc) + goto out; + + /* Use second reserved smid for discovery related IOs */ + smid = ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; + + rc = 0; + mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + if (transfer_packet->is_raid) + mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; + else + mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + mpi_request->DevHandle = cpu_to_le16(handle); + + switch (transfer_packet->dir) { + case DMA_TO_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_WRITE; + data_out_dma = transfer_packet->data_dma; + data_out_sz = transfer_packet->data_length; + break; + case DMA_FROM_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_READ; + data_in_dma = transfer_packet->data_dma; + data_in_sz = transfer_packet->data_length; + break; + case DMA_BIDIRECTIONAL: + mpi_control = MPI2_SCSIIO_CONTROL_BIDIRECTIONAL; + /* TODO - is BIDI support needed ?? */ + WARN_ON_ONCE(true); + break; + default: + case DMA_NONE: + mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; + break; + } + + psge = &mpi_request->SGL; + ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, + data_in_sz); + + mpi_request->Control = cpu_to_le32(mpi_control | + MPI2_SCSIIO_CONTROL_SIMPLEQ); + mpi_request->DataLength = cpu_to_le32(transfer_packet->data_length); + mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; + mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; + mpi_request->SenseBufferLowAddress = + mpt3sas_base_get_sense_buffer_dma(ioc, smid); + priv_sense = mpt3sas_base_get_sense_buffer(ioc, smid); + mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; + mpi_request->IoFlags = cpu_to_le16(transfer_packet->cdb_length); + int_to_scsilun(transfer_packet->lun, (struct scsi_lun *) + mpi_request->LUN); + memcpy(mpi_request->CDB.CDB32, transfer_packet->cdb, + transfer_packet->cdb_length); + init_completion(&ioc->scsih_cmds.done); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) + ioc->put_smid_scsi_io(ioc, smid, handle); + else + ioc->put_smid_default(ioc, smid); + wait_for_completion_timeout(&ioc->scsih_cmds.done, + transfer_packet->timeout*HZ); + if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { + mpt3sas_check_cmd_timeout(ioc, + ioc->scsih_cmds.status, mpi_request, + sizeof(Mpi2SCSIIORequest_t)/4, issue_reset); + goto issue_target_reset; + } + if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { + transfer_packet->valid_reply = 1; + mpi_reply = ioc->scsih_cmds.reply; + transfer_packet->sense_length = + le32_to_cpu(mpi_reply->SenseCount); + if (transfer_packet->sense_length) + memcpy(transfer_packet->sense, priv_sense, + transfer_packet->sense_length); + transfer_packet->transfer_length = + le32_to_cpu(mpi_reply->TransferCount); + transfer_packet->ioc_status = + le16_to_cpu(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + transfer_packet->scsi_state = mpi_reply->SCSIState; + transfer_packet->scsi_status = mpi_reply->SCSIStatus; + transfer_packet->log_info = + le32_to_cpu(mpi_reply->IOCLogInfo); + } + goto out; + + issue_target_reset: + if (issue_reset) { + pr_info("issue target reset: handle (0x%04x)\n", handle); + tm_return_code = + mpt3sas_scsih_issue_locked_tm(ioc, handle, + 0xFFFFFFFF, 0xFFFFFFFF, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, smid, 0, + tr_timeout, tr_method); + + if (tm_return_code == SUCCESS) { + pr_info("target reset completed: handle (0x%04x)\n", handle); + /* If the command is successfully aborted due to + * target reset TM then do up to three retries else + * command will be terminated by the host reset TM and + * hence retry once. + */ + if (((ioc->scsih_cmds.status & MPT3_CMD_COMPLETE) && + retry_count++ < 3) || + ((ioc->scsih_cmds.status & MPT3_CMD_RESET) && + host_reset_count++ == 0)) { + pr_info("issue retry: handle (0x%04x)\n", handle); + goto retry_loop; + } + } else + pr_info("target reset didn't complete: handle(0x%04x)\n", handle); + rc = -EFAULT; + } else + rc = -EAGAIN; + + out: + ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; + mutex_unlock(&ioc->scsih_cmds.mutex); + return rc; +} + +/** + * _scsih_determine_disposition - + * @ioc: per adapter object + * @transfer_packet: packet describing the transfer + * Context: user + * + * Determines if an internal generated scsi_io is good data, or + * whether it needs to be retried or treated as an error. + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_determine_disposition(struct MPT3SAS_ADAPTER *ioc, + struct _scsi_io_transfer *transfer_packet) +{ + static enum device_responsive_state rc; + struct sense_info sense_info = {0, 0, 0}; + u8 check_sense = 0; + char *desc = NULL; + + if (!transfer_packet->valid_reply) + return DEVICE_READY; + + switch (transfer_packet->ioc_status) { + case MPI2_IOCSTATUS_BUSY: + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + if (transfer_packet->log_info == 0x31170000) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->cdb[0] == REPORT_LUNS) + rc = DEVICE_READY; + else + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI2_IOCSTATUS_SUCCESS: + if (!transfer_packet->scsi_state && + !transfer_packet->scsi_status) { + rc = DEVICE_READY; + break; + } + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + rc = DEVICE_ERROR; + check_sense = 1; + break; + } + if (transfer_packet->scsi_state & + (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS | + MPI2_SCSI_STATE_TERMINATED)) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->scsi_status >= + MPI2_SCSI_STATUS_BUSY) { + rc = DEVICE_RETRY; + break; + } + rc = DEVICE_READY; + break; + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_TERMINATED) + rc = DEVICE_RETRY; + else + rc = DEVICE_ERROR; + break; + case MPI2_IOCSTATUS_INSUFFICIENT_POWER: + default: + rc = DEVICE_ERROR; + break; + } + + if (check_sense) { + _scsih_normalize_sense(transfer_packet->sense, &sense_info); + if (sense_info.skey == UNIT_ATTENTION) + rc = DEVICE_RETRY_UA; + else if (sense_info.skey == NOT_READY) { + /* medium isn't present */ + if (sense_info.asc == 0x3a) + rc = DEVICE_READY; + /* LOGICAL UNIT NOT READY */ + else if (sense_info.asc == 0x04) { + if (sense_info.ascq == 0x03 || + sense_info.ascq == 0x0b || + sense_info.ascq == 0x0c) { + rc = DEVICE_ERROR; + } else + rc = DEVICE_START_UNIT; + } + /* LOGICAL UNIT HAS NOT SELF-CONFIGURED YET */ + else if (sense_info.asc == 0x3e && !sense_info.ascq) + rc = DEVICE_START_UNIT; + } else if (sense_info.skey == ILLEGAL_REQUEST && + transfer_packet->cdb[0] == REPORT_LUNS) { + rc = DEVICE_READY; + } else if (sense_info.skey == MEDIUM_ERROR) { + + /* medium is corrupt, lets add the device so + * users can collect some info as needed + */ + + if (sense_info.asc == 0x31) + rc = DEVICE_READY; + } else if (sense_info.skey == HARDWARE_ERROR) { + /* Defect List Error, still add the device */ + if (sense_info.asc == 0x19) + rc = DEVICE_READY; + } + } + + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { + switch (rc) { + case DEVICE_READY: + desc = "ready"; + break; + case DEVICE_RETRY: + desc = "retry"; + break; + case DEVICE_RETRY_UA: + desc = "retry_ua"; + break; + case DEVICE_START_UNIT: + desc = "start_unit"; + break; + case DEVICE_STOP_UNIT: + desc = "stop_unit"; + break; + case DEVICE_ERROR: + desc = "error"; + break; + } + + pr_info("ioc_status(0x%04x),\n" + "loginfo(0x%08x), scsi_status(0x%02x),\n" + "scsi_state(0x%02x), rc(%s)\n", + transfer_packet->ioc_status, + transfer_packet->log_info, transfer_packet->scsi_status, + transfer_packet->scsi_state, desc); + + if (check_sense) + pr_info("\t[sense_key,asc,ascq]:\n" + "[0x%02x,0x%02x,0x%02x]\n", + sense_info.skey, sense_info.asc, sense_info.ascq); + } + return rc; +} + +/** + * _scsih_report_luns - send REPORT_LUNS to target + * @ioc: per adapter object + * @handle: expander handle + * @data: report luns data payload + * @data_length: length of data in bytes + * @retry_count: Requeue count + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_report_luns(struct MPT3SAS_ADAPTER *ioc, u16 handle, void *data, + u32 data_length, u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + void *lun_data; + int return_code; + int retries; + + lun_data = NULL; + transfer_packet = kzalloc_obj(struct _scsi_io_transfer); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + lun_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + for (retries = 0; retries < 4; retries++) { + rc = DEVICE_ERROR; + ioc_info(ioc, "REPORT_LUNS: handle(0x%04x),\n" + "retries(%d)\n", handle, retries); + memset(lun_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = REPORT_LUNS; + transfer_packet->cdb[6] = (data_length >> 24) & 0xFF; + transfer_packet->cdb[7] = (data_length >> 16) & 0xFF; + transfer_packet->cdb[8] = (data_length >> 8) & 0xFF; + transfer_packet->cdb[9] = data_length & 0xFF; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + memcpy(data, lun_data, data_length); + goto out; + } else if (rc == DEVICE_ERROR) + goto out; + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + goto out; + } + } + out: + + if (lun_data) + dma_free_coherent(&ioc->pdev->dev, data_length, lun_data, + transfer_packet->data_dma); + kfree(transfer_packet); + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) + rc = DEVICE_ERROR; + + return rc; +} + +/** + * _scsih_start_unit - send START_UNIT to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_start_unit(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, u8 is_pd, + u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + + transfer_packet = kzalloc_obj(struct _scsi_io_transfer); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = START_STOP; + transfer_packet->cdb[1] = 1; + transfer_packet->cdb[4] = 1; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + pr_info("START_UNIT: handle(0x%04x), lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_test_unit_ready - send TUR to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value for Pcie devie + * @tr_method: pcie device Target reset method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_test_unit_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, + u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + int sata_init_failure = 0; + + transfer_packet = kzalloc_obj(struct _scsi_io_transfer); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = TEST_UNIT_READY; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + sata_init_retry: + pr_info("TEST_UNIT_READY: handle(0x%04x) lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_RETRY && + transfer_packet->log_info == 0x31111000) { + if (!sata_init_failure++) { + pr_info("SATA Initialization Timeout sending a retry\n"); + rc = DEVICE_READY; + goto sata_init_retry; + } else { + pr_err("SATA Initialization Failed\n"); + rc = DEVICE_ERROR; + } + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_ata_pass_thru_idd - obtain SATA device Identify Device Data + * @ioc: per adapter object + * @handle: device handle + * @is_ssd_device : is this SATA SSD device + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 *is_ssd_device, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + u16 *idd_data; + int return_code; + u32 data_length; + + idd_data = NULL; + transfer_packet = kzalloc_obj(struct _scsi_io_transfer); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + data_length = 512; + idd_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!idd_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + rc = DEVICE_READY; + memset(idd_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = ATA_12; + transfer_packet->cdb[1] = 0x8; + transfer_packet->cdb[2] = 0xd; + transfer_packet->cdb[3] = 0x1; + transfer_packet->cdb[9] = 0xec; + transfer_packet->timeout = 30; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, 30, 0); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + // Check if nominal media rotation rate is set to 1 i.e. SSD device + if (idd_data[217] == 1) + *is_ssd_device = 1; + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + + out: + if (idd_data) { + dma_free_coherent(&ioc->pdev->dev, data_length, idd_data, + transfer_packet->data_dma); + } + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_wait_for_device_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @lun: lun number + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ + +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + + if (ioc->pci_error_recovery) + return DEVICE_ERROR; + + if (ioc->shost_recovery) + return DEVICE_RETRY; + + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_READY || rc == DEVICE_ERROR) + return rc; + else if (rc == DEVICE_START_UNIT) { + rc = _scsih_start_unit(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_ERROR) + return rc; + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + } + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) + rc = DEVICE_ERROR; + return rc; +} + +static inline int mpt_scsilun_to_int(struct scsi_lun *scsilun) +{ + return scsilun_to_int(scsilun); +} + +/** + * _scsih_wait_for_target_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value + * @tr_method: Target Reset method Hot/Protocol level. + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + struct scsi_lun *lun_data; + u32 length, num_luns; + u8 *data; + int lun; + struct scsi_lun *lunp; + + lun_data = kzalloc_objs(struct scsi_lun, MPT3_MAX_LUNS); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + return DEVICE_RETRY; + } + + rc = _scsih_report_luns(ioc, handle, lun_data, + MPT3_MAX_LUNS * sizeof(struct scsi_lun), retry_count, is_pd, + tr_timeout, tr_method); + + if (rc != DEVICE_READY) + goto out; + + /* some debug bits*/ + data = (u8 *)lun_data; + length = ((data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | (data[3] << 0)); + + num_luns = (length / sizeof(struct scsi_lun)); + + lunp = &lun_data[1]; + lun = (num_luns) ? mpt_scsilun_to_int(&lun_data[1]) : 0; + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, retry_count, + is_pd, lun, tr_timeout, tr_method); + + if (rc == DEVICE_ERROR) { + struct scsi_lun *lunq; + + for (lunq = lunp++; lunq <= &lun_data[num_luns]; lunq++) { + + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, + retry_count, is_pd, mpt_scsilun_to_int(lunq), + tr_timeout, tr_method); + if (rc != DEVICE_ERROR) + goto out; + } + } +out: + kfree(lun_data); + return rc; +} /** @@ -7220,8 +8309,8 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, sas_device->handle, handle); sas_target_priv_data->handle = handle; sas_device->handle = handle; - if (le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + if ((le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) + && (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { sas_device->enclosure_level = sas_device_pg0.EnclosureLevel; memcpy(sas_device->connector_name, @@ -7263,7 +8352,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address, port); + + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, sas_address, port); + else + _scsih_ublock_io_device(ioc, sas_address, port); if (sas_device) sas_device_put(sas_device); @@ -7279,7 +8372,7 @@ out_unlock: * _scsih_add_device - creating sas device object * @ioc: per adapter object * @handle: sas device handle - * @phy_num: phy number end device attached to + * @retry_count: number of times this event has been retried * @is_pd: is this hidden raid component * * Creating end device object, stored in ioc->sas_device_list. @@ -7287,16 +8380,18 @@ out_unlock: * Return: 0 for success, non-zero for failure. */ static int -_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, +_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd) { Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; struct _sas_device *sas_device; struct _enclosure_node *enclosure_dev = NULL; + enum device_responsive_state rc; u32 ioc_status; u64 sas_address; u32 device_info; + u8 connector_name[5]; u8 port_id; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, @@ -7352,8 +8447,49 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.EnclosureHandle); } - sas_device = kzalloc(sizeof(struct _sas_device), - GFP_KERNEL); + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "sas_address(0x%016llx), phy(%d)\n", handle, + (unsigned long long)sas_address, sas_device_pg0.PhyNum); + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, is_pd, 30, 0); + if (rc != DEVICE_READY) { + if (le16_to_cpu(sas_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", __func__, + le16_to_cpu(sas_device_pg0.Slot))); + if ((le16_to_cpu(sas_device_pg0.Flags) & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) && + (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { + memcpy(connector_name, + sas_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready:\n" + "enclosure level(0x%04x),\n" + "connector name( %s)\n", __func__, + sas_device_pg0.EnclosureLevel, connector_name)); + } + + if ((enclosure_dev) && (le16_to_cpu(enclosure_dev->pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID)) + ioc_info(ioc, "chassis slot(0x%04x)\n", + enclosure_dev->pg0.ChassisSlot); + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } + } + + sas_device = kzalloc_obj(struct _sas_device); if (!sas_device) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -7567,10 +8703,13 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { int i; + int rc; + int requeue_event; u16 parent_handle, handle; u16 reason_code; u8 phy_number, max_phys; struct _sas_node *sas_expander; + struct _sas_device *sas_device; u64 sas_address; unsigned long flags; u8 link_rate, prev_link_rate; @@ -7620,7 +8759,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_node_lock, flags); /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring expander event\n")); @@ -7637,6 +8776,20 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) continue; + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring\n" + "Target not responding event phy in re-queued event processing\n")); + continue; + } + + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring Target not responding\n" + "event phy in re-queued event processing\n")); + continue; + } + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; @@ -7660,9 +8813,32 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, _scsih_check_device(ioc, sas_address, handle, phy_number, link_rate); + /* This code after this point handles the test case + * where a device has been added, however its returning + * BUSY for sometime. Then before the Device Missing + * Delay expires and the device becomes READY, the + * device is removed and added back. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, + handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, + flags); + + if (sas_device) { + sas_device_put(sas_device); + break; + } + if (!test_bit(handle, ioc->pend_os_device_add)) break; + dewtprintk(ioc, ioc_info(ioc, "handle(0x%04x) device not found: convert\n" + "event to a device add\n", handle)); + event_data->PHY[i].PhyStatus &= 0xF0; + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + fallthrough; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: @@ -7673,7 +8849,18 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, mpt3sas_transport_update_links(ioc, sas_address, handle, phy_number, link_rate, port); - _scsih_add_device(ioc, handle, phy_number, 0); + if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) + break; + + rc = _scsih_add_device(ioc, handle, + fw_event->retries[i], 0); + if (rc) {/* retry due to busy device */ + fw_event->retries[i]++; + requeue_event = 1; + } else {/* mark entry vacant */ + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT; + } break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: @@ -7688,7 +8875,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, sas_expander) mpt3sas_expander_remove(ioc, sas_address, port); - return 0; + return requeue_event; } /** @@ -8059,7 +9246,10 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); pcie_device_put(pcie_device); - _scsih_ublock_io_device(ioc, wwid, NULL); + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, wwid, NULL); + else + _scsih_ublock_io_device(ioc, wwid, NULL); return; } @@ -8068,19 +9258,24 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) * _scsih_pcie_add_device - creating pcie device object * @ioc: per adapter object * @handle: pcie device handle + * @retry_count: number of times this event has been retried * * Creating end device object, stored in ioc->pcie_device_list. * * Return: 1 means queue the event later, 0 means complete the event */ static int -_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) +_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count) { Mpi26PCIeDevicePage0_t pcie_device_pg0; Mpi26PCIeDevicePage2_t pcie_device_pg2; Mpi2ConfigReply_t mpi_reply; struct _pcie_device *pcie_device; struct _enclosure_node *enclosure_dev; + enum device_responsive_state rc; + u8 connector_name[5]; + u8 tr_timeout = 30; + u8 tr_method = 0; u32 ioc_status; u64 wwid; @@ -8148,9 +9343,56 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) __LINE__, __func__); return 0; } + + if (!ioc->tm_custom_handling) { + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + if (pcie_device_pg2.ControllerResetTO) + tr_timeout = pcie_device_pg2.ControllerResetTO; + + } + } + + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive) && + (pcie_device_pg0.AccessStatus != + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "wwid(0x%016llx), port(%d)\n", handle, + (unsigned long long)wwid, pcie_device_pg0.PortNum); + + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, 0, tr_timeout, tr_method); + if (rc != DEVICE_READY) { + if (le16_to_cpu(pcie_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", + __func__, + le16_to_cpu(pcie_device_pg0.Slot))); + + if (le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) { + memcpy(connector_name, + pcie_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s: device not ready: enclosure\n" + "level(0x%04x), connector name( %s)\n", __func__, + pcie_device_pg0.EnclosureLevel, + connector_name)); + } + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } } - pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); + pcie_device = kzalloc_obj(struct _pcie_device); if (!pcie_device) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -8311,7 +9553,7 @@ _scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, * Context: user. * */ -static void +static int _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { @@ -8321,6 +9563,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, u8 link_rate, prev_link_rate; unsigned long flags; int rc; + int requeue_event; Mpi26EventDataPCIeTopologyChangeList_t *event_data = (Mpi26EventDataPCIeTopologyChangeList_t *) fw_event->event_data; struct _pcie_device *pcie_device; @@ -8330,22 +9573,22 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } if (ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; reason_code = event_data->PortEntry[i].PortStatus; handle = le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); @@ -8399,8 +9642,11 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (link_rate < MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) break; - rc = _scsih_pcie_add_device(ioc, handle); - if (!rc) { + rc = _scsih_pcie_add_device(ioc, handle, fw_event->retries[i]); + if (rc) {/* retry due to busy device */ + fw_event->retries[i]++; + requeue_event = 1; + } else { /* mark entry vacant */ /* TODO This needs to be reviewed and fixed, * we dont have an entry @@ -8415,11 +9661,12 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, break; } } + return requeue_event; } /** * _scsih_pcie_device_status_change_event_debug - debug for device event - * @ioc: ? + * @ioc: per adapter object * @event_data: event data payload * Context: user. */ @@ -8597,8 +9844,7 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, case MPI2_EVENT_SAS_ENCL_RC_ADDED: if (!enclosure_dev) { enclosure_dev = - kzalloc(sizeof(struct _enclosure_node), - GFP_KERNEL); + kzalloc_obj(struct _enclosure_node); if (!enclosure_dev) { ioc_info(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -8791,7 +10037,7 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, ioc->broadcast_aen_busy = 0; if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 1); mutex_unlock(&ioc->tm_cmds.mutex); } @@ -9023,7 +10269,7 @@ _scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc, if (raid_device) return; - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); + raid_device = kzalloc_obj(struct _raid_device); if (!raid_device) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -9441,7 +10687,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, break; } - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); + raid_device = kzalloc_obj(struct _raid_device); if (!raid_device) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -9802,7 +11048,7 @@ _scsih_create_enclosure_list_after_reset(struct MPT3SAS_ADAPTER *ioc) enclosure_handle = 0xFFFF; do { enclosure_dev = - kzalloc(sizeof(struct _enclosure_node), GFP_KERNEL); + kzalloc_obj(struct _enclosure_node); if (!enclosure_dev) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -10325,7 +11571,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "removing unresponding devices: complete\n"); /* unblock devices */ - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 0); } static void @@ -10605,7 +11851,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } retry_count = 0; parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle); - _scsih_pcie_add_device(ioc, handle); + while (_scsih_pcie_add_device(ioc, handle, retry_count++)) + ssleep(1); ioc_info(ioc, "\tAFTER adding pcie end device: handle (0x%04x), wwid(0x%016llx)\n", handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); @@ -10749,7 +11996,11 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); break; case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); + if (_scsih_sas_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) @@ -10789,9 +12040,12 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_pcie_enumeration_event(ioc, fw_event); break; case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: - _scsih_pcie_topology_change_event(ioc, fw_event); - ioc->current_event = NULL; - return; + if (_scsih_pcie_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } + break; } out: fw_event_work_put(fw_event); @@ -10815,6 +12069,15 @@ _firmware_event_work(struct work_struct *work) _mpt3sas_fw_work(fw_event->ioc, fw_event); } +static void +_firmware_event_work_delayed(struct work_struct *work) +{ + struct fw_event_work *fw_event = container_of(work, + struct fw_event_work, delayed_work.work); + + _mpt3sas_fw_work(fw_event->ioc, fw_event); +} + /** * mpt3sas_scsih_event_callback - firmware event handler (called at ISR time) * @ioc: per adapter object @@ -10995,6 +12258,34 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, return 1; } + if (event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST) { + Mpi2EventDataSasTopologyChangeList_t *topo_event_data = + (Mpi2EventDataSasTopologyChangeList_t *) + mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + kfree(fw_event->event_data); + fw_event_work_put(fw_event); + return 1; + } + } + + if (event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST) { + Mpi26EventDataPCIeTopologyChangeList_t *topo_event_data = + (Mpi26EventDataPCIeTopologyChangeList_t *) mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + fw_event_work_put(fw_event); + return 1; + } + } + memcpy(fw_event->event_data, mpi_reply->EventData, sz); fw_event->ioc = ioc; fw_event->VF_ID = mpi_reply->VF_ID; @@ -12710,7 +14001,7 @@ static const struct pci_device_id mpt3sas_pci_table[] = { }; MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table); -static struct pci_error_handlers _mpt3sas_err_handler = { +static const struct pci_error_handlers _mpt3sas_err_handler = { .error_detected = scsih_pci_error_detected, .mmio_enabled = scsih_pci_mmio_enabled, .slot_reset = scsih_pci_slot_reset, diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index d84413b77d84..e74a526efa8d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -166,6 +166,9 @@ _transport_convert_phy_link_rate(u8 link_rate) case MPI25_SAS_NEG_LINK_RATE_12_0: rc = SAS_LINK_RATE_12_0_GBPS; break; + case MPI26_SAS_NEG_LINK_RATE_22_5: + rc = SAS_LINK_RATE_22_5_GBPS; + break; case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: rc = SAS_PHY_DISABLED; break; @@ -328,10 +331,10 @@ struct rep_manu_reply { u8 reserved0[2]; u8 sas_format; u8 reserved2[3]; - u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; - u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; - u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; - u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] __nonstring; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN] __nonstring; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] __nonstring; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] __nonstring; u16 component_id; u8 component_revision_id; u8 reserved3; @@ -695,8 +698,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, return NULL; } - mpt3sas_port = kzalloc(sizeof(struct _sas_port), - GFP_KERNEL); + mpt3sas_port = kzalloc_obj(struct _sas_port); if (!mpt3sas_port) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -987,11 +989,9 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, list_for_each_entry_safe(mpt3sas_phy, next_phy, &mpt3sas_port->phy_list, port_siblings) { if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &mpt3sas_port->port->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) - mpt3sas_port->remote_identify.sas_address, - mpt3sas_phy->phy_id); + ioc_info(ioc, "remove: sas_addr(0x%016llx), phy(%d)\n", + (unsigned long long) mpt3sas_port->remote_identify.sas_address, + mpt3sas_phy->phy_id); mpt3sas_phy->phy_belongs_to_port = 0; if (!ioc->remove_host) sas_port_delete_phy(mpt3sas_port->port, diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index 9b19d5205e50..f4db93c13986 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -49,7 +49,7 @@ static int mvme16x_probe(struct platform_device *dev) goto out; } - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + hostdata = kzalloc_obj(struct NCR_700_Host_Parameters); if (hostdata == NULL) { printk(KERN_ERR "mvme16x-scsi: " "Failed to allocate host data\n"); diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h index c25a5dfe7889..749f616b21af 100644 --- a/drivers/scsi/mvsas/mv_64xx.h +++ b/drivers/scsi/mvsas/mv_64xx.h @@ -101,8 +101,8 @@ enum sas_sata_vsp_regs { VSR_PHY_MODE9 = 0x09, /* Test */ VSR_PHY_MODE10 = 0x0A, /* Power */ VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ - VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ - VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ + VSR_PHY_VS0 = 0x0C, /* Vendor Specific 0 */ + VSR_PHY_VS1 = 0x0D, /* Vendor Specific 1 */ }; enum chip_register_bits { diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index 8ef174cd4d37..3e4124177b2a 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -215,7 +215,7 @@ enum hw_register_bits { /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ - PHYEV_DCDR_ERR = (1U << 23), /* STP Deocder Error */ + PHYEV_DCDR_ERR = (1U << 23), /* STP Decoder Error */ PHYEV_CRC_ERR = (1U << 22), /* STP CRC Error */ PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ PHYEV_AN = (1U << 18), /* SATA async notification */ @@ -347,7 +347,7 @@ enum sas_cmd_port_registers { CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ - CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ + CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memory BIST Status */ CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 2c72da6b8cf0..5abc17a2e261 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -124,7 +124,7 @@ static void mvs_free(struct mvs_info *mvi) if (mvi->shost) scsi_host_put(mvi->shost); list_for_each_entry(mwq, &mvi->wq_list, entry) - cancel_delayed_work(&mwq->work_q); + cancel_delayed_work_sync(&mwq->work_q); kfree(mvi->rsvd_tags); kfree(mvi); } @@ -401,7 +401,7 @@ static int mvs_prep_sas_ha_init(struct Scsi_Host *shost, sha->sas_port = arr_port; sha->shost = shost; - sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL); + sha->lldd_ha = kzalloc_obj(struct mvs_prv_info); if (!sha->lldd_ha) goto exit_free; @@ -502,7 +502,7 @@ static int mvs_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) chip = &mvs_chips[ent->driver_data]; SHOST_TO_SAS_HA(shost) = - kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); + kzalloc_objs(struct sas_ha_struct, 1); if (!SHOST_TO_SAS_HA(shost)) { scsi_host_put(shost); rc = -ENOMEM; diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 1444b1f1c4c8..359226e80eae 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -151,16 +151,6 @@ static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); } -void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) -{ - u32 no; - for_each_phy(phy_mask, phy_mask, no) { - if (!(phy_mask & 1)) - continue; - MVS_CHIP_DISP->phy_reset(mvi, no, hard); - } -} - int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata) { @@ -828,7 +818,7 @@ err_out: dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); if (!sas_protocol_ata(task->task_proto)) if (n_elem) - dma_unmap_sg(mvi->dev, task->scatter, n_elem, + dma_unmap_sg(mvi->dev, task->scatter, task->num_scatter, task->data_dir); prep_out: return rc; @@ -874,7 +864,7 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, if (!sas_protocol_ata(task->task_proto)) if (slot->n_elem) dma_unmap_sg(mvi->dev, task->scatter, - slot->n_elem, task->data_dir); + task->num_scatter, task->data_dir); switch (task->task_proto) { case SAS_PROTOCOL_SMP: @@ -986,7 +976,7 @@ static u32 mvs_is_sig_fis_received(u32 irq_status) static void mvs_sig_remove_timer(struct mvs_phy *phy) { if (phy->timer.function) - del_timer(&phy->timer); + timer_delete(&phy->timer); phy->timer.function = NULL; } @@ -1185,7 +1175,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock) mvi_device->dev_type = dev->dev_type; mvi_device->mvi_info = mvi; mvi_device->sas_device = dev; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(dev)) { int phy_id; phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); @@ -1749,7 +1739,7 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) struct mvs_wq *mwq; int ret = 0; - mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC); + mwq = kmalloc_obj(struct mvs_wq, GFP_ATOMIC); if (mwq) { mwq->mvi = mvi; mwq->data = data; @@ -1765,7 +1755,7 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) static void mvs_sig_time_out(struct timer_list *t) { - struct mvs_phy *phy = from_timer(phy, t, timer); + struct mvs_phy *phy = timer_container_of(phy, t, timer); struct mvs_info *mvi = phy->mvi; u8 phy_no; diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 19b01f7c4767..09ce3f2241f2 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -425,7 +425,6 @@ struct mvs_task_exec_info { void mvs_get_sas_addr(void *buf, u32 buflen); void mvs_iounmap(void __iomem *regs); int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); -void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata); void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo, diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 96549e7f5705..e70d336b4ab3 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -106,7 +106,7 @@ static int mvumi_map_pci_addr(struct pci_dev *dev, void **addr_array) static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, enum resource_type type, unsigned int size) { - struct mvumi_res *res = kzalloc(sizeof(*res), GFP_ATOMIC); + struct mvumi_res *res = kzalloc_obj(*res, GFP_ATOMIC); if (!res) { dev_err(&mhba->pdev->dev, @@ -252,7 +252,7 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, { struct mvumi_cmd *cmd; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + cmd = kzalloc_obj(*cmd); if (!cmd) { dev_err(&mhba->pdev->dev, "failed to create a internal cmd\n"); return NULL; @@ -368,7 +368,7 @@ static int mvumi_alloc_cmds(struct mvumi_hba *mhba) struct mvumi_cmd *cmd; for (i = 0; i < mhba->max_io; i++) { - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + cmd = kzalloc_obj(*cmd); if (!cmd) goto err_exit; @@ -1572,8 +1572,7 @@ static int mvumi_probe_devices(struct mvumi_hba *mhba) found = mvumi_match_devices(mhba, id, wwid); if (!found) { mvumi_remove_devices(mhba, id); - mv_dev = kzalloc(sizeof(struct mvumi_device), - GFP_KERNEL); + mv_dev = kzalloc_obj(struct mvumi_device); if (!mv_dev) { dev_err(&mhba->pdev->dev, "%s alloc mv_dev failed\n", @@ -1749,7 +1748,7 @@ static void mvumi_launch_events(struct mvumi_hba *mhba, u32 isr_status) continue; } - mu_ev = kzalloc(sizeof(*mu_ev), GFP_ATOMIC); + mu_ev = kzalloc_obj(*mu_ev, GFP_ATOMIC); if (mu_ev) { INIT_WORK(&mu_ev->work_q, mvumi_scan_events); mu_ev->mhba = mhba; @@ -2077,8 +2076,8 @@ error: * @shost: Scsi host to queue command on * @scmd: SCSI command to be queued */ -static int mvumi_queue_command(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mvumi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mvumi_cmd *cmd; struct mvumi_hba *mhba; @@ -2142,7 +2141,7 @@ static enum scsi_timeout_action mvumi_timed_out(struct scsi_cmnd *scmd) } static int -mvumi_bios_param(struct scsi_device *sdev, struct block_device *bdev, +mvumi_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors; @@ -2193,7 +2192,7 @@ static int mvumi_cfg_hw_reg(struct mvumi_hba *mhba) mhba->mmio = mhba->base_addr[0]; base = mhba->mmio; if (!mhba->regs) { - mhba->regs = kzalloc(sizeof(*regs), GFP_KERNEL); + mhba->regs = kzalloc_obj(*regs); if (mhba->regs == NULL) return -ENOMEM; } @@ -2245,7 +2244,7 @@ static int mvumi_cfg_hw_reg(struct mvumi_hba *mhba) mhba->mmio = mhba->base_addr[2]; base = mhba->mmio; if (!mhba->regs) { - mhba->regs = kzalloc(sizeof(*regs), GFP_KERNEL); + mhba->regs = kzalloc_obj(*regs); if (mhba->regs == NULL) return -ENOMEM; } diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index dc4bd422b601..3678b66310ed 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -891,7 +891,7 @@ static bool myrb_enable_mmio(struct myrb_hba *cb, mbox_mmio_init_t mmio_init_fn) status = mmio_init_fn(pdev, base, &mbox); if (status != MYRB_STATUS_SUCCESS) { dev_err(&pdev->dev, - "Failed to enable mailbox, statux %02X\n", + "Failed to enable mailbox, status %02X\n", status); return false; } @@ -1260,8 +1260,8 @@ static int myrb_host_reset(struct scsi_cmnd *scmd) return SUCCESS; } -static int myrb_pthru_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_pthru_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrb_hba *cb = shost_priv(shost); @@ -1416,8 +1416,8 @@ static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, data, 8); } -static int myrb_ldev_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_ldev_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct myrb_hba *cb = shost_priv(shost); struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd); @@ -1603,8 +1603,8 @@ submit: return 0; } -static int myrb_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct scsi_device *sdev = scmd->device; @@ -1628,7 +1628,7 @@ static int myrb_ldev_sdev_init(struct scsi_device *sdev) ldev_info = cb->ldev_info_buf + ldev_num; - sdev->hostdata = kzalloc(sizeof(*ldev_info), GFP_KERNEL); + sdev->hostdata = kzalloc_obj(*ldev_info); if (!sdev->hostdata) return -ENOMEM; dev_dbg(&sdev->sdev_gendev, @@ -1672,7 +1672,7 @@ static int myrb_pdev_sdev_init(struct scsi_device *sdev) if (sdev->id > MYRB_MAX_TARGETS) return -ENXIO; - pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL); + pdev_info = kzalloc_obj(*pdev_info); if (!pdev_info) return -ENOMEM; @@ -1745,7 +1745,7 @@ static void myrb_sdev_destroy(struct scsi_device *sdev) kfree(sdev->hostdata); } -static int myrb_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int myrb_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { struct myrb_hba *cb = shost_priv(sdev->host); diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index 95af3bb03834..afd68225221a 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -498,14 +498,14 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, /* Temporary dma mapping, used only in the scope of this function */ mbox = dma_alloc_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox), &mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, mbox_addr)) + if (!mbox) return false; /* These are the base addresses for the command memory mailbox array */ cs->cmd_mbox_size = MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox); cmd_mbox = dma_alloc_coherent(&pdev->dev, cs->cmd_mbox_size, &cs->cmd_mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->cmd_mbox_addr)) { + if (!cmd_mbox) { dev_err(&pdev->dev, "Failed to map command mailbox\n"); goto out_free; } @@ -520,7 +520,7 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, cs->stat_mbox_size = MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox); stat_mbox = dma_alloc_coherent(&pdev->dev, cs->stat_mbox_size, &cs->stat_mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->stat_mbox_addr)) { + if (!stat_mbox) { dev_err(&pdev->dev, "Failed to map status mailbox\n"); goto out_free; } @@ -533,16 +533,16 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, cs->fwstat_buf = dma_alloc_coherent(&pdev->dev, sizeof(struct myrs_fwstat), &cs->fwstat_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->fwstat_addr)) { + if (!cs->fwstat_buf) { dev_err(&pdev->dev, "Failed to map firmware health buffer\n"); cs->fwstat_buf = NULL; goto out_free; } - cs->ctlr_info = kzalloc(sizeof(struct myrs_ctlr_info), GFP_KERNEL); + cs->ctlr_info = kzalloc_obj(struct myrs_ctlr_info); if (!cs->ctlr_info) goto out_free; - cs->event_buf = kzalloc(sizeof(struct myrs_event), GFP_KERNEL); + cs->event_buf = kzalloc_obj(struct myrs_event); if (!cs->event_buf) goto out_free; @@ -1581,8 +1581,8 @@ static void myrs_mode_sense(struct myrs_hba *cs, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, modes, mode_len); } -static int myrs_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrs_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrs_hba *cs = shost_priv(shost); @@ -1803,7 +1803,7 @@ static int myrs_sdev_init(struct scsi_device *sdev) ldev_num = myrs_translate_ldev(cs, sdev); - ldev_info = kzalloc(sizeof(*ldev_info), GFP_KERNEL); + ldev_info = kzalloc_obj(*ldev_info); if (!ldev_info) return -ENOMEM; @@ -1865,7 +1865,7 @@ static int myrs_sdev_init(struct scsi_device *sdev) } else { struct myrs_pdev_info *pdev_info; - pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL); + pdev_info = kzalloc_obj(*pdev_info); if (!pdev_info) return -ENOMEM; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 14ac81ec0aa0..4a255aafed80 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7852,7 +7852,7 @@ static int ncr53c8xx_sdev_configure(struct scsi_device *device, return 0; } -static int ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct ncr_cmd_priv *cmd_priv = scsi_cmd_priv(cmd); void (*done)(struct scsi_cmnd *) = scsi_done; @@ -7923,7 +7923,7 @@ irqreturn_t ncr53c8xx_intr(int irq, void *dev_id) static void ncr53c8xx_timeout(struct timer_list *t) { - struct ncb *np = from_timer(np, t, timer); + struct ncb *np = timer_container_of(np, t, timer); unsigned long flags; struct scsi_cmnd *done_list; diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index abc4ce9eae74..e893d5677241 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -185,7 +185,8 @@ static void __exit exit_nsp32 (void); static int nsp32_show_info (struct seq_file *, struct Scsi_Host *); static int nsp32_detect (struct pci_dev *pdev); -static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status nsp32_queuecommand(struct Scsi_Host *, + struct scsi_cmnd *); static const char *nsp32_info (struct Scsi_Host *); static int nsp32_release (struct Scsi_Host *); @@ -905,7 +906,7 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt) return TRUE; } -static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 1b54ba51a485..014ae8d42331 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -96,7 +96,7 @@ static int aha152x_probe(struct pcmcia_device *link) dev_dbg(&link->dev, "aha152x_attach()\n"); /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (!info) return -ENOMEM; info->p_dev = link; link->priv = info; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a5a1406a2bde..ae70fda96ae9 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -186,7 +186,7 @@ static void nsp_scsi_done(struct scsi_cmnd *SCpnt) scsi_done(SCpnt); } -static int nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) +static enum scsi_qc_status nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) { struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt); #ifdef NSP_DEBUG @@ -1520,7 +1520,7 @@ static int nsp_cs_probe(struct pcmcia_device *link) nsp_dbg(NSP_DEBUG_INIT, "in"); /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (info == NULL) { return -ENOMEM; } info->p_dev = link; link->priv = info; diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index e1ee8ef90ad3..12e58386bb8f 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -294,7 +294,8 @@ static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); static const char *nsp_info (struct Scsi_Host *shpnt); static int nsp_show_info (struct seq_file *m, struct Scsi_Host *host); -static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +static enum scsi_qc_status nsp_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Error handler */ /*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/ diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 310d0b6586a6..5d8a434d3f66 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -152,7 +152,7 @@ static int qlogic_probe(struct pcmcia_device *link) dev_dbg(&link->dev, "qlogic_attach()\n"); /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (!info) return -ENOMEM; info->p_dev = link; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 278c78d066c4..1530c1ad5d36 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -544,7 +544,7 @@ SYM53C500_info(struct Scsi_Host *SChost) return (info_msg); } -static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) { struct sym53c500_cmd_priv *scp = scsi_cmd_priv(SCpnt); int i; @@ -597,7 +597,7 @@ SYM53C500_host_reset(struct scsi_cmnd *SCpnt) static int SYM53C500_biosparm(struct scsi_device *disk, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int *info_array) { int size; @@ -849,7 +849,7 @@ SYM53C500_probe(struct pcmcia_device *link) dev_dbg(&link->dev, "SYM53C500_attach()\n"); /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (!info) return -ENOMEM; info->p_dev = link; diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 85ff95c6543a..cbfda8c04e95 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -534,23 +534,25 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, char *str = buf; u32 read_size = pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024; - static u32 start, end, count; u32 max_read_times = 32; u32 max_count = (read_size * 1024) / (max_read_times * 4); u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr; - if ((count % max_count) == 0) { - start = 0; - end = max_read_times; - count = 0; + mutex_lock(&pm8001_ha->iop_log_lock); + + if ((pm8001_ha->iop_log_count % max_count) == 0) { + pm8001_ha->iop_log_start = 0; + pm8001_ha->iop_log_end = max_read_times; + pm8001_ha->iop_log_count = 0; } else { - start = end; - end = end + max_read_times; + pm8001_ha->iop_log_start = pm8001_ha->iop_log_end; + pm8001_ha->iop_log_end = pm8001_ha->iop_log_end + max_read_times; } - for (; start < end; start++) - str += sprintf(str, "%08x ", *(temp+start)); - count++; + for (; pm8001_ha->iop_log_start < pm8001_ha->iop_log_end; pm8001_ha->iop_log_start++) + str += sprintf(str, "%08x ", *(temp+pm8001_ha->iop_log_start)); + pm8001_ha->iop_log_count++; + mutex_unlock(&pm8001_ha->iop_log_lock); return str - buf; } static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); @@ -644,7 +646,7 @@ static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); #define FLASH_CMD_SET_NVMD 0x02 struct flash_command { - u8 command[8]; + u8 command[8] __nonstring; int code; }; @@ -680,7 +682,7 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) struct pm8001_ioctl_payload *payload; DECLARE_COMPLETION_ONSTACK(completion); u8 *ioctlbuffer; - u32 ret; + int ret; u32 length = 1024 * 5 + sizeof(*payload) - 1; if (pm8001_ha->fw_image->size > 4096) { diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 42a4eeac24c9..fff8d877abb9 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1686,7 +1686,7 @@ int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, struct pm8001_work *pw; int ret = 0; - pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC); + pw = kmalloc_obj(struct pm8001_work, GFP_ATOMIC); if (pw) { pw->pm8001_ha = pm8001_ha; pw->data = data; @@ -2163,8 +2163,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { - if (!((t->dev->parent) && - (dev_is_expander(t->dev->parent->dev_type)))) { + if (!dev_parent_is_expander(t->dev)) { for (i = 0, j = 4; j <= 7 && i <= 3; i++, j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0, j = 0; j <= 3 && i <= 3; i++, j++) @@ -4168,7 +4167,6 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 firstBurstSize = 0; u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; - struct domain_device *parent_dev = dev->parent; struct pm8001_port *port = dev->port->lldd_port; memset(&payload, 0, sizeof(payload)); @@ -4186,10 +4184,9 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && dev_is_expander(parent_dev->dev_type)) - phy_id = parent_dev->ex_dev.ex_phy->phy_id; - else - phy_id = pm8001_dev->attached_phy; + + phy_id = pm80xx_get_local_phy_id(dev); + opc = OPC_INB_REG_DEV; linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? pm8001_dev->sas_device->linkrate : dev->port->linkrate; @@ -4374,7 +4371,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ioctl_payload *ioctl_payload = payload; nvmd_type = ioctl_payload->minor_function; - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + fw_control_context = kzalloc_obj(struct fw_control_ex); if (!fw_control_context) return -ENOMEM; fw_control_context->usrAddr = (u8 *)ioctl_payload->func_specific; @@ -4467,7 +4464,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ioctl_payload *ioctl_payload = payload; nvmd_type = ioctl_payload->minor_function; - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + fw_control_context = kzalloc_obj(struct fw_control_ex); if (!fw_control_context) return -ENOMEM; @@ -4582,7 +4579,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, dma_addr_t phys_addr = pm8001_ha->memoryMap.region[FW_FLASH].phys_addr; struct pm8001_ioctl_payload *ioctl_payload = payload; - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + fw_control_context = kzalloc_obj(struct fw_control_ex); if (!fw_control_context) return -ENOMEM; fw_control = (struct fw_control_info *)&ioctl_payload->func_specific; diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index fc2127dcb58d..f1ce8df082b0 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h @@ -339,8 +339,10 @@ struct ssp_completion_resp { __le32 status; __le32 param; __le32 ssptag_rescv_rescpad; + + /* Must be last --ends in a flexible-array member. */ struct ssp_response_iu ssp_resp_iu; - __le32 residual_count; + /* __le32 residual_count; */ } __attribute__((packed, aligned(4))); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 599410bcdfea..e93ea76b565e 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -552,6 +552,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->id = pm8001_id++; pm8001_ha->logging_level = logging_level; pm8001_ha->non_fatal_count = 0; + mutex_init(&pm8001_ha->iop_log_lock); if (link_rate >= 1 && link_rate <= 15) pm8001_ha->link_rate = (link_rate << 8); else { @@ -621,7 +622,7 @@ static int pm8001_prep_sas_ha_init(struct Scsi_Host *shost, sha->sas_phy = arr_phy; sha->sas_port = arr_port; - sha->lldd_ha = kzalloc(sizeof(struct pm8001_hba_info), GFP_KERNEL); + sha->lldd_ha = kzalloc_obj(struct pm8001_hba_info); if (!sha->lldd_ha) goto exit_free1; @@ -1147,7 +1148,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, goto err_out_regions; } chip = &pm8001_chips[ent->driver_data]; - sha = kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); + sha = kzalloc_obj(struct sas_ha_struct); if (!sha) { rc = -ENOMEM; goto err_out_free_host; @@ -1263,7 +1264,7 @@ static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha) /* Memory region for ccb_info*/ pm8001_ha->ccb_count = ccb_count; pm8001_ha->ccb_info = - kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL); + kzalloc_objs(struct pm8001_ccb_info, ccb_count); if (!pm8001_ha->ccb_info) { pm8001_dbg(pm8001_ha, FAIL, "Unable to allocate memory for ccb\n"); @@ -1533,7 +1534,7 @@ static int __init pm8001_init(void) if (pm8001_use_tasklet && !pm8001_use_msix) pm8001_use_tasklet = false; - pm8001_wq = alloc_workqueue("pm80xx", 0, 0); + pm8001_wq = alloc_workqueue("pm80xx", WQ_PERCPU, 0); if (!pm8001_wq) goto err; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 183ce00aa671..645524f3fe2d 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -130,6 +130,16 @@ static void pm80xx_get_tag_opcodes(struct sas_task *task, int *ata_op, } } +u32 pm80xx_get_local_phy_id(struct domain_device *dev) +{ + struct pm8001_device *pm8001_dev = dev->lldd_dev; + + if (dev_parent_is_expander(dev)) + return dev->parent->ex_dev.ex_phy->phy_id; + + return pm8001_dev->attached_phy; +} + void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *target_pm8001_dev) { @@ -477,7 +487,7 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) struct pm8001_device *pm8001_dev = dev->lldd_dev; bool internal_abort = sas_is_internal_abort(task); struct pm8001_hba_info *pm8001_ha; - struct pm8001_port *port = NULL; + struct pm8001_port *port; struct pm8001_ccb_info *ccb; unsigned long flags; u32 n_elem = 0; @@ -502,8 +512,7 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) spin_lock_irqsave(&pm8001_ha->lock, flags); - pm8001_dev = dev->lldd_dev; - port = pm8001_ha->phy[pm8001_dev->attached_phy].port; + port = dev->port->lldd_port; if (!internal_abort && (DEV_IS_GONE(pm8001_dev) || !port || !port->port_attached)) { @@ -516,8 +525,9 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) } else { task->task_done(task); } - rc = -ENODEV; - goto err_out; + spin_unlock_irqrestore(&pm8001_ha->lock, flags); + pm8001_dbg(pm8001_ha, IO, "pm8001_task_exec device gone\n"); + return 0; } ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, task); @@ -701,7 +711,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) dev->lldd_dev = pm8001_device; pm8001_device->dev_type = dev->dev_type; pm8001_device->dcompletion = &completion; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(dev)) { int phy_id; phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); @@ -766,6 +776,16 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) spin_lock_irqsave(&pm8001_ha->lock, flags); } PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); + + /* + * The phy array only contains local phys. Thus, we cannot clear + * phy_attached for a device behind an expander. + */ + if (!dev_parent_is_expander(dev)) { + u32 phy_id = pm80xx_get_local_phy_id(dev); + + pm8001_ha->phy[phy_id].phy_attached = 0; + } pm8001_free_dev(pm8001_dev); } else { pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); @@ -1047,7 +1067,7 @@ int pm8001_abort_task(struct sas_task *task) struct pm8001_hba_info *pm8001_ha; struct pm8001_device *pm8001_dev; int rc = TMF_RESP_FUNC_FAILED, ret; - u32 phy_id, port_id; + u32 port_id; struct sas_task_slow slow_task; if (!task->lldd_task || !task->dev) @@ -1056,7 +1076,6 @@ int pm8001_abort_task(struct sas_task *task) dev = task->dev; pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); - phy_id = pm8001_dev->attached_phy; if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) { // If the controller is seeing fatal errors @@ -1088,7 +1107,8 @@ int pm8001_abort_task(struct sas_task *task) if (pm8001_ha->chip_id == chip_8006) { DECLARE_COMPLETION_ONSTACK(completion_reset); DECLARE_COMPLETION_ONSTACK(completion); - struct pm8001_phy *phy = pm8001_ha->phy + phy_id; + u32 phy_id = pm80xx_get_local_phy_id(dev); + struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; port_id = phy->port->port_id; /* 1. Set Device state as Recovery */ diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 315f6a7523f0..b63b6ffcaaf5 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -170,6 +170,14 @@ struct forensic_data { #define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80 #define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */ +/** + * enum fatal_error_reporter: Indicates the originator of the fatal error + */ +enum fatal_error_reporter { + REPORTER_DRIVER, + REPORTER_FIRMWARE, +}; + struct pm8001_dispatch { char *name; int (*chip_init)(struct pm8001_hba_info *pm8001_ha); @@ -539,6 +547,10 @@ struct pm8001_hba_info { u32 ci_offset; u32 pi_offset; u32 max_memcnt; + u32 iop_log_start; + u32 iop_log_end; + u32 iop_log_count; + struct mutex iop_log_lock; }; struct pm8001_work { @@ -715,6 +727,8 @@ 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); int pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha); +void pm80xx_fatal_error_uevent_emit(struct pm8001_hba_info *pm8001_ha, + enum fatal_error_reporter error_reporter); void pm8001_free_dev(struct pm8001_device *pm8001_dev); /* ctl shared API */ extern const struct attribute_group *pm8001_host_groups[]; @@ -788,6 +802,7 @@ void pm8001_setds_completion(struct domain_device *dev); void pm8001_tmf_aborted(struct sas_task *task); void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *dev); +u32 pm80xx_get_local_phy_id(struct domain_device *dev); #endif diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 5b373c53c036..954f307352e6 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1552,6 +1552,52 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) } /** + * pm80xx_fatal_error_uevent_emit - emits a single fatal error uevent + * @pm8001_ha: our hba card information + * @error_reporter: reporter of fatal error + */ +void pm80xx_fatal_error_uevent_emit(struct pm8001_hba_info *pm8001_ha, + enum fatal_error_reporter error_reporter) +{ + struct kobj_uevent_env *env; + + pm8001_dbg(pm8001_ha, FAIL, "emitting fatal error uevent"); + + env = kzalloc_obj(struct kobj_uevent_env); + if (!env) + return; + + if (add_uevent_var(env, "DRIVER=%s", DRV_NAME)) + goto exit; + + if (add_uevent_var(env, "HBA_NUM=%u", pm8001_ha->id)) + goto exit; + + if (add_uevent_var(env, "EVENT_TYPE=FATAL_ERROR")) + goto exit; + + switch (error_reporter) { + case REPORTER_DRIVER: + if (add_uevent_var(env, "REPORTED_BY=DRIVER")) + goto exit; + break; + case REPORTER_FIRMWARE: + if (add_uevent_var(env, "REPORTED_BY=FIRMWARE")) + goto exit; + break; + default: + if (add_uevent_var(env, "REPORTED_BY=OTHER")) + goto exit; + break; + } + + kobject_uevent_env(&pm8001_ha->shost->shost_dev.kobj, KOBJ_CHANGE, env->envp); + +exit: + kfree(env); +} + +/** * pm80xx_fatal_errors - returns non-zero *ONLY* when fatal errors * @pm8001_ha: our hba card information * @@ -1580,6 +1626,7 @@ pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha) "Fatal error SCRATCHPAD1 = 0x%x SCRATCHPAD2 = 0x%x SCRATCHPAD3 = 0x%x SCRATCHPAD_RSVD0 = 0x%x SCRATCHPAD_RSVD1 = 0x%x\n", scratch_pad1, scratch_pad2, scratch_pad3, scratch_pad_rsvd0, scratch_pad_rsvd1); + pm80xx_fatal_error_uevent_emit(pm8001_ha, REPORTER_DRIVER); ret = 1; } @@ -2293,8 +2340,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { - if (!((t->dev->parent) && - (dev_is_expander(t->dev->parent->dev_type)))) { + if (!dev_parent_is_expander(t->dev)) { for (i = 0, j = 4; i <= 3 && j <= 7; i++, j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0, j = 0; i <= 3 && j <= 3; i++, j++) @@ -4039,6 +4085,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) pm8001_dbg(pm8001_ha, FAIL, "Firmware Fatal error! Regval:0x%x\n", regval); + pm80xx_fatal_error_uevent_emit(pm8001_ha, REPORTER_FIRMWARE); pm8001_handle_event(pm8001_ha, NULL, IO_FATAL_ERROR); print_scratchpad_registers(pm8001_ha); return ret; @@ -4677,8 +4724,12 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; - return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, + ret = pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, sizeof(payload), 0); + if (ret < 0) + pm8001_tag_free(pm8001_ha, tag); + + return ret; } /** @@ -4704,8 +4755,12 @@ static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, payload.tag = cpu_to_le32(tag); payload.phy_id = cpu_to_le32(phy_id); - return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, + ret = pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, sizeof(payload), 0); + if (ret < 0) + pm8001_tag_free(pm8001_ha, tag); + + return ret; } /* @@ -4724,7 +4779,6 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 firstBurstSize = 0; u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; - struct domain_device *parent_dev = dev->parent; struct pm8001_port *port = dev->port->lldd_port; memset(&payload, 0, sizeof(payload)); @@ -4743,10 +4797,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && dev_is_expander(parent_dev->dev_type)) - phy_id = parent_dev->ex_dev.ex_phy->phy_id; - else - phy_id = pm8001_dev->attached_phy; + + phy_id = pm80xx_get_local_phy_id(dev); opc = OPC_INB_REG_DEV; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index eb8fd37b2066..d8a63b7fed6a 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -558,8 +558,10 @@ struct ssp_completion_resp { __le32 status; __le32 param; __le32 ssptag_rescv_rescpad; + + /* Must be last --ends in a flexible-array member. */ struct ssp_response_iu ssp_resp_iu; - __le32 residual_count; + /* __le32 residual_count; */ } __attribute__((packed, aligned(4))); #define SSP_RESCV_BIT 0x00010000 diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 3ba53916fd86..942a99393204 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -495,7 +495,7 @@ static void pmcraid_clr_trans_op( } if (pinstance->reset_cmd != NULL) { - del_timer(&pinstance->reset_cmd->timer); + timer_delete(&pinstance->reset_cmd->timer); spin_lock_irqsave( pinstance->host->host_lock, lock_flags); pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); @@ -544,7 +544,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *); */ static void pmcraid_bist_done(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; unsigned long lock_flags; int rc; @@ -601,7 +601,7 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd) */ static void pmcraid_reset_alert_done(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; u32 status = ioread32(pinstance->ioa_status); unsigned long lock_flags; @@ -685,7 +685,7 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) */ static void pmcraid_timeout_handler(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; unsigned long lock_flags; @@ -1999,7 +1999,7 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) cpu_to_le32(PMCRAID_DRIVER_ILID); /* In case the command timer is still running */ - del_timer(&cmd->timer); + timer_delete(&cmd->timer); /* If this is an IO command, complete it by invoking scsi_done * function. If this is one of the internal commands other @@ -3242,14 +3242,14 @@ static int pmcraid_build_ioadl( * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy */ -static int pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) { struct pmcraid_instance *pinstance; struct pmcraid_resource_entry *res; struct pmcraid_ioarcb *ioarcb; + enum scsi_qc_status rc = 0; struct pmcraid_cmd *cmd; u32 fw_version; - int rc = 0; pinstance = (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; @@ -3468,7 +3468,7 @@ static long pmcraid_chr_ioctl( void __user *argp = (void __user *)arg; int retval = -ENOTTY; - hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); + hdr = kmalloc_obj(struct pmcraid_ioctl_header); if (!hdr) { pmcraid_err("failed to allocate memory for ioctl header\n"); @@ -3982,7 +3982,7 @@ static void pmcraid_tasklet_function(unsigned long instance) list_del(&cmd->free_list); spin_unlock_irqrestore(&pinstance->pending_pool_lock, pending_lock_flags); - del_timer(&cmd->timer); + timer_delete(&cmd->timer); atomic_dec(&pinstance->outstanding_cmds); if (cmd->cmd_done == pmcraid_ioa_reset) { @@ -4385,9 +4385,8 @@ static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) int i; pinstance->res_entries = - kcalloc(PMCRAID_MAX_RESOURCES, - sizeof(struct pmcraid_resource_entry), - GFP_KERNEL); + kzalloc_objs(struct pmcraid_resource_entry, + PMCRAID_MAX_RESOURCES); if (NULL == pinstance->res_entries) { pmcraid_err("failed to allocate memory for resource table\n"); diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 9f59930e8b4f..cd059b7599b4 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -657,7 +657,7 @@ struct pmcraid_hostrcb { */ struct pmcraid_instance { /* Array of allowed-to-be-exposed resources, initialized from - * Configutation Table, later updated with CCNs + * Configuration Table, later updated with CCNs */ struct pmcraid_resource_entry *res_entries; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index a06329b47851..8a4e910d5758 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -816,7 +816,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) return 0; } -static int ppa_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ppa_queuecommand_lck(struct scsi_cmnd *cmd) { ppa_struct *dev = ppa_dev(cmd->device->host); @@ -845,7 +845,7 @@ static DEF_SCSI_QCMD(ppa_queuecommand) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -static int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int ppa_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { ip[0] = 0x40; @@ -1042,7 +1042,7 @@ static int __ppa_attach(struct parport *pb) int err = -ENOMEM; struct pardev_cb ppa_cb; - dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL); + dev = kzalloc_obj(ppa_struct); if (!dev) return -ENOMEM; dev->base = -1; @@ -1104,7 +1104,6 @@ static int __ppa_attach(struct parport *pb) host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); if (!host) goto out1; - host->no_highmem = true; host->io_port = pb->base; host->n_io_port = ports; host->dma_channel = -1; diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 92fe5c5c5bb0..a9c727d22931 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -201,7 +201,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, return 0; } -static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) { struct ps3rom_private *priv = shost_priv(cmd->device->host); struct ps3_storage_device *dev = priv->dev; diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 98afdfe63600..5b330a3203e1 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -487,8 +487,8 @@ extern uint qedf_debug; extern struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf); extern void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr); -extern int qedf_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd); +extern enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); extern void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb); extern u8 *qedf_get_src_mac(struct fc_lport *lport); extern void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb); diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index 769da92ee20d..7ebb46689f97 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -166,8 +166,8 @@ static const struct bin_attribute sysfs_grcdump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qedf_sysfs_read_grcdump, - .write_new = qedf_sysfs_write_grcdump, + .read = qedf_sysfs_read_grcdump, + .write = qedf_sysfs_write_grcdump, }; static struct sysfs_bin_attrs bin_file_entries[] = { diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index 96174353e389..a9d109c2cb4d 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -422,7 +422,7 @@ qedf_offload_stats_show(struct seq_file *s, void *unused) struct qedf_ctx *qedf = s->private; struct qed_fcoe_stats *fw_fcoe_stats; - fw_fcoe_stats = kmalloc(sizeof(struct qed_fcoe_stats), GFP_KERNEL); + fw_fcoe_stats = kmalloc_obj(struct qed_fcoe_stats); if (!fw_fcoe_stats) { QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate memory for " "fw_fcoe_stats.\n"); diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index 1ff5bc314fc0..12841516653d 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -297,7 +297,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) aborted_io_req->xid); memset(&rrq, 0, sizeof(rrq)); - cb_arg = kzalloc(sizeof(struct qedf_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct qedf_els_cb_arg, GFP_NOIO); if (!cb_arg) { QEDF_ERR(&(qedf->dbg_ctx), "Unable to allocate cb_arg for " "RRQ\n"); @@ -510,7 +510,7 @@ int qedf_send_adisc(struct qedf_rport *fcport, struct fc_frame *fp) qedf = fcport->qedf; fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct qedf_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct qedf_els_cb_arg, GFP_NOIO); if (!cb_arg) { QEDF_ERR(&(qedf->dbg_ctx), "Unable to allocate cb_arg for " "ADISC\n"); @@ -659,7 +659,7 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) "orig_xid=0x%x\n", orig_io_req, orig_io_req->xid); memset(&srr, 0, sizeof(srr)); - cb_arg = kzalloc(sizeof(struct qedf_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct qedf_els_cb_arg, GFP_NOIO); if (!cb_arg) { QEDF_ERR(&(qedf->dbg_ctx), "Unable to allocate cb_arg for " "SRR\n"); @@ -708,7 +708,7 @@ static void qedf_initiate_seq_cleanup(struct qedf_ioreq *orig_io_req, "Doing sequence cleanup for xid=0x%x offset=%u.\n", orig_io_req->xid, offset); - cb_arg = kzalloc(sizeof(struct qedf_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct qedf_els_cb_arg, GFP_NOIO); if (!cb_arg) { QEDF_ERR(&(fcport->qedf->dbg_ctx), "Unable to allocate cb_arg " "for sequence cleanup\n"); @@ -1033,7 +1033,7 @@ int qedf_send_rec(struct qedf_ioreq *orig_io_req) memset(&rec, 0, sizeof(rec)); - cb_arg = kzalloc(sizeof(struct qedf_els_cb_arg), GFP_NOIO); + cb_arg = kzalloc_obj(struct qedf_els_cb_arg, GFP_NOIO); if (!cb_arg) { QEDF_ERR(&(qedf->dbg_ctx), "Unable to allocate cb_arg for " "REC\n"); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index fcfc3bed02c6..a120f0e37a64 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -230,8 +230,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) } /* Allocate task parameters to pass to f/w init funcions */ - io_req->task_params = kzalloc(sizeof(*io_req->task_params), - GFP_KERNEL); + io_req->task_params = kzalloc_obj(*io_req->task_params); if (!io_req->task_params) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to allocate task_params for xid=0x%x\n", @@ -243,8 +242,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) * Allocate scatter/gather list info to pass to f/w init * functions. */ - io_req->sgl_task_params = kzalloc( - sizeof(struct scsi_sgl_task_params), GFP_KERNEL); + io_req->sgl_task_params = kzalloc_obj(struct scsi_sgl_task_params); if (!io_req->sgl_task_params) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to allocate sgl_task_params for xid=0x%x\n", @@ -254,8 +252,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) } /* Allocate pool of io_bdts - one for each qedf_ioreq */ - cmgr->io_bdt_pool = kmalloc_array(num_ios, sizeof(struct io_bdt *), - GFP_KERNEL); + cmgr->io_bdt_pool = kmalloc_objs(struct io_bdt *, num_ios); if (!cmgr->io_bdt_pool) { QEDF_WARN(&(qedf->dbg_ctx), "Failed to alloc io_bdt_pool.\n"); @@ -263,8 +260,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) } for (i = 0; i < num_ios; i++) { - cmgr->io_bdt_pool[i] = kmalloc(sizeof(struct io_bdt), - GFP_KERNEL); + cmgr->io_bdt_pool[i] = kmalloc_obj(struct io_bdt); if (!cmgr->io_bdt_pool[i]) { QEDF_WARN(&(qedf->dbg_ctx), "Failed to alloc io_bdt_pool[%d].\n", i); @@ -930,8 +926,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) return false; } -int -qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct qedf_ctx *qedf = lport_priv(lport); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 436bd29d5eba..da429b3a4283 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -699,7 +699,7 @@ static u32 qedf_get_login_failures(void *cookie) } static struct qed_fcoe_cb_ops qedf_cb_ops = { - { + .common = { .link_update = qedf_link_update, .bw_update = qedf_bw_update, .schedule_recovery_handler = qedf_schedule_recovery_handler, @@ -2082,7 +2082,7 @@ static struct fc_host_statistics *qedf_fc_get_host_stats(struct Scsi_Host if (lport->vport) goto out; - fw_fcoe_stats = kmalloc(sizeof(struct qed_fcoe_stats), GFP_KERNEL); + fw_fcoe_stats = kmalloc_obj(struct qed_fcoe_stats); if (!fw_fcoe_stats) { QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate memory for " "fw_fcoe_stats.\n"); @@ -2674,7 +2674,7 @@ static int qedf_ll2_rx(void *cookie, struct sk_buff *skb, return 0; } - skb_work = kzalloc(sizeof(struct qedf_skb_work), GFP_ATOMIC); + skb_work = kzalloc_obj(struct qedf_skb_work, GFP_ATOMIC); if (!skb_work) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate skb_work so " "dropping frame.\n"); @@ -2778,8 +2778,7 @@ static int qedf_prepare_sb(struct qedf_ctx *qedf) int ret; qedf->fp_array = - kcalloc(qedf->num_queues, sizeof(struct qedf_fastpath), - GFP_KERNEL); + kzalloc_objs(struct qedf_fastpath, qedf->num_queues); if (!qedf->fp_array) { QEDF_ERR(&(qedf->dbg_ctx), "fastpath array allocation " @@ -2790,7 +2789,7 @@ static int qedf_prepare_sb(struct qedf_ctx *qedf) for (id = 0; id < qedf->num_queues; id++) { fp = &(qedf->fp_array[id]); fp->sb_id = QEDF_SB_ID_NULL; - fp->sb_info = kcalloc(1, sizeof(*fp->sb_info), GFP_KERNEL); + fp->sb_info = kzalloc_objs(*fp->sb_info, 1); if (!fp->sb_info) { QEDF_ERR(&(qedf->dbg_ctx), "SB info struct " "allocation failed.\n"); @@ -3083,8 +3082,7 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf) /* Allocate a CQ and an associated PBL for each MSI-X vector */ for (i = 0; i < qedf->num_queues; i++) { - qedf->global_queues[i] = kzalloc(sizeof(struct global_queue), - GFP_KERNEL); + qedf->global_queues[i] = kzalloc_obj(struct global_queue); if (!qedf->global_queues[i]) { QEDF_WARN(&(qedf->dbg_ctx), "Unable to allocate " "global queue %d.\n", i); @@ -3374,7 +3372,8 @@ retry_probe: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO, "qedf->io_mempool=%p.\n", qedf->io_mempool); - qedf->link_update_wq = alloc_workqueue("qedf_%u_link", WQ_MEM_RECLAIM, + qedf->link_update_wq = alloc_workqueue("qedf_%u_link", + WQ_MEM_RECLAIM | WQ_PERCPU, 1, qedf->lport->host->host_no); INIT_DELAYED_WORK(&qedf->link_update, qedf_handle_link_update); INIT_DELAYED_WORK(&qedf->link_recovery, qedf_link_recovery); @@ -3585,7 +3584,8 @@ retry_probe: ether_addr_copy(params.ll2_mac_address, qedf->mac); /* Start LL2 processing thread */ - qedf->ll2_recv_wq = alloc_workqueue("qedf_%d_ll2", WQ_MEM_RECLAIM, 1, + qedf->ll2_recv_wq = alloc_workqueue("qedf_%d_ll2", + WQ_MEM_RECLAIM | WQ_PERCPU, 1, host->host_no); if (!qedf->ll2_recv_wq) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to LL2 workqueue.\n"); @@ -3628,7 +3628,8 @@ retry_probe: } qedf->timer_work_queue = alloc_workqueue("qedf_%u_timer", - WQ_MEM_RECLAIM, 1, qedf->lport->host->host_no); + WQ_MEM_RECLAIM | WQ_PERCPU, 1, + qedf->lport->host->host_no); if (!qedf->timer_work_queue) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to start timer " "workqueue.\n"); @@ -3641,7 +3642,8 @@ retry_probe: sprintf(host_buf, "qedf_%u_dpc", qedf->lport->host->host_no); qedf->dpc_wq = - alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, host_buf); + alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_PERCPU, 1, + host_buf); } INIT_DELAYED_WORK(&qedf->recovery_work, qedf_recovery_handler); @@ -4177,7 +4179,8 @@ static int __init qedf_init(void) goto err3; } - qedf_io_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, "qedf_io_wq"); + qedf_io_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_PERCPU, 1, + "qedf_io_wq"); if (!qedf_io_wq) { QEDF_ERR(NULL, "Could not create qedf_io_wq.\n"); goto err4; diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c index 2ebef4d20b5b..2f3e044b818f 100644 --- a/drivers/scsi/qedi/qedi_dbg.c +++ b/drivers/scsi/qedi/qedi_dbg.c @@ -103,25 +103,3 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, ret: va_end(va); } - -int -qedi_create_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) -{ - int ret = 0; - - for (; iter->name; iter++) { - ret = sysfs_create_bin_file(&shost->shost_gendev.kobj, - iter->attr); - if (ret) - pr_err("Unable to create sysfs %s attr, err(%d).\n", - iter->name, ret); - } - return ret; -} - -void -qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) -{ - for (; iter->name; iter++) - sysfs_remove_bin_file(&shost->shost_gendev.kobj, iter->attr); -} diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h index 5a1ec4542183..864951865869 100644 --- a/drivers/scsi/qedi/qedi_dbg.h +++ b/drivers/scsi/qedi/qedi_dbg.h @@ -87,18 +87,6 @@ void qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, void qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, u32 info, const char *fmt, ...); -struct Scsi_Host; - -struct sysfs_bin_attrs { - char *name; - const struct bin_attribute *attr; -}; - -int qedi_create_sysfs_attr(struct Scsi_Host *shost, - struct sysfs_bin_attrs *iter); -void qedi_remove_sysfs_attr(struct Scsi_Host *shost, - struct sysfs_bin_attrs *iter); - /* DebugFS related code */ struct qedi_list_of_funcs { char *oper_str; diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index 6901738324da..854efa4f61d8 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -190,7 +190,7 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi, cqe_tmp_response = &cqe->cqe_common.iscsi_hdr.tmf_response; qedi_cmd = task->dd_data; - qedi_cmd->tmf_resp_buf = kzalloc(sizeof(*resp_hdr_ptr), GFP_ATOMIC); + qedi_cmd->tmf_resp_buf = kzalloc_obj(*resp_hdr_ptr, GFP_ATOMIC); if (!qedi_cmd->tmf_resp_buf) { QEDI_ERR(&qedi->dbg_ctx, "Failed to allocate resp buf, cid=0x%x\n", @@ -1358,7 +1358,7 @@ static void qedi_abort_work(struct work_struct *work) goto clear_cleanup; } - list_work = kzalloc(sizeof(*list_work), GFP_NOIO); + list_work = kzalloc_obj(*list_work, GFP_NOIO); if (!list_work) { QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n"); goto clear_cleanup; diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h index 772218445a56..5e10441f2e22 100644 --- a/drivers/scsi/qedi/qedi_gbl.h +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -45,7 +45,6 @@ int qedi_iscsi_cleanup_task(struct iscsi_task *task, void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd); void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, struct qedi_cmd *qedi_cmd); -void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt); void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid); void qedi_process_iscsi_error(struct qedi_endpoint *ep, struct iscsi_eqe_data *data); diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 6ed8ef97642c..6ab3a989d281 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -440,7 +440,7 @@ static int qedi_iscsi_update_conn(struct qedi_ctx *qedi, qedi_ep = qedi_conn->ep; - conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); + conn_info = kzalloc_obj(*conn_info); if (!conn_info) { QEDI_ERR(&qedi->dbg_ctx, "memory alloc failed\n"); return -ENOMEM; @@ -505,7 +505,7 @@ static int qedi_iscsi_offload_conn(struct qedi_endpoint *qedi_ep) int rval; int i; - conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); + conn_info = kzalloc_obj(*conn_info); if (!conn_info) { QEDI_ERR(&qedi->dbg_ctx, "Failed to allocate memory ep=%p\n", qedi_ep); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index c9539897048a..227ff7bd1bdc 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -276,7 +276,7 @@ static int qedi_alloc_uio_rings(struct qedi_ctx *qedi) } } - udev = kzalloc(sizeof(*udev), GFP_KERNEL); + udev = kzalloc_obj(*udev); if (!udev) goto err_udev; @@ -410,16 +410,16 @@ static int qedi_alloc_fp(struct qedi_ctx *qedi) { int ret = 0; - qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), - sizeof(struct qedi_fastpath), GFP_KERNEL); + qedi->fp_array = kzalloc_objs(struct qedi_fastpath, + MIN_NUM_CPUS_MSIX(qedi)); if (!qedi->fp_array) { QEDI_ERR(&qedi->dbg_ctx, "fastpath fp array allocation failed.\n"); return -ENOMEM; } - qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), - sizeof(struct qed_sb_info), GFP_KERNEL); + qedi->sb_array = kzalloc_objs(struct qed_sb_info, + MIN_NUM_CPUS_MSIX(qedi)); if (!qedi->sb_array) { QEDI_ERR(&qedi->dbg_ctx, "fastpath sb array allocation failed.\n"); @@ -498,9 +498,8 @@ static int qedi_setup_cid_que(struct qedi_ctx *qedi) if (!qedi->cid_que.cid_que_base) return -ENOMEM; - qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns, - sizeof(struct qedi_conn *), - GFP_KERNEL); + qedi->cid_que.conn_cid_tbl = kmalloc_objs(struct qedi_conn *, + qedi->max_active_conns); if (!qedi->cid_que.conn_cid_tbl) { kfree(qedi->cid_que.cid_que_base); qedi->cid_que.cid_que_base = NULL; @@ -706,7 +705,7 @@ static int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) "Allowed frame ethertype [0x%x] len [0x%x].\n", eh->h_proto, skb->len); - work = kzalloc(sizeof(*work), GFP_ATOMIC); + work = kzalloc_obj(*work, GFP_ATOMIC); if (!work) { QEDI_WARN(&qedi->dbg_ctx, "Could not allocate work so dropping frame.\n"); @@ -956,7 +955,7 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi, pri_ctrl_flags = !!(block->target[0].ctrl_flags & NVM_ISCSI_CFG_TARGET_ENABLED); if (pri_ctrl_flags) { - pri_tgt = kzalloc(sizeof(*pri_tgt), GFP_KERNEL); + pri_tgt = kzalloc_obj(*pri_tgt); if (!pri_tgt) return -1; qedi_get_boot_tgt_info(block, pri_tgt, 0); @@ -965,7 +964,7 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi, sec_ctrl_flags = !!(block->target[1].ctrl_flags & NVM_ISCSI_CFG_TARGET_ENABLED); if (sec_ctrl_flags) { - sec_tgt = kzalloc(sizeof(*sec_tgt), GFP_KERNEL); + sec_tgt = kzalloc_obj(*sec_tgt); if (!sec_tgt) { ret = -1; goto free_tgt; @@ -1066,7 +1065,7 @@ static void qedi_get_protocol_tlv_data(void *dev, void *data) struct qedi_ctx *qedi = dev; int rval = 0; - fw_iscsi_stats = kmalloc(sizeof(*fw_iscsi_stats), GFP_KERNEL); + fw_iscsi_stats = kmalloc_obj(*fw_iscsi_stats); if (!fw_iscsi_stats) { QEDI_ERR(&qedi->dbg_ctx, "Could not allocate memory for fw_iscsi_stats.\n"); @@ -1239,7 +1238,7 @@ static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe, case ISCSI_CQE_TYPE_UNSOLICITED: case ISCSI_CQE_TYPE_DUMMY: case ISCSI_CQE_TYPE_TASK_CLEANUP: - qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC); + qedi_work = kzalloc_obj(*qedi_work, GFP_ATOMIC); if (!qedi_work) { rc = -1; break; @@ -1668,8 +1667,7 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi) */ for (i = 0; i < qedi->num_queues; i++) { qedi->global_queues[i] = - kzalloc(sizeof(*qedi->global_queues[0]), - GFP_KERNEL); + kzalloc_obj(*qedi->global_queues[0]); if (!qedi->global_queues[i]) { QEDI_ERR(&qedi->dbg_ctx, "Unable to allocation global queue %d.\n", i); @@ -1877,14 +1875,6 @@ void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) WARN_ON(1); } -void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) -{ - *proto_itt = qedi->itt_map[tid].itt; - QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, - "Get itt map tid [0x%x with proto itt[0x%x]", - tid, *proto_itt); -} - struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) { struct qedi_cmd *cmd = NULL; @@ -1903,8 +1893,8 @@ struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) static int qedi_alloc_itt(struct qedi_ctx *qedi) { - qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES, - sizeof(struct qedi_itt_map), GFP_KERNEL); + qedi->itt_map = kzalloc_objs(struct qedi_itt_map, + MAX_ISCSI_TASK_ENTRIES); if (!qedi->itt_map) { QEDI_ERR(&qedi->dbg_ctx, "Unable to allocate itt map array memory\n"); @@ -2776,7 +2766,7 @@ retry_probe: } qedi->offload_thread = alloc_workqueue("qedi_ofld%d", - WQ_MEM_RECLAIM, + WQ_MEM_RECLAIM | WQ_PERCPU, 1, qedi->shost->host_no); if (!qedi->offload_thread) { QEDI_ERR(&qedi->dbg_ctx, @@ -2876,7 +2866,7 @@ MODULE_DEVICE_TABLE(pci, qedi_pci_tbl); static enum cpuhp_state qedi_cpuhp_state; -static struct pci_error_handlers qedi_err_handler = { +static const struct pci_error_handlers qedi_err_handler = { .error_detected = qedi_io_error_detected, }; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 47d74f881948..cdd6fe002c32 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -406,9 +406,11 @@ static int qla1280_device_reset(struct scsi_qla_host *, int, int); static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); static int qla1280_abort_isp(struct scsi_qla_host *); #ifdef QLA_64BIT_PTR -static int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *, + struct srb *); #else -static int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *, + struct srb *); #endif static void qla1280_nv_write(struct scsi_qla_host *, uint16_t); static void qla1280_poll(struct scsi_qla_host *); @@ -682,12 +684,12 @@ qla1280_info(struct Scsi_Host *host) * handling). Unfortunately, it sometimes calls the scheduler in interrupt * context which is a big NO! NO!. **************************************************************************/ -static int qla1280_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qla1280_queuecommand_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; struct srb *sp = scsi_cmd_priv(cmd); - int status; + enum scsi_qc_status status; sp->cmd = cmd; sp->flags = 0; @@ -721,7 +723,7 @@ enum action { static void qla1280_mailbox_timeout(struct timer_list *t) { - struct scsi_qla_host *ha = from_timer(ha, t, mailbox_timer); + struct scsi_qla_host *ha = timer_container_of(ha, t, mailbox_timer); struct device_reg __iomem *reg; reg = ha->iobase; @@ -1023,7 +1025,7 @@ qla1280_eh_adapter_reset(struct scsi_cmnd *cmd) } static int -qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev, +qla1280_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; @@ -2454,7 +2456,7 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) qla1280_debounce_register(®->istatus); wait_for_completion(&wait); - del_timer_sync(&ha->mailbox_timer); + timer_delete_sync(&ha->mailbox_timer); spin_lock_irq(ha->host->host_lock); @@ -2730,7 +2732,7 @@ qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type) * 0 = success, was able to issue command. */ #ifdef QLA_64BIT_PTR -static int +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; @@ -2738,7 +2740,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) cmd_a64_entry_t *pkt; __le32 *dword_ptr; dma_addr_t dma_handle; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; @@ -2799,7 +2801,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) dprintk(2, "start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd)); - dprintk(2, " bus %i, target %i, lun %i\n", + dprintk(2, " bus %i, target %i, lun %llu\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); qla1280_dump_buffer(2, cmd->cmnd, MAX_COMMAND_SIZE); @@ -2871,7 +2873,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) remseg--; } dprintk(5, "qla1280_64bit_start_scsi: Scatter/gather " - "command packet data - b %i, t %i, l %i \n", + "command packet data - b %i, t %i, l %llu\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); qla1280_dump_buffer(5, (char *)pkt, @@ -2929,14 +2931,14 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) remseg -= cnt; dprintk(5, "qla1280_64bit_start_scsi: " "continuation packet data - b %i, t " - "%i, l %i \n", SCSI_BUS_32(cmd), + "%i, l %llu\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE); } } else { /* No data transfer */ dprintk(5, "qla1280_64bit_start_scsi: No data, command " - "packet data - b %i, t %i, l %i \n", + "packet data - b %i, t %i, l %llu\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE); } @@ -2984,14 +2986,14 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) * Returns: * 0 = success, was able to issue command. */ -static int +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; __le32 *dword_ptr; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; @@ -3655,7 +3657,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, dprintk(2, "qla1280_status_entry: Check " "condition Sense data, b %i, t %i, " - "l %i\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), + "l %llu\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); if (sense_sz) qla1280_dump_buffer(2, @@ -3955,7 +3957,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) sp = scsi_cmd_priv(cmd); printk("SCSI Command @= 0x%p, Handle=0x%p\n", cmd, CMD_HANDLE(cmd)); - printk(" chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + printk(" chan=%d, target = 0x%02x, lun = 0x%02llx, cmd_len = 0x%02x\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd), CMD_CDBLEN(cmd)); printk(" CDB = "); @@ -3976,29 +3978,6 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow, cmd->sc_data_direction); } - -/************************************************************************** - * ql1280_dump_device - * - **************************************************************************/ -static void -ql1280_dump_device(struct scsi_qla_host *ha) -{ - - struct scsi_cmnd *cp; - struct srb *sp; - int i; - - printk(KERN_DEBUG "Outstanding Commands on controller:\n"); - - for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { - if ((sp = ha->outstanding_cmds[i]) == NULL) - continue; - if ((cp = sp->cmd) == NULL) - continue; - qla1280_print_scsi_cmd(1, cp); - } -} #endif diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index a8b4314bfd6e..6946d7155bc2 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -25,11 +25,7 @@ config SCSI_QLA_FC Upon request, the driver caches the firmware image until the driver is unloaded. - Firmware images can be retrieved from: - - http://ldriver.qlogic.com/firmware/ - - They are also included in the linux-firmware tree as well. + Firmware images are included in the linux-firmware tree. config TCM_QLA2XXX tristate "TCM_QLA2XXX fabric module for QLogic 24xx+ series target mode HBAs" diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index dcb0c2af1fa7..6a05ce195aa0 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -174,8 +174,8 @@ static const struct bin_attribute sysfs_fw_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_fw_dump, - .write_new = qla2x00_sysfs_write_fw_dump, + .read = qla2x00_sysfs_read_fw_dump, + .write = qla2x00_sysfs_write_fw_dump, }; static ssize_t @@ -288,8 +288,8 @@ static const struct bin_attribute sysfs_nvram_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 512, - .read_new = qla2x00_sysfs_read_nvram, - .write_new = qla2x00_sysfs_write_nvram, + .read = qla2x00_sysfs_read_nvram, + .write = qla2x00_sysfs_write_nvram, }; static ssize_t @@ -350,8 +350,8 @@ static const struct bin_attribute sysfs_optrom_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_optrom, - .write_new = qla2x00_sysfs_write_optrom, + .read = qla2x00_sysfs_read_optrom, + .write = qla2x00_sysfs_write_optrom, }; static ssize_t @@ -535,7 +535,7 @@ static const struct bin_attribute sysfs_optrom_ctl_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_sysfs_write_optrom_ctl, + .write = qla2x00_sysfs_write_optrom_ctl, }; static ssize_t @@ -648,8 +648,8 @@ static const struct bin_attribute sysfs_vpd_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_vpd, - .write_new = qla2x00_sysfs_write_vpd, + .read = qla2x00_sysfs_read_vpd, + .write = qla2x00_sysfs_write_vpd, }; static ssize_t @@ -685,7 +685,7 @@ static const struct bin_attribute sysfs_sfp_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = SFP_DEV_SIZE, - .read_new = qla2x00_sysfs_read_sfp, + .read = qla2x00_sysfs_read_sfp, }; static ssize_t @@ -829,7 +829,7 @@ static const struct bin_attribute sysfs_reset_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_sysfs_write_reset, + .write = qla2x00_sysfs_write_reset, }; static ssize_t @@ -872,7 +872,7 @@ static const struct bin_attribute sysfs_issue_logo_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_issue_logo, + .write = qla2x00_issue_logo, }; static ssize_t @@ -935,7 +935,7 @@ static const struct bin_attribute sysfs_xgmac_stats_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_xgmac_stats, + .read = qla2x00_sysfs_read_xgmac_stats, }; static ssize_t @@ -993,7 +993,7 @@ static const struct bin_attribute sysfs_dcbx_tlv_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_dcbx_tlv, + .read = qla2x00_sysfs_read_dcbx_tlv, }; static struct sysfs_entry { @@ -1638,7 +1638,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); int rval = QLA_FUNCTION_FAILED; - uint16_t state[6]; + uint16_t state[16]; uint32_t pstate; if (IS_QLAFX00(vha->hw)) { @@ -2402,6 +2402,63 @@ qla2x00_dport_diagnostics_show(struct device *dev, vha->dport_data[0], vha->dport_data[1], vha->dport_data[2], vha->dport_data[3]); } + +static ssize_t +qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int rval = QLA_FUNCTION_FAILED; + u16 state[16]; + u16 mpi_state; + struct qla_hw_data *ha = vha->hw; + + if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha))) + return scnprintf(buf, PAGE_SIZE, + "MPI state reporting is not supported for this HBA.\n"); + + memset(state, 0, sizeof(state)); + + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); + ql_dbg(ql_dbg_user, vha, 0x70df, + "ISP reset is in progress, failing mpi_fw_state.\n"); + return -EBUSY; + } else if (vha->hw->flags.eeh_busy) { + mutex_unlock(&vha->hw->optrom_mutex); + ql_dbg(ql_dbg_user, vha, 0x70ea, + "HBA in PCI error state, failing mpi_fw_state.\n"); + return -EBUSY; + } + + rval = qla2x00_get_firmware_state(vha, state); + mutex_unlock(&vha->hw->optrom_mutex); + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_user, vha, 0x70eb, + "MB Command to retrieve MPI state failed (%d), failing mpi_fw_state.\n", + rval); + return -EIO; + } + + mpi_state = state[11]; + + if (!(mpi_state & BIT_15)) + return scnprintf(buf, PAGE_SIZE, + "MPI firmware state reporting is not supported by this firmware. (0x%02x)\n", + mpi_state); + + if (!(mpi_state & BIT_8)) + return scnprintf(buf, PAGE_SIZE, + "MPI firmware is disabled. (0x%02x)\n", + mpi_state); + + return scnprintf(buf, PAGE_SIZE, + "MPI firmware is enabled, state is %s. (0x%02x)\n", + mpi_state & BIT_9 ? "active" : "inactive", + mpi_state); +} + static DEVICE_ATTR(dport_diagnostics, 0444, qla2x00_dport_diagnostics_show, NULL); @@ -2469,6 +2526,8 @@ static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show, qla2x00_port_speed_store); static DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL); static DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL); +static DEVICE_ATTR(mpi_fw_state, 0444, qla2x00_mpi_fw_state_show, NULL); + static struct attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version.attr.attr, @@ -2517,6 +2576,7 @@ static struct attribute *qla2x00_host_attrs[] = { &dev_attr_qlini_mode.attr, &dev_attr_ql2xiniexchg.attr, &dev_attr_ql2xexchoffld.attr, + &dev_attr_mpi_fw_state.attr, NULL, }; diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 10431a67d202..5e910b5ca670 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -11,6 +11,8 @@ #include <linux/delay.h> #include <linux/bsg-lib.h> +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job); + static void qla2xxx_free_fcport_work(struct work_struct *work) { struct fc_port *fcport = container_of(work, typeof(*fcport), @@ -1546,8 +1548,9 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; mutex_unlock(&ha->optrom_mutex); - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!rval) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rval; } @@ -2392,7 +2395,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) !IS_QLA28XX(vha->hw)) return -EPERM; - dd = kmalloc(sizeof(*dd), GFP_KERNEL); + dd = kmalloc_obj(*dd); if (!dd) { ql_log(ql_log_warn, vha, 0x70db, "Failed to allocate memory for dport.\n"); @@ -2438,7 +2441,7 @@ qla2x00_do_dport_diagnostics_v2(struct bsg_job *bsg_job) if (!IS_DPORT_CAPABLE(vha->hw)) return -EPERM; - dd = kzalloc(sizeof(*dd), GFP_KERNEL); + dd = kzalloc_obj(*dd); if (!dd) return -ENOMEM; @@ -2550,6 +2553,30 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job) } static int +qla2x00_get_drv_attr(struct bsg_job *bsg_job) +{ + struct qla_drv_attr drv_attr; + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + + memset(&drv_attr, 0, sizeof(struct qla_drv_attr)); + drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT; + + + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, &drv_attr, + sizeof(struct qla_drv_attr)); + + bsg_reply->reply_payload_rcv_len = sizeof(struct qla_drv_attr); + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_reply->result = DID_OK << 16; + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return 0; +} + +static int qla2x00_manage_host_stats(struct bsg_job *bsg_job) { scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); @@ -2571,7 +2598,7 @@ qla2x00_manage_host_stats(struct bsg_job *bsg_job) return -EIO; } - req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + req_data = kzalloc_obj(*req_data); if (!req_data) { ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); return -ENOMEM; @@ -2612,8 +2639,9 @@ qla2x00_manage_host_stats(struct bsg_job *bsg_job) sizeof(struct ql_vnd_mng_host_stats_resp)); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return ret; } @@ -2641,7 +2669,7 @@ qla2x00_get_host_stats(struct bsg_job *bsg_job) return -EIO; } - req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + req_data = kzalloc_obj(*req_data); if (!req_data) { ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); return -ENOMEM; @@ -2702,8 +2730,9 @@ qla2x00_get_host_stats(struct bsg_job *bsg_job) bsg_job->reply_payload.sg_cnt, data, response_len); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); kfree(data); host_stat_out: @@ -2747,7 +2776,7 @@ qla2x00_get_tgt_stats(struct bsg_job *bsg_job) return -EIO; } - req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + req_data = kzalloc_obj(*req_data); if (!req_data) { ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); return -ENOMEM; @@ -2802,8 +2831,9 @@ reply: bsg_job->reply_payload.sg_cnt, data, response_len); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); tgt_stat_out: kfree(data); @@ -2829,7 +2859,7 @@ qla2x00_manage_host_port(struct bsg_job *bsg_job) return -EIO; } - req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + req_data = kzalloc_obj(*req_data); if (!req_data) { ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n"); return -ENOMEM; @@ -2864,8 +2894,9 @@ qla2x00_manage_host_port(struct bsg_job *bsg_job) bsg_job->reply_payload.sg_cnt, &rsp_data, sizeof(struct ql_vnd_mng_host_port_resp)); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return ret; } @@ -2933,6 +2964,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j case QL_VND_GET_FLASH_UPDATE_CAPS: return qla27xx_get_flash_upd_cap(bsg_job); + case QL_VND_GET_DRV_ATTR: + return qla2x00_get_drv_attr(bsg_job); + + case QL_VND_IMG_SET_VALID: + return qla28xx_validate_flash_image(bsg_job); + case QL_VND_SET_FLASH_UPDATE_CAPS: return qla27xx_set_flash_upd_cap(bsg_job); @@ -3106,8 +3143,8 @@ static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job) switch (rval) { case QLA_SUCCESS: /* Wait for the command completion. */ - ratov_j = ha->r_a_tov / 10 * 4 * 1000; - ratov_j = msecs_to_jiffies(ratov_j); + ratov_j = ha->r_a_tov / 10 * 4; + ratov_j = secs_to_jiffies(ratov_j); if (!wait_for_completion_timeout(&comp, ratov_j)) { ql_log(ql_log_info, vha, 0x7089, @@ -3240,9 +3277,97 @@ int qla2x00_mailbox_passthru(struct bsg_job *bsg_job) bsg_job->reply_len = sizeof(*bsg_job->reply); bsg_reply->result = DID_OK << 16; - bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); kfree(req_data); return ret; } + +static int +qla28xx_do_validate_flash_image(struct bsg_job *bsg_job, uint16_t *state) +{ + struct fc_bsg_request *bsg_request = bsg_job->request; + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + uint16_t mstate[16]; + uint16_t mpi_state = 0; + uint16_t img_idx; + int rval = QLA_SUCCESS; + + memset(mstate, 0, sizeof(mstate)); + + rval = qla2x00_get_firmware_state(vha, mstate); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "MBC to get MPI state failed (%d)\n", rval); + rval = -EINVAL; + goto exit_flash_img; + } + + mpi_state = mstate[11]; + + if (!(mpi_state & BIT_9 && mpi_state & BIT_8 && mpi_state & BIT_15)) { + ql_log(ql_log_warn, vha, 0xffff, + "MPI firmware state failed (0x%02x)\n", mpi_state); + rval = -EINVAL; + goto exit_flash_img; + } + + rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to lock flash semaphore."); + goto exit_flash_img; + } + + img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + + rval = qla_mpipt_validate_fw(vha, img_idx, state); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to validate Firmware image index [0x%x].\n", + img_idx); + } + + qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); + +exit_flash_img: + return rval; +} + +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct qla_hw_data *ha = vha->hw; + uint16_t state = 0; + int rval = 0; + + if (!IS_QLA28XX(ha) || vha->vp_idx != 0) + return -EPERM; + + mutex_lock(&ha->optrom_mutex); + rval = qla28xx_do_validate_flash_image(bsg_job, &state); + if (rval) + rval = -EINVAL; + mutex_unlock(&ha->optrom_mutex); + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + + if (rval) + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + (state == 39) ? EXT_STATUS_IMG_SET_VALID_ERR : + EXT_STATUS_IMG_SET_CONFIG_ERR; + else + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_reply->result = DID_OK << 16; + bsg_reply->reply_payload_rcv_len = 0; + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + if (!rval) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + + return QLA_SUCCESS; +} diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index d38dab0a07e8..a920c8e482bc 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -32,12 +32,14 @@ #define QL_VND_GET_PRIV_STATS_EX 0x1A #define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E #define QL_VND_EDIF_MGMT 0X1F +#define QL_VND_GET_DRV_ATTR 0x22 #define QL_VND_MANAGE_HOST_STATS 0x23 #define QL_VND_GET_HOST_STATS 0x24 #define QL_VND_GET_TGT_STATS 0x25 #define QL_VND_MANAGE_HOST_PORT 0x26 #define QL_VND_MBX_PASSTHRU 0x2B #define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C +#define QL_VND_IMG_SET_VALID 0x30 /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -50,6 +52,8 @@ #define EXT_STATUS_BUFFER_TOO_SMALL 16 #define EXT_STATUS_NO_MEMORY 17 #define EXT_STATUS_DEVICE_OFFLINE 22 +#define EXT_STATUS_IMG_SET_VALID_ERR 47 +#define EXT_STATUS_IMG_SET_CONFIG_ERR 48 /* * To support bidirectional iocb @@ -318,6 +322,14 @@ struct qla_active_regions { uint8_t reserved[31]; } __packed; +struct qla_drv_attr { + uint32_t attributes; + u32 ext_attributes; +#define QLA_IMG_SET_VALID_SUPPORT BIT_4 + u32 status_flags; + uint8_t reserved[20]; +} __packed; + #include "qla_edif_bsg.h" #endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 691ef827a5ab..a7e3ec9bba47 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -54,10 +54,11 @@ * | Misc | 0xd303 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | - * | Target Mode | 0xe081 | | + * | Target Mode | 0xe089 | | * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | + * | Target Mode SRR | 0x11038 | | * ---------------------------------------------------------------------- */ @@ -2706,59 +2707,6 @@ ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, const void *buf, } /* - * This function is for formatting and logging log messages. - * It is to be used when vha is available. It formats the message - * and logs it to the messages file. All the messages will be logged - * irrespective of value of ql2xextended_error_logging. - * parameters: - * level: The level of the log messages to be printed in the - * messages file. - * vha: Pointer to the scsi_qla_host_t - * id: This is a unique id for the level. It identifies the - * part of the code from where the message originated. - * msg: The message to be displayed. - */ -void -ql_log_qp(uint32_t level, struct qla_qpair *qpair, int32_t id, - const char *fmt, ...) -{ - va_list va; - struct va_format vaf; - char pbuf[128]; - - if (level > ql_errlev) - return; - - ql_ktrace(0, level, pbuf, NULL, qpair ? qpair->vha : NULL, id, fmt); - - if (!pbuf[0]) /* set by ql_ktrace */ - ql_dbg_prefix(pbuf, ARRAY_SIZE(pbuf), NULL, - qpair ? qpair->vha : NULL, id); - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - switch (level) { - case ql_log_fatal: /* FATAL LOG */ - pr_crit("%s%pV", pbuf, &vaf); - break; - case ql_log_warn: - pr_err("%s%pV", pbuf, &vaf); - break; - case ql_log_info: - pr_warn("%s%pV", pbuf, &vaf); - break; - default: - pr_info("%s%pV", pbuf, &vaf); - break; - } - - va_end(va); -} - -/* * This function is for formatting and logging debug information. * It is to be used when vha is available. It formats the message * and logs it to the messages file. diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 54f0a412226f..5f4a8c9ae6ba 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -334,9 +334,6 @@ ql_log(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) ql_log_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...); -void __attribute__((format (printf, 4, 5))) -ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); - /* Debug Levels */ /* The 0x40000000 is the max value any debug level can have * as ql2xextended_error_logging is of type signed int diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cb95b7b12051..5593ad7fad27 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1270,6 +1270,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) */ #define MBC_LOAD_RAM 1 /* Load RAM. */ #define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_LOAD_FLASH_FIRMWARE 3 /* Load flash firmware. */ #define MBC_READ_RAM_WORD 5 /* Read RAM word. */ #define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ #define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ @@ -1385,6 +1386,26 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define HCS_WRITE_SERDES 0x3 #define HCS_READ_SERDES 0x4 +/* + * ISP2[7|8]xx mailbox commands. + */ +#define MBC_MPI_PASSTHROUGH 0x200 + +/* MBC_MPI_PASSTHROUGH */ +#define MPIPT_REQ_V1 1 +enum { + MPIPT_SUBCMD_GET_SUP_CMD = 0x10, + MPIPT_SUBCMD_GET_SUP_FEATURE, + MPIPT_SUBCMD_GET_STATUS, + MPIPT_SUBCMD_VALIDATE_FW, +}; + +enum { + MPIPT_MPI_STATUS = 1, + MPIPT_FCORE_STATUS, + MPIPT_LOCKDOWN_STATUS, +}; + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -3503,7 +3524,6 @@ 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 @@ -4150,6 +4170,7 @@ struct qla_hw_data { uint32_t eeh_flush:2; #define EEH_FLUSH_RDY 1 #define EEH_FLUSH_DONE 2 + uint32_t secure_mcu:1; } flags; uint16_t max_exchg; @@ -4415,6 +4436,8 @@ struct qla_hw_data { ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&\ (ha->zio_mode == QLA_ZIO_MODE_6)) +#define IS_QLA28XX_SECURED(ha) (IS_QLA28XX(ha) && ha->flags.secure_mcu) + /* HBA serial number */ uint8_t serial0; uint8_t serial1; @@ -5369,7 +5392,7 @@ struct edif_sa_index_entry { struct list_head next; }; -/* Refer to SNIA SFF 8247 */ +/* Refer to SNIA SFF 8472 */ struct sff_8247_a0 { u8 txid; /* transceiver id */ u8 ext_txid; @@ -5413,6 +5436,7 @@ struct sff_8247_a0 { #define FC_SP_32 BIT_3 #define FC_SP_2 BIT_2 #define FC_SP_1 BIT_0 +#define FC_SPEED_2 BIT_1 u8 fc_sp_cc10; u8 encode; u8 bitrate; @@ -5431,7 +5455,8 @@ struct sff_8247_a0 { u8 vendor_pn[SFF_PART_NAME_LEN]; /* part number */ u8 vendor_rev[4]; u8 wavelength[2]; - u8 resv; +#define FC_SP_64 BIT_0 + u8 fiber_channel_speed2; u8 cc_base; u8 options[2]; /* offset 64 */ u8 br_max; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 08273520c777..43970caca7b3 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -179,10 +179,9 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) struct qla_hw_data *ha = vha->hw; struct gid_list_info *gid_list; dma_addr_t gid_list_dma; - fc_port_t fc_port; char *id_iter; int rc, i; - uint16_t entries, loop_id; + uint16_t entries; seq_printf(s, "%s\n", vha->host_str); gid_list = dma_alloc_coherent(&ha->pdev->dev, @@ -205,18 +204,11 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) seq_puts(s, "Port Name Port ID Loop ID\n"); for (i = 0; i < entries; i++) { - struct gid_list_info *gid = - (struct gid_list_info *)id_iter; - loop_id = le16_to_cpu(gid->loop_id); - memset(&fc_port, 0, sizeof(fc_port_t)); - - fc_port.loop_id = loop_id; - - rc = qla24xx_gpdb_wait(vha, &fc_port, 0); - seq_printf(s, "%8phC %02x%02x%02x %d\n", - fc_port.port_name, fc_port.d_id.b.domain, - fc_port.d_id.b.area, fc_port.d_id.b.al_pa, - fc_port.loop_id); + struct gid_list_info *gid = (struct gid_list_info *)id_iter; + + rc = qla24xx_print_fc_port_id(vha, s, le16_to_cpu(gid->loop_id)); + if (rc != QLA_SUCCESS) + break; id_iter += ha->gid_list_info_size; } out_free_id_list: diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c index dcde55c8ee5d..eccedb38a515 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -94,7 +94,8 @@ static struct edif_list_entry *qla_edif_list_find_sa_index(fc_port_t *fcport, /* timeout called when no traffic and delayed rx sa_index delete */ static void qla2x00_sa_replace_iocb_timeout(struct timer_list *t) { - struct edif_list_entry *edif_entry = from_timer(edif_entry, t, timer); + struct edif_list_entry *edif_entry = timer_container_of(edif_entry, t, + timer); fc_port_t *fcport = edif_entry->fcport; struct scsi_qla_host *vha = fcport->vha; struct edif_sa_ctl *sa_ctl; @@ -173,7 +174,7 @@ static int qla_edif_list_add_sa_update_index(fc_port_t *fcport, * when update is called for the first two sa_indexes * followed by a delete of the first sa_index */ - entry = kzalloc((sizeof(struct edif_list_entry)), GFP_ATOMIC); + entry = kzalloc_obj(struct edif_list_entry, GFP_ATOMIC); if (!entry) return -ENOMEM; @@ -1392,7 +1393,7 @@ qla_edif_add_sa_ctl(fc_port_t *fcport, struct qla_sa_update_frame *sa_frame, int index = sa_frame->fast_sa_index; unsigned long flags = 0; - sa_ctl = kzalloc(sizeof(*sa_ctl), GFP_KERNEL); + sa_ctl = kzalloc_obj(*sa_ctl); if (!sa_ctl) { /* couldn't get space */ ql_dbg(ql_dbg_edif, fcport->vha, 0x9100, @@ -1797,7 +1798,7 @@ retry: switch (rval) { case QLA_SUCCESS: break; - case EAGAIN: + case -EAGAIN: msleep(EDIF_MSLEEP_INTERVAL); cnt++; if (cnt < EDIF_RETRY_COUNT) @@ -2186,7 +2187,7 @@ qla_edb_node_alloc(scsi_qla_host_t *vha, uint32_t ntype) { struct edb_node *node; - node = kzalloc(sizeof(*node), GFP_ATOMIC); + node = kzalloc_obj(*node, GFP_ATOMIC); if (!node) { /* couldn't get space */ ql_dbg(ql_dbg_edif, vha, 0x9100, @@ -3278,7 +3279,7 @@ static uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport, } /* if there is no entry for this nport, add one */ - entry = kzalloc((sizeof(struct edif_sa_index_entry)), GFP_ATOMIC); + entry = kzalloc_obj(struct edif_sa_index_entry, GFP_ATOMIC); if (!entry) return INVALID_EDIF_SA_INDEX; @@ -3380,7 +3381,7 @@ void qla_edif_sadb_release(struct qla_hw_data *ha) int qla_edif_sadb_build_free_pool(struct qla_hw_data *ha) { ha->edif_tx_sa_id_map = - kcalloc(BITS_TO_LONGS(EDIF_NUM_SA_INDEX), sizeof(long), GFP_KERNEL); + kzalloc_objs(long, BITS_TO_LONGS(EDIF_NUM_SA_INDEX)); if (!ha->edif_tx_sa_id_map) { ql_log_pci(ql_log_fatal, ha->pdev, 0x0009, @@ -3389,7 +3390,7 @@ int qla_edif_sadb_build_free_pool(struct qla_hw_data *ha) } ha->edif_rx_sa_id_map = - kcalloc(BITS_TO_LONGS(EDIF_NUM_SA_INDEX), sizeof(long), GFP_KERNEL); + kzalloc_objs(long, BITS_TO_LONGS(EDIF_NUM_SA_INDEX)); if (!ha->edif_rx_sa_id_map) { kfree(ha->edif_tx_sa_id_map); ha->edif_tx_sa_id_map = NULL; @@ -3648,7 +3649,7 @@ retry: p->e.extra_rx_xchg_address, p->e.extra_control_flags, sp->handle, sp->remap.req.len, bsg_job); break; - case EAGAIN: + case -EAGAIN: msleep(EDIF_MSLEEP_INTERVAL); cnt++; if (cnt < EDIF_RETRY_COUNT) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index e556f57c91af..9e328c235e39 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -164,10 +164,8 @@ extern int ql2xsmartsan; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xextended_error_logging_ktrace; -extern int ql2xiidmaenable; extern int ql2xmqsupport; extern int ql2xfwloadbin; -extern int ql2xetsenable; extern int ql2xshiftctondsd; extern int ql2xdbwr; extern int ql2xasynctmfenable; @@ -347,6 +345,9 @@ extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); extern int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha); + +extern int qla2x00_get_fw_version(scsi_qla_host_t *); extern int @@ -559,6 +560,7 @@ qla26xx_dport_diagnostics_v2(scsi_qla_host_t *, int qla24xx_send_mb_cmd(struct scsi_qla_host *, mbx_cmd_t *); int qla24xx_gpdb_wait(struct scsi_qla_host *, fc_port_t *, u8); +int qla24xx_print_fc_port_id(struct scsi_qla_host *, struct seq_file *, u16); int qla24xx_gidlist_wait(struct scsi_qla_host *, void *, dma_addr_t, uint16_t *); int __qla24xx_parse_gpdb(struct scsi_qla_host *, fc_port_t *, @@ -720,7 +722,6 @@ extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); 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 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 *); @@ -768,7 +769,7 @@ extern int qla2x00_dfs_remove(scsi_qla_host_t *); /* Globa function prototypes for multi-q */ extern int qla25xx_request_irq(struct qla_hw_data *, struct qla_qpair *, - struct qla_msix_entry *, int); + struct qla_msix_entry *); extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, @@ -822,7 +823,6 @@ extern int qlafx00_rescan_isp(scsi_qla_host_t *); /* PCI related functions */ extern int qla82xx_pci_config(struct scsi_qla_host *); extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); -extern int qla82xx_pci_region_offset(struct pci_dev *, int); extern int qla82xx_iospace_config(struct qla_hw_data *); /* Initialization related functions */ @@ -842,6 +842,8 @@ extern int qla82xx_write_optrom_data(struct scsi_qla_host *, void *, extern int qla82xx_abort_isp(scsi_qla_host_t *); extern int qla82xx_restart_isp(scsi_qla_host_t *); +extern int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, u16 *state); + /* IOCB related functions */ extern int qla82xx_start_scsi(srb_t *); extern void qla2x00_sp_free(srb_t *sp); @@ -866,7 +868,6 @@ extern int qla82xx_rd_32(struct qla_hw_data *, ulong); /* ISP 8021 IDC */ extern void qla82xx_clear_drv_active(struct qla_hw_data *); -extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t); extern int qla82xx_idc_lock(struct qla_hw_data *); extern void qla82xx_idc_unlock(struct qla_hw_data *); extern int qla82xx_device_state_handler(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index d2bddca7045a..880cd73feaca 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -2626,96 +2626,6 @@ qla2x00_port_speed_capability(uint16_t speed) } /** - * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. - * @vha: HA context - * @list: switch info entries to populate - * - * Returns 0 on success. - */ -int -qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval; - uint16_t i; - 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; - struct ct_arg arg; - - if (!IS_IIDMA_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - if (!ha->flags.gpsc_supported) - return QLA_FUNCTION_FAILED; - - rval = qla2x00_mgmt_svr_login(vha); - if (rval) - return rval; - - arg.iocb = ha->ms_iocb; - arg.req_dma = ha->ct_sns_dma; - arg.rsp_dma = ha->ct_sns_dma; - arg.req_size = GPSC_REQ_SIZE; - arg.rsp_size = GPSC_RSP_SIZE; - arg.nport_handle = vha->mgmt_svr_loop_id; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GFPN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = qla24xx_prep_ms_iocb(vha, &arg); - - /* Prepare CT request */ - ct_req = qla24xx_prep_ct_fm_req(ha->ct_sns, GPSC_CMD, - GPSC_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_name */ - memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, - WWN_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, 0x2059, - "GPSC issue IOCB failed (%d).\n", rval); - } else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GPSC")) != QLA_SUCCESS) { - /* FM command unsupported? */ - if (rval == QLA_INVALID_COMMAND && - (ct_rsp->header.reason_code == - CT_REASON_INVALID_COMMAND_CODE || - ct_rsp->header.reason_code == - CT_REASON_COMMAND_UNSUPPORTED)) { - ql_dbg(ql_dbg_disc, vha, 0x205a, - "GPSC command unsupported, disabling " - "query.\n"); - ha->flags.gpsc_supported = 0; - rval = QLA_FUNCTION_FAILED; - break; - } - rval = QLA_FUNCTION_FAILED; - } else { - list->fp_speed = qla2x00_port_speed_capability( - be16_to_cpu(ct_rsp->rsp.gpsc.speed)); - ql_dbg(ql_dbg_disc, vha, 0x205b, - "GPSC ext entry - fpn " - "%8phN speeds=%04x speed=%04x.\n", - list[i].fabric_port_name, - be16_to_cpu(ct_rsp->rsp.gpsc.speeds), - be16_to_cpu(ct_rsp->rsp.gpsc.speed)); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. * * @vha: HA context @@ -3356,9 +3266,6 @@ login_logout: atomic_read(&fcport->state) == FCS_ONLINE) || do_delete) { if (fcport->loop_id != FC_NO_LOOP_ID) { - if (fcport->flags & FCF_FCP2_DEVICE) - continue; - ql_log(ql_log_warn, vha, 0x20f0, "%s %d %8phC post del sess\n", __func__, __LINE__, @@ -3625,8 +3532,8 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp) if (vha->scan.scan_flags & SF_SCANNING) { spin_unlock_irqrestore(&vha->work_lock, flags); ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x2012, - "%s: scan active\n", __func__); - return rval; + "%s: scan active for sp:%p\n", __func__, sp); + goto done_free_sp; } vha->scan.scan_flags |= SF_SCANNING; if (!sp) @@ -3791,23 +3698,25 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp) return rval; done_free_sp: - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } + if (sp) { + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.req_allocated_size, + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } - /* ref: INIT */ - kref_put(&sp->cmd_kref, qla2x00_sp_release); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); + } spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 79cdfec2bca3..e746c9274cde 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -45,7 +45,7 @@ static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *); void qla2x00_sp_timeout(struct timer_list *t) { - srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer); + srb_t *sp = timer_container_of(sp, t, u.iocb_cmd.timer); struct srb_iocb *iocb; scsi_qla_host_t *vha = sp->vha; @@ -67,7 +67,7 @@ void qla2x00_sp_free(srb_t *sp) { struct srb_iocb *iocb = &sp->u.iocb_cmd; - del_timer(&iocb->timer); + timer_delete(&iocb->timer); qla2x00_rel_sp(sp); } @@ -1859,15 +1859,6 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea) case RSCN_PORT_ADDR: fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1); if (fcport) { - if (ql2xfc2target && - fcport->flags & FCF_FCP2_DEVICE && - atomic_read(&fcport->state) == FCS_ONLINE) { - ql_dbg(ql_dbg_disc, vha, 0x2115, - "Delaying session delete for FCP2 portid=%06x %8phC ", - fcport->d_id.b24, fcport->port_name); - return; - } - if (vha->hw->flags.edif_enabled && DBELL_ACTIVE(vha)) { /* * On ipsec start by remote port, Target port @@ -2059,11 +2050,11 @@ static void qla_marker_sp_done(srb_t *sp, int res) int cnt = 5; \ do { \ if (_chip_gen != sp->vha->hw->chip_reset || _login_gen != sp->fcport->login_gen) {\ - _rval = EINVAL; \ + _rval = -EINVAL; \ break; \ } \ _rval = qla2x00_start_sp(_sp); \ - if (_rval == EAGAIN) \ + if (_rval == -EAGAIN) \ msleep(1); \ else \ break; \ @@ -2471,8 +2462,23 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) ea->sp->gen1, fcport->rscn_gen, ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]); - if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || - (fcport->fw_login_state == DSC_LS_PRLI_PEND)) { + if (fcport->fw_login_state == DSC_LS_PLOGI_PEND) { + ql_dbg(ql_dbg_disc, vha, 0x20ea, + "%s %d %8phC Remote is trying to login\n", + __func__, __LINE__, fcport->port_name); + /* + * If we get here, there is port thats already logged in, + * but it's state has not moved ahead. Recheck with FW on + * what state it is in and proceed ahead + */ + if (!N2N_TOPO(vha->hw)) { + fcport->fw_login_state = DSC_LS_PRLI_COMP; + qla24xx_post_gpdb_work(vha, fcport, 0); + } + return; + } + + if (fcport->fw_login_state == DSC_LS_PRLI_PEND) { ql_dbg(ql_dbg_disc, vha, 0x20ea, "%s %d %8phC Remote is trying to login\n", __func__, __LINE__, fcport->port_name); @@ -4027,9 +4033,7 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req) req->num_outstanding_cmds = ha->cur_fw_iocb_count; } - req->outstanding_cmds = kcalloc(req->num_outstanding_cmds, - sizeof(srb_t *), - GFP_KERNEL); + req->outstanding_cmds = kzalloc_objs(srb_t *, req->num_outstanding_cmds); if (!req->outstanding_cmds) { /* @@ -4037,9 +4041,8 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req) * initialization. */ req->num_outstanding_cmds = MIN_OUTSTANDING_COMMANDS; - req->outstanding_cmds = kcalloc(req->num_outstanding_cmds, - sizeof(srb_t *), - GFP_KERNEL); + req->outstanding_cmds = kzalloc_objs(srb_t *, + req->num_outstanding_cmds); if (!req->outstanding_cmds) { ql_log(ql_log_fatal, NULL, 0x0126, @@ -4074,6 +4077,22 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha) u8 str[STR_LEN], *ptr, p; int leftover, len; + ql_dbg(ql_dbg_init, vha, 0x015a, + "SFP: %.*s -> %.*s ->%s%s%s%s%s%s%s\n", + (int)sizeof(a0->vendor_name), a0->vendor_name, + (int)sizeof(a0->vendor_pn), a0->vendor_pn, + a0->fc_sp_cc10 & FC_SP_2 ? a0->fiber_channel_speed2 & FC_SP_64 ? + " 64G" : "" : "", + a0->fc_sp_cc10 & FC_SP_32 ? " 32G" : "", + a0->fc_sp_cc10 & FC_SP_16 ? " 16G" : "", + a0->fc_sp_cc10 & FC_SP_8 ? " 8G" : "", + a0->fc_sp_cc10 & FC_SP_4 ? " 4G" : "", + a0->fc_sp_cc10 & FC_SP_2 ? " 2G" : "", + a0->fc_sp_cc10 & FC_SP_1 ? " 1G" : ""); + + if (!(ql2xextended_error_logging & ql_dbg_verbose)) + return; + memset(str, 0, STR_LEN); snprintf(str, SFF_VEN_NAME_LEN+1, a0->vendor_name); ql_dbg(ql_dbg_init, vha, 0x015a, @@ -4369,6 +4388,7 @@ enable_82xx_npiv: ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; } + qlt_config_nvram_with_fw_version(vha); qla2x00_get_resource_cnts(vha); qla_init_iocb_limit(vha); @@ -4894,7 +4914,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) unsigned long wtime, mtime, cs84xx_time; uint16_t min_wait; /* Minimum wait time if loop is down */ uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t state[6]; + uint16_t state[16]; struct qla_hw_data *ha = vha->hw; if (IS_QLAFX00(vha->hw)) @@ -5551,7 +5571,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) { fc_port_t *fcport; - fcport = kzalloc(sizeof(fc_port_t), flags); + fcport = kzalloc_obj(fc_port_t, flags); if (!fcport) return NULL; @@ -6471,8 +6491,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) /* Try GID_PT to get device list, else GAN. */ if (!ha->swl) - ha->swl = kcalloc(ha->max_fibre_devices, sizeof(sw_info_t), - GFP_KERNEL); + ha->swl = kzalloc_objs(sw_info_t, ha->max_fibre_devices); swl = ha->swl; if (!swl) { /*EMPTY*/ @@ -8442,6 +8461,148 @@ bool qla24xx_risc_firmware_invalid(uint32_t *dword) } static int +qla28xx_get_srisc_addr(scsi_qla_host_t *vha, uint32_t *srisc_addr, + uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + uint32_t *dcode; + int rval; + + *srisc_addr = 0; + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01aa, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + *srisc_addr = be32_to_cpu((__force __be32)dcode[2]); + return QLA_SUCCESS; +} + +static int +qla28xx_load_fw_template(scsi_qla_host_t *vha, uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct fwdt *fwdt = ha->fwdt; + struct req_que *req = ha->req_q_map[0]; + uint32_t risc_size, risc_attr = 0; + uint templates, segments, fragment; + uint32_t *dcode; + ulong dlen; + int rval; + uint j; + + dcode = (uint32_t *)req->ring; + segments = FA_RISC_CODE_SEGMENTS; + + for (j = 0; j < segments; j++) { + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a1, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + risc_size = be32_to_cpu((__force __be32)dcode[3]); + + if (risc_attr == 0) + risc_attr = be32_to_cpu((__force __be32)dcode[9]); + + dlen = ha->fw_transfer_size >> 2; + for (fragment = 0; fragment < risc_size; fragment++) { + if (dlen > risc_size) + dlen = risc_size; + + faddr += dlen; + risc_size -= dlen; + } + } + + templates = (risc_attr & BIT_9) ? 2 : 1; + + ql_dbg(ql_dbg_init, vha, 0x01a1, "-> templates = %u\n", templates); + + for (j = 0; j < templates; j++, fwdt++) { + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 7); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a2, + "-> Unable to read template size.\n"); + goto failed; + } + + risc_size = be32_to_cpu((__force __be32)dcode[2]); + ql_dbg(ql_dbg_init, vha, 0x01a3, + "-> fwdt%u template array at %#x (%#x dwords)\n", + j, faddr, risc_size); + if (!risc_size || !~risc_size) { + ql_dbg(ql_dbg_init, vha, 0x01a4, + "-> fwdt%u failed to read array\n", j); + goto failed; + } + + /* skip header and ignore checksum */ + faddr += 7; + risc_size -= 8; + + ql_dbg(ql_dbg_init, vha, 0x01a5, + "-> fwdt%u template allocate template %#x words...\n", + j, risc_size); + fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x01a6, + "-> fwdt%u failed allocate template.\n", j); + goto failed; + } + + dcode = fwdt->template; + rval = qla24xx_read_flash_data(vha, dcode, faddr, risc_size); + + if (rval || !qla27xx_fwdt_template_valid(dcode)) { + ql_log(ql_log_warn, vha, 0x01a7, + "-> fwdt%u failed template validate (rval %x)\n", + j, rval); + goto failed; + } + + dlen = qla27xx_fwdt_template_size(dcode); + ql_dbg(ql_dbg_init, vha, 0x01a7, + "-> fwdt%u template size %#lx bytes (%#lx words)\n", + j, dlen, dlen / sizeof(*dcode)); + if (dlen > risc_size * sizeof(*dcode)) { + ql_log(ql_log_warn, vha, 0x01a8, + "-> fwdt%u template exceeds array (%-lu bytes)\n", + j, dlen - risc_size * sizeof(*dcode)); + goto failed; + } + + fwdt->length = dlen; + ql_dbg(ql_dbg_init, vha, 0x01a9, + "-> fwdt%u loaded template ok\n", j); + + faddr += risc_size + 1; + } + + return QLA_SUCCESS; + +failed: + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + return QLA_SUCCESS; +} + +static int qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, uint32_t faddr) { @@ -8603,8 +8764,6 @@ failed: return QLA_SUCCESS; } -#define QLA_FW_URL "http://ldriver.qlogic.com/firmware/" - int qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { @@ -8622,8 +8781,6 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) if (!blob) { ql_log(ql_log_info, vha, 0x0083, "Firmware image unavailable.\n"); - ql_log(ql_log_info, vha, 0x0084, - "Firmware images can be retrieved from: "QLA_FW_URL ".\n"); return QLA_FUNCTION_FAILED; } @@ -8884,16 +9041,18 @@ int qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + uint32_t f_region = 0; struct qla_hw_data *ha = vha->hw; struct active_regions active_regions = { }; - if (ql2xfwloadbin == 2) + if (ql2xfwloadbin == 2 && !IS_QLA28XX(ha)) goto try_blob_fw; /* FW Load priority: - * 1) Firmware residing in flash. - * 2) Firmware via request-firmware interface (.bin file). - * 3) Golden-Firmware residing in flash -- (limited operation). + * 1) If 28xxx, ROM cmd to load flash firmware. + * 2) Firmware residing in flash. + * 3) Firmware via request-firmware interface (.bin file). + * 4) Golden-Firmware residing in flash -- (limited operation). */ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) @@ -8901,6 +9060,40 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) qla27xx_get_active_image(vha, &active_regions); + /* For 28XXX, always load the flash firmware using rom mbx */ + if (IS_QLA28XX_SECURED(ha)) { + rval = qla28xx_load_flash_firmware(vha); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_fatal, vha, 0x019e, + "Failed to load flash firmware.\n"); + goto exit_load_risc; + } + + f_region = + (active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + ha->flt_region_fw : ha->flt_region_fw_sec; + + ql_log(ql_log_info, vha, 0x019f, + "Load flash firmware successful (%s).\n", + ((active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + "Primary" : "Secondary")); + + rval = qla28xx_get_srisc_addr(vha, srisc_addr, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x019f, + "failed to read srisc address\n"); + goto exit_load_risc; + } + + rval = qla28xx_load_fw_template(vha, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x01a0, + "failed to read firmware template\n"); + } + + goto exit_load_risc; + } + if (active_regions.global != QLA27XX_SECONDARY_IMAGE) goto try_primary_fw; @@ -8930,6 +9123,8 @@ try_blob_fw: ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n"); ha->flags.running_gold_fw = 1; + +exit_load_risc: return rval; } @@ -9032,7 +9227,7 @@ qla84xx_get_chip(struct scsi_qla_host *vha) } } - cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL); + cs84xx = kzalloc_obj(*cs84xx); if (!cs84xx) goto done; @@ -9686,7 +9881,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, } if (ql2xmqsupport || ql2xnvmeenable) { - qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); + qpair = kzalloc_obj(struct qla_qpair); if (qpair == NULL) { ql_log(ql_log_warn, vha, 0x0182, "Failed to allocate memory for queue pair.\n"); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index ef4b3cc1cd77..47fbd830ff16 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -621,8 +621,7 @@ static inline int qla_mapq_alloc_qp_cpu_map(struct qla_hw_data *ha) scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); if (!ha->qp_cpu_map) { - ha->qp_cpu_map = kcalloc(NR_CPUS, sizeof(struct qla_qpair *), - GFP_KERNEL); + ha->qp_cpu_map = kzalloc_objs(struct qla_qpair *, nr_cpu_ids); if (!ha->qp_cpu_map) { ql_log(ql_log_fatal, vha, 0x0180, "Unable to allocate memory for qp_cpu_map ptrs.\n"); diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 0b41e8a06602..dbe3cd4e274c 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -882,7 +882,7 @@ alloc_and_fill: used_dsds -= avail_dsds; /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(struct dsd_dma, GFP_ATOMIC); if (!dsd_ptr) return 1; @@ -979,7 +979,7 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, used_dsds -= avail_dsds; /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(struct dsd_dma, GFP_ATOMIC); if (!dsd_ptr) return 1; @@ -1123,8 +1123,8 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, * Allocate list item to store * the DMA buffers */ - dsd_ptr = kzalloc(sizeof(*dsd_ptr), - GFP_ATOMIC); + dsd_ptr = kzalloc_obj(*dsd_ptr, + GFP_ATOMIC); if (!dsd_ptr) { ql_dbg(ql_dbg_tgt, vha, 0xe024, "%s: failed alloc dsd_ptr\n", @@ -1209,7 +1209,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, used_dsds -= avail_dsds; /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(*dsd_ptr, GFP_ATOMIC); if (!dsd_ptr) { ql_dbg(ql_dbg_tgt, vha, 0xe026, "%s: failed alloc dsd_ptr\n", @@ -1275,7 +1275,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, used_dsds -= avail_dsds; /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(*dsd_ptr, GFP_ATOMIC); if (!dsd_ptr) { ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe027, @@ -2572,7 +2572,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) static void qla2x00_async_done(struct srb *sp, int res) { - if (del_timer(&sp->u.iocb_cmd.timer)) { + if (timer_delete(&sp->u.iocb_cmd.timer)) { /* * Successfully cancelled the timeout handler * ref: TMR @@ -2645,7 +2645,7 @@ static void qla2x00_els_dcmd_sp_free(srb_t *sp) elsio->u.els_logo.els_logo_pyld, elsio->u.els_logo.els_logo_pyld_dma); - del_timer(&elsio->timer); + timer_delete(&elsio->timer); qla2x00_rel_sp(sp); } @@ -2751,7 +2751,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, if (!elsio->u.els_logo.els_logo_pyld) { /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); - qla2x00_free_fcport(fcport); return QLA_FUNCTION_FAILED; } @@ -2776,7 +2775,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, if (rval != QLA_SUCCESS) { /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); - qla2x00_free_fcport(fcport); return QLA_FUNCTION_FAILED; } @@ -3450,7 +3448,7 @@ qla82xx_start_scsi(srb_t *sp) more_dsd_lists -= qpair->dsd_avail; for (i = 0; i < more_dsd_lists; i++) { - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(struct dsd_dma, GFP_ATOMIC); if (!dsd_ptr) { ql_log(ql_log_fatal, vha, 0x300e, "Failed to allocate memory for dsd_dma " @@ -4315,7 +4313,7 @@ qla_start_scsi_type6(srb_t *sp) more_dsd_lists -= qpair->dsd_avail; for (i = 0; i < more_dsd_lists; i++) { - dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + dsd_ptr = kzalloc_obj(*dsd_ptr, GFP_ATOMIC); if (!dsd_ptr) { ql_log(ql_log_fatal, vha, 0x3029, "Failed to allocate memory for dsd_dma for cmd=%p.\n", cmd); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index fe98c76e9be3..33776330956c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -878,6 +878,9 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, payload_size = sizeof(purex->els_frame_payload); } + if (total_bytes > sizeof(item->iocb.iocb)) + total_bytes = sizeof(item->iocb.iocb); + pending_bytes = total_bytes; no_bytes = (pending_bytes > payload_size) ? payload_size : pending_bytes; @@ -1163,6 +1166,10 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt, total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) - PURX_ELS_HEADER_SIZE; + + if (total_bytes > sizeof(item->iocb.iocb)) + total_bytes = sizeof(item->iocb.iocb); + pending_bytes = total_bytes; entry_count = entry_count_remaining = purex->entry_count; no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ? @@ -1669,13 +1676,28 @@ skip_rio: /* Port logout */ fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]); - if (!fcport) + if (!fcport) { + ql_dbg(ql_dbg_async, vha, 0x5011, + "Could not find fcport:%04x %04x %04x\n", + mb[1], mb[2], mb[3]); break; - if (atomic_read(&fcport->state) != FCS_ONLINE) + } + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + ql_dbg(ql_dbg_async, vha, 0x5012, + "Port state is not online State:0x%x \n", + atomic_read(&fcport->state)); + ql_dbg(ql_dbg_async, vha, 0x5012, + "Scheduling session for deletion \n"); + fcport->logout_on_delete = 0; + qlt_schedule_sess_for_deletion(fcport); break; + } + ql_dbg(ql_dbg_async, vha, 0x508a, "Marking port lost loopid=%04x portid=%06x.\n", fcport->loop_id, fcport->d_id.b24); + if (qla_ini_mode_enabled(vha)) { fcport->logout_on_delete = 0; qlt_schedule_sess_for_deletion(fcport); @@ -4467,32 +4489,6 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) 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; - - 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; - - 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); - - return IRQ_HANDLED; -} - /* Interrupt handling helpers. */ struct qla_init_msix_entry { @@ -4505,7 +4501,6 @@ 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[] = { @@ -4533,13 +4528,13 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) if (USER_CTRL_IRQ(ha) || !ha->mqiobase) { /* user wants to control IRQ setting for target mode */ ret = pci_alloc_irq_vectors(ha->pdev, min_vecs, - min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)), - PCI_IRQ_MSIX); + blk_mq_num_online_queues(ha->msix_count) + min_vecs, + PCI_IRQ_MSIX); } else ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs, - min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)), - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, - &desc); + blk_mq_num_online_queues(ha->msix_count) + min_vecs, + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, + &desc); if (ret < 0) { ql_log(ql_log_fatal, vha, 0x00c7, @@ -4567,9 +4562,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) } } vha->irq_offset = desc.pre_vectors; - ha->msix_entries = kcalloc(ha->msix_count, - sizeof(struct qla_msix_entry), - GFP_KERNEL); + ha->msix_entries = kzalloc_objs(struct qla_msix_entry, ha->msix_count); if (!ha->msix_entries) { ql_log(ql_log_fatal, vha, 0x00c8, "Failed to allocate memory for ha->msix_entries.\n"); @@ -4792,9 +4785,10 @@ free_irqs: } int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, - struct qla_msix_entry *msix, int vector_type) + struct qla_msix_entry *msix) { - const struct qla_init_msix_entry *intr = &msix_entries[vector_type]; + const struct qla_init_msix_entry *intr = + &msix_entries[QLA_MSIX_QPAIR_MULTIQ_RSP_Q]; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); int ret; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 0cd6f3e14882..44e310f1a370 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -43,6 +43,7 @@ static struct rom_cmd { } rom_cmds[] = { { MBC_LOAD_RAM }, { MBC_EXECUTE_FIRMWARE }, + { MBC_LOAD_FLASH_FIRMWARE }, { MBC_READ_RAM_WORD }, { MBC_MAILBOX_REGISTER_TEST }, { MBC_VERIFY_CHECKSUM }, @@ -253,6 +254,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Issue set host interrupt command to send cmd out. */ ha->flags.mbox_int = 0; clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); /* Unlock mbx registers and wait for interrupt */ ql_dbg(ql_dbg_mbx, vha, 0x100f, @@ -279,6 +281,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "cmd=%x Timeout.\n", command); spin_lock_irqsave(&ha->hardware_lock, flags); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (chip_reset != ha->chip_reset) { @@ -823,6 +826,53 @@ done: } /* + * qla2x00_load_flash_firmware + * Load firmware from flash. + * + * Input: + * vha = adapter block pointer. + * + * Returns: + * qla28xx local function return status code. + * + * Context: + * Kernel context. + */ +int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + int rval = QLA_COMMAND_ERROR; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA28XX(ha)) + return rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE; + mcp->out_mb = MBX_2 | MBX_1 | MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_log_info, vha, 0x11a7, + "Failed=%x cmd error=%x img error=%x.\n", + rval, mcp->mb[1], mcp->mb[2]); + } else { + ql_dbg(ql_log_info, vha, 0x11a8, + "Done %s.\n", __func__); + } + + return rval; +} + + +/* * qla_get_exlogin_status * Get extended login status * uses the memory offload control/status Mailbox @@ -2147,7 +2197,7 @@ qla24xx_get_port_database(scsi_qla_host_t *vha, u16 nport_handle, pdb_dma = dma_map_single(&vha->hw->pdev->dev, pdb, sizeof(*pdb), DMA_FROM_DEVICE); - if (!pdb_dma) { + if (dma_mapping_error(&vha->hw->pdev->dev, pdb_dma)) { ql_log(ql_log_warn, vha, 0x1116, "Failed to map dma buffer.\n"); return QLA_MEMORY_ALLOC_FAILED; } @@ -2218,6 +2268,13 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; else mcp->in_mb = MBX_1|MBX_0; + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + mcp->mb[12] = 0; + mcp->out_mb |= MBX_12; + mcp->in_mb |= MBX_12; + } + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -2230,6 +2287,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) states[3] = mcp->mb[4]; states[4] = mcp->mb[5]; states[5] = mcp->mb[6]; /* DPORT status */ + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + states[11] = mcp->mb[12]; /* MPI state. */ } if (rval != QLA_SUCCESS) { @@ -6597,6 +6656,54 @@ done: return rval; } +int qla24xx_print_fc_port_id(struct scsi_qla_host *vha, struct seq_file *s, u16 loop_id) +{ + int rval = QLA_FUNCTION_FAILED; + dma_addr_t pd_dma; + struct port_database_24xx *pd; + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + + if (!vha->hw->flags.fw_started) + goto done; + + pd = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); + if (pd == NULL) { + ql_log(ql_log_warn, vha, 0xd047, + "Failed to allocate port database structure.\n"); + goto done; + } + + memset(&mc, 0, sizeof(mc)); + mc.mb[0] = MBC_GET_PORT_DATABASE; + mc.mb[1] = loop_id; + mc.mb[2] = MSW(pd_dma); + mc.mb[3] = LSW(pd_dma); + mc.mb[6] = MSW(MSD(pd_dma)); + mc.mb[7] = LSW(MSD(pd_dma)); + mc.mb[9] = vha->vp_idx; + + rval = qla24xx_send_mb_cmd(vha, &mc); + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x1193, "%s: fail\n", __func__); + goto done_free_sp; + } + + ql_dbg(ql_dbg_mbx, vha, 0x1197, "%s: %8phC done\n", + __func__, pd->port_name); + + seq_printf(s, "%8phC %02x%02x%02x %d\n", + pd->port_name, pd->port_id[0], + pd->port_id[1], pd->port_id[2], + loop_id); + +done_free_sp: + if (pd) + dma_pool_free(ha->s_dma_pool, pd, pd_dma); +done: + return rval; +} + /* * qla24xx_gpdb_wait * NOTE: Do not call this routine from DPC thread @@ -7107,3 +7214,43 @@ int qla_mailbox_passthru(scsi_qla_host_t *vha, return rval; } + +int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state) +{ + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_QLA28XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s %d\n", __func__, __LINE__); + return QLA_FUNCTION_FAILED; + } + + if (img_idx > 1) { + ql_log(ql_log_info, vha, 0xffff, + "%s %d Invalid flash image index [%d]\n", + __func__, __LINE__, img_idx); + return QLA_INVALID_COMMAND; + } + + memset(&mc, 0, sizeof(mc)); + mcp->mb[0] = MBC_MPI_PASSTHROUGH; + mcp->mb[1] = MPIPT_SUBCMD_VALIDATE_FW; + mcp->mb[2] = img_idx; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + + /* send mb via iocb */ + rval = qla24xx_send_mb_cmd(vha, &mc); + if (rval) { + ql_log(ql_log_info, vha, 0xffff, "%s:Failed %x (mb=%x,%x)\n", + __func__, rval, mcp->mb[0], mcp->mb[1]); + *state = mcp->mb[1]; + } else { + ql_log(ql_log_info, vha, 0xffff, "%s: mb=%x,%x,%x\n", __func__, + mcp->mb[0], mcp->mb[1], mcp->mb[2]); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 79879c4743e6..c563133f751e 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -20,7 +20,7 @@ void qla2x00_vp_stop_timer(scsi_qla_host_t *vha) { if (vha->vp_idx && vha->timer_active) { - del_timer_sync(&vha->timer); + timer_delete_sync(&vha->timer); vha->timer_active = 0; } } @@ -707,7 +707,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, device_reg_t *reg; uint32_t cnt; - req = kzalloc(sizeof(struct req_que), GFP_KERNEL); + req = kzalloc_obj(struct req_que); if (req == NULL) { ql_log(ql_log_fatal, base_vha, 0x00d9, "Failed to allocate memory for request queue.\n"); @@ -834,7 +834,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, uint16_t que_id = 0; device_reg_t *reg; - rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); + rsp = kzalloc_obj(struct rsp_que); if (rsp == NULL) { ql_log(ql_log_warn, base_vha, 0x0066, "Failed to allocate memory for response queue.\n"); @@ -899,9 +899,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->options, rsp->id, rsp->rsp_q_in, rsp->rsp_q_out); - ret = qla25xx_request_irq(ha, qpair, qpair->msix, - ha->flags.disable_msix_handshake ? - QLA_MSIX_QPAIR_MULTIQ_RSP_Q : QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS); + ret = qla25xx_request_irq(ha, qpair, qpair->msix); if (ret) goto que_failed; @@ -1104,7 +1102,7 @@ int qla_create_buf_pool(struct scsi_qla_host *vha, struct qla_qpair *qp) return -ENOMEM; } sz = qp->req->length * sizeof(dma_addr_t); - qp->buf_pool.dma_array = kcalloc(qp->req->length, sizeof(dma_addr_t), GFP_KERNEL); + qp->buf_pool.dma_array = kzalloc_objs(dma_addr_t, qp->req->length); if (!qp->buf_pool.dma_array) { ql_log(ql_log_warn, vha, 0x0186, "Failed to allocate dma_array(%d).\n", sz); diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h index 4f63aff333db..3a2bd953a976 100644 --- a/drivers/scsi/qla2xxx/qla_mr.h +++ b/drivers/scsi/qla2xxx/qla_mr.h @@ -282,8 +282,8 @@ struct register_host_info { #define QLAFX00_TGT_NODE_LIST_SIZE (sizeof(uint32_t) * 32) struct config_info_data { - uint8_t model_num[16]; - uint8_t model_description[80]; + uint8_t model_num[16] __nonstring; + uint8_t model_description[80] __nonstring; uint8_t reserved0[160]; uint8_t symbolic_name[64]; uint8_t serial_num[32]; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8ee2e337c9e1..2531e71c39dc 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -419,7 +419,7 @@ retry: switch (rval) { case QLA_SUCCESS: break; - case EAGAIN: + case -EAGAIN: msleep(PURLS_MSLEEP_INTERVAL); cnt++; if (cnt < PURLS_RETRY_COUNT) @@ -1286,13 +1286,13 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) goto out; } - uctx = kzalloc(sizeof(*uctx), GFP_ATOMIC); + uctx = kzalloc_obj(*uctx, GFP_ATOMIC); if (!uctx) { ql_log(ql_log_info, vha, 0x2126, "Failed allocate memory\n"); a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 6dfb70edb9a6..298c060c1292 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1099,11 +1099,6 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) unsigned offset, n; struct qla_hw_data *ha = vha->hw; - struct crb_addr_pair { - long addr; - long data; - }; - /* Halt all the individual PEGs and other blocks of the ISP */ qla82xx_rom_lock(ha); @@ -1188,7 +1183,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) ql_log(ql_log_info, vha, 0x0072, "%d CRB init values found in ROM.\n", n); - buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL); + buf = kmalloc_objs(struct crb_addr_pair, n); if (buf == NULL) { ql_log(ql_log_fatal, vha, 0x010c, "Unable to allocate memory.\n"); @@ -1595,25 +1590,6 @@ qla82xx_get_fw_offs(struct qla_hw_data *ha) return (u8 *)&ha->hablob->fw->data[offset]; } -/* PCI related functions */ -int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) -{ - unsigned long val = 0; - u32 control; - - switch (region) { - case 0: - val = 0; - break; - case 1: - pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); - val = control + QLA82XX_MSIX_TBL_SPACE; - break; - } - return val; -} - - int qla82xx_iospace_config(struct qla_hw_data *ha) { @@ -2934,32 +2910,6 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha) } } -/* -* qla82xx_wait_for_state_change -* Wait for device state to change from given current state -* -* Note: -* IDC lock must not be held upon entry -* -* Return: -* Changed device state. -*/ -uint32_t -qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t dev_state; - - do { - msleep(1000); - qla82xx_idc_lock(ha); - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla82xx_idc_unlock(ha); - } while (dev_state == curr_state); - - return dev_state; -} - void qla8xxx_dev_failed_handler(scsi_qla_host_t *vha) { diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 5d1bdc15b75c..8e7a7f5f0adb 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -892,6 +892,7 @@ struct ct6_dsd { #define FA_VPD_SIZE_82XX 0x400 #define FA_FLASH_LAYOUT_ADDR_82 0xFC400 +#define FA_FLASH_MCU_OFF 0x13000 /****************************************************************************** * diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6b9b8218b512..72b1c28e4dae 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -17,6 +17,7 @@ #include <linux/crash_dump.h> #include <linux/trace_events.h> #include <linux/trace.h> +#include <linux/irq.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> @@ -176,12 +177,6 @@ MODULE_PARM_DESC(ql2xenablehba_err_chk, " 1 -- Error isolation enabled only for DIX Type 0\n" " 2 -- Error isolation enabled for all Types\n"); -int ql2xiidmaenable = 1; -module_param(ql2xiidmaenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xiidmaenable, - "Enables iIDMA settings " - "Default is 1 - perform iIDMA. 0 - no iIDMA."); - int ql2xmqsupport = 1; module_param(ql2xmqsupport, int, S_IRUGO); MODULE_PARM_DESC(ql2xmqsupport, @@ -199,12 +194,6 @@ MODULE_PARM_DESC(ql2xfwloadbin, " 1 -- load firmware from flash.\n" " 0 -- use default semantics.\n"); -int ql2xetsenable; -module_param(ql2xetsenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xetsenable, - "Enables firmware ETS burst." - "Default is 0 - skip ETS enablement."); - int ql2xdbwr = 1; module_param(ql2xdbwr, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xdbwr, @@ -401,7 +390,7 @@ qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval) static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *vha) { - del_timer_sync(&vha->timer); + timer_delete_sync(&vha->timer); vha->timer_active = 0; } @@ -413,8 +402,9 @@ static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, struct req_que **, struct rsp_que **); static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); -int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair); +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd, + struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, @@ -448,23 +438,21 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *), - GFP_KERNEL); + ha->req_q_map = kzalloc_objs(struct req_que *, ha->max_req_queues); if (!ha->req_q_map) { ql_log(ql_log_fatal, vha, 0x003b, "Unable to allocate memory for request queue ptrs.\n"); goto fail_req_map; } - ha->rsp_q_map = kcalloc(ha->max_rsp_queues, sizeof(struct rsp_que *), - GFP_KERNEL); + ha->rsp_q_map = kzalloc_objs(struct rsp_que *, ha->max_rsp_queues); if (!ha->rsp_q_map) { ql_log(ql_log_fatal, vha, 0x003c, "Unable to allocate memory for response queue ptrs.\n"); goto fail_rsp_map; } - ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); + ha->base_qpair = kzalloc_obj(struct qla_qpair); if (ha->base_qpair == NULL) { ql_log(ql_log_warn, vha, 0x00e0, "Failed to allocate base queue pair memory.\n"); @@ -474,8 +462,8 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, qla_init_base_qpair(vha, req, rsp); if ((ql2xmqsupport || ql2xnvmeenable) && ha->max_qpairs) { - ha->queue_pair_map = kcalloc(ha->max_qpairs, sizeof(struct qla_qpair *), - GFP_KERNEL); + ha->queue_pair_map = kzalloc_objs(struct qla_qpair *, + ha->max_qpairs); if (!ha->queue_pair_map) { ql_log(ql_log_fatal, vha, 0x0180, "Unable to allocate memory for queue pair ptrs.\n"); @@ -869,8 +857,8 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res) complete(comp); } -static int -qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla2xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -992,9 +980,9 @@ qc24_fail_command: } /* For MQ supported I/O */ -int +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair) + struct qla_qpair *qpair) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -1194,7 +1182,8 @@ qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha) while ((qla2x00_reset_active(vha) || ha->dpc_active || ha->flags.mbox_busy) || test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) || - test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) { + test_bit(FX00_TARGET_SCAN, &vha->dpc_flags) || + (vha->scan.scan_flags & SF_SCANNING)) { if (test_bit(UNLOADING, &base_vha->dpc_flags)) break; msleep(1000); @@ -1303,8 +1292,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval); /* Wait for the command completion. */ - ratov_j = ha->r_a_tov/10 * 4 * 1000; - ratov_j = msecs_to_jiffies(ratov_j); + ratov_j = ha->r_a_tov / 10 * 4; + ratov_j = secs_to_jiffies(ratov_j); switch (rval) { case QLA_SUCCESS: if (!wait_for_completion_timeout(&comp, ratov_j)) { @@ -1818,8 +1807,8 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, rval = ha->isp_ops->abort_command(sp); /* Wait for command completion. */ ret_cmd = false; - ratov_j = ha->r_a_tov/10 * 4 * 1000; - ratov_j = msecs_to_jiffies(ratov_j); + ratov_j = ha->r_a_tov / 10 * 4; + ratov_j = secs_to_jiffies(ratov_j); switch (rval) { case QLA_SUCCESS: if (wait_for_completion_timeout(&comp, ratov_j)) { @@ -1874,12 +1863,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - if (qla2x00_chip_is_down(vha)) { - req->outstanding_cmds[cnt] = NULL; - sp->done(sp, res); - continue; - } - switch (sp->cmd_type) { case TYPE_SRB: qla2x00_abort_srb(qp, sp, res, &flags); @@ -1893,10 +1876,26 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) continue; } cmd = (struct qla_tgt_cmd *)sp; - cmd->aborted = 1; + + if (cmd->sg_mapped) + qlt_unmap_sg(vha, cmd); + + if (cmd->state == QLA_TGT_STATE_NEED_DATA) { + cmd->aborted = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + ha->tgt.tgt_ops->handle_data(cmd); + } else { + ha->tgt.tgt_ops->free_cmd(cmd); + } break; case TYPE_TGT_TMCMD: - /* Skip task management functions. */ + /* + * Currently, only ABTS response gets on the + * outstanding_cmds[] + */ + qlt_free_ul_mcmd(ha, + (struct qla_tgt_mgmt_cmd *) sp); break; default: break; @@ -2959,7 +2958,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql2xallocfwdump = 0; } - ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); + ha = kzalloc_obj(struct qla_hw_data); if (!ha) { ql_log_pci(ql_log_fatal, pdev, 0x0009, "Unable to allocate memory for ha.\n"); @@ -3409,7 +3408,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); + ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (unlikely(!ha->wq)) { ret = -ENOMEM; goto probe_failed; @@ -3456,13 +3455,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->mqenable = 0; if (ha->mqenable) { - bool startit = false; - - if (QLA_TGT_MODE_ENABLED()) - startit = false; - - if (ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) - startit = true; + bool startit = !!(host->active_mode & MODE_INITIATOR); /* Create start of day qpairs for Block MQ */ for (i = 0; i < ha->max_qpairs; i++) @@ -4156,7 +4149,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, int rc; if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) { - ha->vp_map = kcalloc(MAX_MULTI_ID_FABRIC, sizeof(struct qla_vp_map), GFP_KERNEL); + ha->vp_map = kzalloc_objs(struct qla_vp_map, + MAX_MULTI_ID_FABRIC); if (!ha->vp_map) goto fail; } @@ -4252,7 +4246,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->pool.good.count = 0; ha->pool.unusable.count = 0; for (i = 0; i < 128; i++) { - dsd = kzalloc(sizeof(*dsd), GFP_ATOMIC); + dsd = kzalloc_obj(*dsd, GFP_ATOMIC); if (!dsd) { ql_dbg_pci(ql_dbg_init, ha->pdev, 0xe0ee, "%s: failed alloc dsd\n", @@ -4340,7 +4334,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, } /* Allocate memory for request ring */ - *req = kzalloc(sizeof(struct req_que), GFP_KERNEL); + *req = kzalloc_obj(struct req_que); if (!*req) { ql_log_pci(ql_log_fatal, ha->pdev, 0x0028, "Failed to allocate memory for req.\n"); @@ -4356,7 +4350,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, goto fail_req_ring; } /* Allocate memory for response ring */ - *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); + *rsp = kzalloc_obj(struct rsp_que); if (!*rsp) { ql_log_pci(ql_log_fatal, ha->pdev, 0x002a, "Failed to allocate memory for rsp.\n"); @@ -4381,9 +4375,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, (*rsp)->ring); /* Allocate memory for NVRAM data for vports */ if (ha->nvram_npiv_size) { - ha->npiv_info = kcalloc(ha->nvram_npiv_size, - sizeof(struct qla_npiv_entry), - GFP_KERNEL); + ha->npiv_info = kzalloc_objs(struct qla_npiv_entry, + ha->nvram_npiv_size); if (!ha->npiv_info) { ql_log_pci(ql_log_fatal, ha->pdev, 0x002d, "Failed to allocate memory for npiv_info.\n"); @@ -4427,9 +4420,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, INIT_LIST_HEAD(&ha->vp_list); /* Allocate memory for our loop_id bitmap */ - ha->loop_id_map = kcalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE), - sizeof(long), - GFP_KERNEL); + ha->loop_id_map = kzalloc_objs(long, BITS_TO_LONGS(LOOPID_MAP_SIZE)); if (!ha->loop_id_map) goto fail_loop_id_map; else { @@ -4496,7 +4487,7 @@ fail_lsrjt: fail_elsrej: dma_pool_destroy(ha->purex_dma_pool); fail_flt: - dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, + dma_free_coherent(&ha->pdev->dev, sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, ha->flt, ha->flt_dma); fail_flt_buffer: @@ -5141,7 +5132,7 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) if (qla_vha_mark_busy(vha)) return NULL; - e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); + e = kzalloc_obj(struct qla_work_evt, GFP_ATOMIC); if (!e) { QLA_VHA_MARK_NOT_BUSY(vha); return NULL; @@ -5292,7 +5283,7 @@ void qla24xx_sched_upd_fcport(fc_port_t *fcport) qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); spin_unlock_irqrestore(&fcport->vha->work_lock, flags); - queue_work(system_unbound_wq, &fcport->reg_work); + queue_work(system_dfl_wq, &fcport->reg_work); } static @@ -6023,7 +6014,7 @@ qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, ql_dbg(ql_dbg_init, vha, 0x0181, "%s: s_id=%#x\n", __func__, sid); - pdb = kzalloc(sizeof(*pdb), GFP_KERNEL); + pdb = kzalloc_obj(*pdb); if (!pdb) { ql_dbg(ql_dbg_init, vha, 0x0181, "%s: Failed allocate pdb\n", __func__); @@ -7256,6 +7247,7 @@ qla2xxx_wake_dpc(struct scsi_qla_host *vha) if (!test_bit(UNLOADING, &vha->dpc_flags) && t) wake_up_process(t); } +EXPORT_SYMBOL(qla2xxx_wake_dpc); /* * qla2x00_rst_aen @@ -7392,7 +7384,7 @@ static void qla_wind_down_chip(scsi_qla_host_t *vha) void qla2x00_timer(struct timer_list *t) { - scsi_qla_host_t *vha = from_timer(vha, t, timer); + scsi_qla_host_t *vha = timer_container_of(vha, t, timer); unsigned long cpu_flags = 0; int start_dpc = 0; int index; @@ -7783,6 +7775,31 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha) } +/** + * qla2xxx_set_affinity_nobalance + * @pdev: pci_dev struct for a qla2xxx device + * @flag: bool + * true: enable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ + +static void qla2xxx_set_affinity_nobalance(struct pci_dev *pdev, bool flag) +{ + int irq, i; + + for (i = 0; i < QLA_BASE_VECTORS; i++) { + irq = pci_irq_vector(pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -7801,6 +7818,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) goto out; } + qla2xxx_set_affinity_nobalance(pdev, false); + switch (state) { case pci_channel_io_normal: qla_pci_set_eeh_busy(vha); @@ -7895,19 +7914,9 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) "Slot Reset.\n"); ha->pci_error_state = QLA_PCI_SLOT_RESET; - /* Workaround: qla2xxx driver which access hardware earlier - * needs error state to be pci_channel_io_online. - * Otherwise mailbox command timesout. - */ - pdev->error_state = pci_channel_io_normal; pci_restore_state(pdev); - /* pci_restore_state() clears the saved_state flag of the device - * save restored state which resets saved_state flag - */ - pci_save_state(pdev); - if (ha->mem_only) rc = pci_enable_device_mem(pdev); else @@ -7947,6 +7956,8 @@ exit_slot_reset: ql_dbg(ql_dbg_aer, base_vha, 0x900e, "Slot Reset returning %x.\n", ret); + qla2xxx_set_affinity_nobalance(pdev, true); + return ret; } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 6d16546e1729..b6c36a8a2d60 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1084,6 +1084,32 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha) return; } +static int qla28xx_validate_mcu_signature(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + uint32_t *dcode = (uint32_t *)req->ring; + uint32_t signature[2] = {0x000c0000, 0x00050000}; + int ret = QLA_SUCCESS; + + ret = qla24xx_read_flash_data(vha, dcode, FA_FLASH_MCU_OFF >> 2, 2); + if (ret) { + ql_log(ql_log_fatal, vha, 0x01ab, + "-> Failed to read flash mcu signature.\n"); + ret = QLA_FUNCTION_FAILED; + goto done; + } + + ql_dbg(ql_dbg_init, vha, 0x01ac, + "Flash data 0x%08x 0x%08x.\n", dcode[0], dcode[1]); + + if (!(dcode[0] == signature[0] && dcode[1] == signature[1])) + ret = QLA_FUNCTION_FAILED; + +done: + return ret; +} + int qla2xxx_get_flash_info(scsi_qla_host_t *vha) { @@ -1096,6 +1122,9 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha) !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_SUCCESS; + if (IS_QLA28XX(ha) && !qla28xx_validate_mcu_signature(vha)) + ha->flags.secure_mcu = 1; + ret = qla2xxx_find_flt_start(vha, &flt_addr); if (ret != QLA_SUCCESS) return ret; @@ -2136,8 +2165,8 @@ qla2x00_write_flash_byte(struct qla_hw_data *ha, uint32_t addr, uint8_t data) * @flash_id: Flash ID * * This function polls the device until bit 7 of what is read matches data - * bit 7 or until data bit 5 becomes a 1. If that hapens, the flash ROM timed - * out (a fatal error). The flash book recommeds reading bit 7 again after + * bit 7 or until data bit 5 becomes a 1. If that happens, the flash ROM timed + * out (a fatal error). The flash book recommends reading bit 7 again after * reading bit 5 as a 1. * * Returns 0 on success, else non-zero. diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 11eadb3bd36e..e47da45e93a0 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -104,8 +104,6 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, struct rsp_que *rsp, response_t *pkt); static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, int fn, void *iocb, int flags); -static void qlt_send_term_exchange(struct qla_qpair *, struct qla_tgt_cmd - *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort); static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct atio_from_isp *atio, uint16_t status, int qfull); static void qlt_disable_vha(struct scsi_qla_host *vha); @@ -136,20 +134,6 @@ static struct workqueue_struct *qla_tgt_wq; static DEFINE_MUTEX(qla_tgt_mutex); static LIST_HEAD(qla_tgt_glist); -static const char *prot_op_str(u32 prot_op) -{ - switch (prot_op) { - case TARGET_PROT_NORMAL: return "NORMAL"; - case TARGET_PROT_DIN_INSERT: return "DIN_INSERT"; - case TARGET_PROT_DOUT_INSERT: return "DOUT_INSERT"; - case TARGET_PROT_DIN_STRIP: return "DIN_STRIP"; - case TARGET_PROT_DOUT_STRIP: return "DOUT_STRIP"; - case TARGET_PROT_DIN_PASS: return "DIN_PASS"; - case TARGET_PROT_DOUT_PASS: return "DOUT_PASS"; - default: return "UNKNOWN"; - } -} - /* This API intentionally takes dest as a parameter, rather than returning * int value to avoid caller forgetting to issue wmb() after the store */ void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest) @@ -226,6 +210,10 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha, struct qla_tgt_sess_op *u; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; unsigned long flags; + unsigned int add_cdb_len = 0; + + /* atio must be the last member of qla_tgt_sess_op for add_cdb_len */ + BUILD_BUG_ON(offsetof(struct qla_tgt_sess_op, atio) + sizeof(u->atio) != sizeof(*u)); if (tgt->tgt_stop) { ql_dbg(ql_dbg_async, vha, 0x502c, @@ -234,12 +222,17 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha, goto out_term; } - u = kzalloc(sizeof(*u), GFP_ATOMIC); + if (atio->u.raw.entry_type == ATIO_TYPE7 && + atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0) + add_cdb_len = + ((unsigned int) atio->u.isp24.fcp_cmnd.add_cdb_len) * 4; + + u = kzalloc(sizeof(*u) + add_cdb_len, GFP_ATOMIC); if (u == NULL) goto out_term; u->vha = vha; - memcpy(&u->atio, atio, sizeof(*atio)); + memcpy(&u->atio, atio, sizeof(*atio) + add_cdb_len); INIT_LIST_HEAD(&u->cmd_list); spin_lock_irqsave(&vha->cmd_list_lock, flags); @@ -252,7 +245,7 @@ out: return; out_term: - qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked, 0); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked); goto out; } @@ -271,7 +264,7 @@ static void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, "Freeing unknown %s %p, because of Abort\n", "ATIO_TYPE7", u); qlt_send_term_exchange(vha->hw->base_qpair, NULL, - &u->atio, ha_locked, 0); + &u->atio, ha_locked); goto abort; } @@ -285,7 +278,7 @@ static void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, "Freeing unknown %s %p, because tgt is being stopped\n", "ATIO_TYPE7", u); qlt_send_term_exchange(vha->hw->base_qpair, NULL, - &u->atio, ha_locked, 0); + &u->atio, ha_locked); } else { ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0x503d, "Reschedule u %p, vha %p, host %p\n", u, vha, host); @@ -1454,50 +1447,6 @@ static struct fc_port *qlt_create_sess( return sess; } -/* - * max_gen - specifies maximum session generation - * at which this deletion requestion is still valid - */ -void -qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) -{ - struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; - struct fc_port *sess = fcport; - unsigned long flags; - - if (!vha->hw->tgt.tgt_ops) - return; - - if (!tgt) - return; - - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); - if (tgt->tgt_stop) { - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - return; - } - if (!sess->se_sess) { - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - return; - } - - if (max_gen - sess->generation < 0) { - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092, - "Ignoring stale deletion request for se_sess %p / sess %p" - " for port %8phC, req_gen %d, sess_gen %d\n", - sess->se_sess, sess, sess->port_name, max_gen, - sess->generation); - return; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); - - sess->local = 1; - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - qlt_schedule_sess_for_deletion(sess); -} - static inline int test_tgt_sess_count(struct qla_tgt *tgt) { struct qla_hw_data *ha = tgt->ha; @@ -1672,7 +1621,7 @@ static int qlt_sched_sess_work(struct qla_tgt *tgt, int type, struct qla_tgt_sess_work_param *prm; unsigned long flags; - prm = kzalloc(sizeof(*prm), GFP_ATOMIC); + prm = kzalloc_obj(*prm, GFP_ATOMIC); if (!prm) { ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf050, "qla_target(%d): Unable to create session " @@ -1953,6 +1902,10 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, * ABTS response. So, in it ID fields are reversed. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe082, + "qla_target(%d): tag %u: Sending TERM EXCH CTIO for ABTS\n", + vha->vp_idx, le32_to_cpu(entry->exchange_addr_to_abort)); + ctio->entry_type = CTIO_TYPE7; ctio->entry_count = 1; ctio->nport_handle = entry->nport_handle; @@ -2031,8 +1984,12 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha, u64 lun, be_id_t s_id) cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); cmd_lun = scsilun_to_int( (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun); - if (cmd_key == key && cmd_lun == lun) + if (cmd_key == key && cmd_lun == lun) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe085, + "qla_target(%d): tag %lld: aborted by TMR\n", + vha->vp_idx, cmd->se_cmd.tag); cmd->aborted = 1; + } } spin_unlock_irqrestore(&vha->cmd_list_lock, flags); } @@ -2061,7 +2018,6 @@ static void qlt_do_tmr_work(struct work_struct *work) struct qla_hw_data *ha = mcmd->vha->hw; int rc; uint32_t tag; - unsigned long flags; switch (mcmd->tmr_func) { case QLA_TGT_ABTS: @@ -2076,34 +2032,12 @@ static void qlt_do_tmr_work(struct work_struct *work) mcmd->tmr_func, tag); if (rc != 0) { - spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags); - switch (mcmd->tmr_func) { - case QLA_TGT_ABTS: - mcmd->fc_tm_rsp = FCP_TMF_REJECTED; - qlt_build_abts_resp_iocb(mcmd); - break; - case QLA_TGT_LUN_RESET: - case QLA_TGT_CLEAR_TS: - case QLA_TGT_ABORT_TS: - case QLA_TGT_CLEAR_ACA: - case QLA_TGT_TARGET_RESET: - qlt_send_busy(mcmd->qpair, &mcmd->orig_iocb.atio, - qla_sam_status); - break; - - case QLA_TGT_ABORT_ALL: - case QLA_TGT_NEXUS_LOSS_SESS: - case QLA_TGT_NEXUS_LOSS: - qlt_send_notify_ack(mcmd->qpair, - &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); - break; - } - spin_unlock_irqrestore(mcmd->qpair->qp_lock_ptr, flags); - ql_dbg(ql_dbg_tgt_mgt, mcmd->vha, 0xf052, "qla_target(%d): tgt_ops->handle_tmr() failed: %d\n", mcmd->vha->vp_idx, rc); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); + mcmd->flags |= QLA24XX_MGMT_LLD_OWNED; + mcmd->fc_tm_rsp = FCP_TMF_FAILED; + qlt_xmit_tm_rsp(mcmd); } } @@ -2291,6 +2225,21 @@ void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) EXPORT_SYMBOL(qlt_free_mcmd); /* + * If the upper layer knows about this mgmt cmd, then call its ->free_cmd() + * callback, which will eventually call qlt_free_mcmd(). Otherwise, call + * qlt_free_mcmd() directly. + */ +void qlt_free_ul_mcmd(struct qla_hw_data *ha, struct qla_tgt_mgmt_cmd *mcmd) +{ + if (!mcmd) + return; + if (mcmd->flags & QLA24XX_MGMT_LLD_OWNED) + qlt_free_mcmd(mcmd); + else + ha->tgt.tgt_ops->free_mcmd(mcmd); +} + +/* * ha->hardware_lock supposed to be held on entry. Might drop it, then * reacquire */ @@ -2382,12 +2331,12 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), mcmd->reset_count, qpair->chip_reset); - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return; } - if (mcmd->flags == QLA24XX_MGMT_SEND_NACK) { + if (mcmd->flags & QLA24XX_MGMT_SEND_NACK) { switch (mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode) { case ELS_LOGO: case ELS_PRLO: @@ -2420,7 +2369,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) * qlt_xmit_tm_rsp() returns here.. */ if (free_mcmd) - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); } @@ -2487,7 +2436,7 @@ out_err: return -1; } -static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) +void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { struct qla_hw_data *ha; struct qla_qpair *qpair; @@ -3262,12 +3211,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, uint32_t full_req_cnt = 0; unsigned long flags = 0; int res; - - if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || - (cmd->sess && cmd->sess->deleted)) { - cmd->state = QLA_TGT_STATE_PROCESSED; - return 0; - } + int pre_xmit_res; ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018, "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p] qp %d\n", @@ -3275,33 +3219,43 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, 1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction, &cmd->se_cmd, qpair->id); - res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, + pre_xmit_res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, &full_req_cnt); - if (unlikely(res != 0)) { - return res; - } + /* + * Check pre_xmit_res later because we want to check other errors + * first. + */ + + /* Begin timer on the first call, not on SRR retry. */ + if (likely(cmd->jiffies_at_hw_st_entry == 0)) + cmd->jiffies_at_hw_st_entry = get_jiffies_64(); spin_lock_irqsave(qpair->qp_lock_ptr, flags); + if (unlikely(cmd->sent_term_exchg || + cmd->sess->deleted || + !qpair->fw_started || + cmd->reset_count != qpair->chip_reset)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe101, + "qla_target(%d): tag %lld: skipping send response for aborted cmd\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_unmap_sg(vha, cmd); + cmd->state = QLA_TGT_STATE_PROCESSED; + vha->hw->tgt.tgt_ops->free_cmd(cmd); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return 0; + } + + /* Check for errors from qlt_pre_xmit_response(). */ + res = pre_xmit_res; + if (unlikely(res)) + goto out_unmap_unlock; + if (xmit_type == QLA_TGT_XMIT_STATUS) qpair->tgt_counters.core_qla_snd_status++; else qpair->tgt_counters.core_qla_que_buf++; - if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) { - /* - * Either the port is not online or this request was from - * previous life, just abort the processing. - */ - cmd->state = QLA_TGT_STATE_PROCESSED; - ql_dbg_qp(ql_dbg_async, qpair, 0xe101, - "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", - vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, qpair->chip_reset); - res = 0; - goto out_unmap_unlock; - } - /* Does F/W have an IOCBs for this request */ res = qlt_check_reserve_free_req(qpair, full_req_cnt); if (unlikely(res)) @@ -3416,36 +3370,50 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) struct qla_tgt_prm prm; unsigned long flags = 0; int res = 0; + int pci_map_res; struct qla_qpair *qpair = cmd->qpair; + /* Begin timer on the first call, not on SRR retry. */ + if (likely(cmd->jiffies_at_hw_st_entry == 0)) + cmd->jiffies_at_hw_st_entry = get_jiffies_64(); + memset(&prm, 0, sizeof(prm)); prm.cmd = cmd; prm.tgt = tgt; prm.sg = NULL; prm.req_cnt = 1; - if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || - (cmd->sess && cmd->sess->deleted)) { - /* - * Either the port is not online or this request was from - * previous life, just abort the processing. - */ + /* Calculate number of entries and segments required */ + pci_map_res = qlt_pci_map_calc_cnt(&prm); + /* + * Check pci_map_res later because we want to check other errors first. + */ + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + + if (unlikely(cmd->sent_term_exchg || + cmd->sess->deleted || + !qpair->fw_started || + cmd->reset_count != qpair->chip_reset)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe102, + "qla_target(%d): tag %lld: skipping data-out for aborted cmd\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_unmap_sg(vha, cmd); cmd->aborted = 1; cmd->write_data_transferred = 0; cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; vha->hw->tgt.tgt_ops->handle_data(cmd); - ql_dbg_qp(ql_dbg_async, qpair, 0xe102, - "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n", - vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, qpair->chip_reset); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return 0; } - /* Calculate number of entries and segments required */ - if (qlt_pci_map_calc_cnt(&prm) != 0) - return -EAGAIN; + /* Check for errors from qlt_pci_map_calc_cnt(). */ + if (unlikely(pci_map_res != 0)) { + res = -EAGAIN; + goto out_unlock_free_unmap; + } - spin_lock_irqsave(qpair->qp_lock_ptr, flags); /* Does F/W have an IOCBs for this request */ res = qlt_check_reserve_free_req(qpair, prm.req_cnt); if (res != 0) @@ -3482,6 +3450,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) return res; out_unlock_free_unmap: + cmd->jiffies_at_hw_st_entry = 0; qlt_unmap_sg(vha, cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -3501,7 +3470,6 @@ qlt_handle_dif_error(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, uint8_t *ep = &sts->expected_dif[0]; uint64_t lba = cmd->se_cmd.t_task_lba; uint8_t scsi_status, sense_key, asc, ascq; - unsigned long flags; struct scsi_qla_host *vha = cmd->vha; cmd->trc_flags |= TRC_DIF_ERR; @@ -3572,16 +3540,14 @@ out: case QLA_TGT_STATE_NEED_DATA: /* handle_data will load DIF error code */ cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; vha->hw->tgt.tgt_ops->handle_data(cmd); break; default: - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->aborted) { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); + if (cmd->sent_term_exchg) { vha->hw->tgt.tgt_ops->free_cmd(cmd); break; } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); qlt_send_resp_ctio(qpair, cmd, scsi_status, sense_key, asc, ascq); @@ -3655,6 +3621,62 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, } /* + * Handle a SRR that had been previously associated with a command when the + * command has been aborted or otherwise cannot process the SRR. + * + * If reject is true, then attempt to reject the SRR. Otherwise abort the + * immediate notify exchange. + */ +void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject) +{ + struct scsi_qla_host *vha = cmd->vha; + struct qla_tgt_srr *srr = cmd->srr; + + if (srr->imm_ntfy_recvd) { + if (reject) + srr->reject = true; + else + srr->aborted = true; + + if (srr->ctio_recvd) { + /* + * The SRR should already be scheduled for processing, + * and the SRR processing code should see that the cmd + * has been aborted and take appropriate action. In + * addition, the cmd refcount should have been + * incremented, preventing the cmd from being freed + * until SRR processing is done. + */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102e, + "qla_target(%d): tag %lld: %s: SRR already scheduled\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + } else { + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + unsigned long flags; + + /* Shedule processing for the SRR immediate notify. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102f, + "qla_target(%d): tag %lld: %s: schedule SRR %s\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, + reject ? "reject" : "abort"); + cmd->srr = NULL; + srr->cmd = NULL; + spin_lock_irqsave(&tgt->srr_lock, flags); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work(qla_tgt_wq, &tgt->srr_work); + spin_unlock_irqrestore(&tgt->srr_lock, flags); + } + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11030, + "qla_target(%d): tag %lld: %s: no IMM SRR; free SRR\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + cmd->srr = NULL; + kfree(srr); + } +} +EXPORT_SYMBOL(qlt_srr_abort); + +/* * If hardware_lock held on entry, might drop it, then reaquire * This function sends the appropriate CTIO to ISP 2xxx or 24xx */ @@ -3662,43 +3684,61 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio) { - struct scsi_qla_host *vha = qpair->vha; struct ctio7_to_24xx *ctio24; - struct qla_hw_data *ha = vha->hw; - request_t *pkt; - int ret = 0; + struct scsi_qla_host *vha; + uint16_t loop_id; uint16_t temp; - ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha); - - if (cmd) + if (cmd) { vha = cmd->vha; + loop_id = cmd->loop_id; + } else { + port_id_t id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); + struct qla_hw_data *ha; + struct fc_port *sess; + unsigned long flags; - pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL); - if (pkt == NULL) { + vha = qpair->vha; + ha = vha->hw; + + /* + * CTIO7_NHANDLE_UNRECOGNIZED works when aborting an idle + * command but not when aborting a command with an active CTIO + * exchange. + */ + loop_id = CTIO7_NHANDLE_UNRECOGNIZED; + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); + if (sess) + loop_id = sess->loop_id; + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + } + + if (cmd) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, + "qla_target(%d): tag %lld: Sending TERM EXCH CTIO state %d cmd_sent_to_fw %u\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state, + cmd->cmd_sent_to_fw); + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, + "qla_target(%d): tag %u: Sending TERM EXCH CTIO (no cmd)\n", + vha->vp_idx, le32_to_cpu(atio->u.isp24.exchange_addr)); + } + + ctio24 = qla2x00_alloc_iocbs_ready(qpair, NULL); + if (!ctio24) { ql_dbg(ql_dbg_tgt, vha, 0xe050, "qla_target(%d): %s failed: unable to allocate " "request packet\n", vha->vp_idx, __func__); return -ENOMEM; } - if (cmd != NULL) { - if (cmd->state < QLA_TGT_STATE_PROCESSED) { - ql_dbg(ql_dbg_tgt, vha, 0xe051, - "qla_target(%d): Terminating cmd %p with " - "incorrect state %d\n", vha->vp_idx, cmd, - cmd->state); - } else - ret = 1; - } - qpair->tgt_counters.num_term_xchg_sent++; - pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - ctio24 = (struct ctio7_to_24xx *)pkt; ctio24->entry_type = CTIO_TYPE7; - ctio24->nport_handle = cpu_to_le16(CTIO7_NHANDLE_UNRECOGNIZED); + ctio24->entry_count = 1; + ctio24->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; + ctio24->nport_handle = cpu_to_le16(loop_id); ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); @@ -3715,12 +3755,25 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, qpair->reqq_start_iocbs(qpair); else qla2x00_start_iocbs(vha, qpair->req); - return ret; + return 0; } -static void qlt_send_term_exchange(struct qla_qpair *qpair, - struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked, - int ul_abort) +/* + * Aborting a command that is active in the FW (i.e. cmd->cmd_sent_to_fw == 1) + * will usually trigger the FW to send a completion CTIO with error status, + * and the driver will then call the ->handle_data() or ->free_cmd() callbacks. + * This can be used to clear a command that is locked up in the FW unless there + * is something more seriously wrong. + * + * Aborting a command that is not active in the FW (i.e. + * cmd->cmd_sent_to_fw == 0) will not directly trigger any callbacks. Instead, + * when the target mode midlevel calls qlt_rdy_to_xfer() or + * qlt_xmit_response(), the driver will see that the cmd has been aborted and + * call the appropriate callback immediately without performing the requested + * operation. + */ +void qlt_send_term_exchange(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked) { struct scsi_qla_host *vha; unsigned long flags = 0; @@ -3744,10 +3797,14 @@ static void qlt_send_term_exchange(struct qla_qpair *qpair, qlt_alloc_qfull_cmd(vha, atio, 0, 0); done: - if (cmd && !ul_abort && !cmd->aborted) { - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - vha->hw->tgt.tgt_ops->free_cmd(cmd); + if (cmd) { + /* + * Set this even if -ENOMEM above, since term exchange will be + * sent eventually... + */ + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; } if (!ha_locked) @@ -3755,6 +3812,7 @@ done: return; } +EXPORT_SYMBOL(qlt_send_term_exchange); static void qlt_init_term_exchange(struct scsi_qla_host *vha) { @@ -3805,38 +3863,35 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha) int qlt_abort_cmd(struct qla_tgt_cmd *cmd) { - struct qla_tgt *tgt = cmd->tgt; - struct scsi_qla_host *vha = tgt->vha; - struct se_cmd *se_cmd = &cmd->se_cmd; + struct scsi_qla_host *vha = cmd->vha; + struct qla_qpair *qpair = cmd->qpair; unsigned long flags; - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, - "qla_target(%d): terminating exchange for aborted cmd=%p " - "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd, - se_cmd->tag); - - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->aborted) { - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - /* - * It's normal to see 2 calls in this path: - * 1) XFER Rdy completion + CMD_T_ABORT - * 2) TCM TMR - drain_state_list - */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf016, - "multiple abort. %p transport_state %x, t_state %x, " - "se_cmd_flags %x\n", cmd, cmd->se_cmd.transport_state, - cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); - return -EIO; + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, + "qla_target(%d): tag %lld: cmd being aborted (state %d) %s; %s\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state, + cmd->cmd_sent_to_fw ? "sent to fw" : "not sent to fw", + cmd->aborted ? "aborted" : "not aborted"); + + if (cmd->state != QLA_TGT_STATE_DONE && !cmd->sent_term_exchg) { + if (!qpair->fw_started || + cmd->reset_count != qpair->chip_reset) { + /* + * Chip was reset; just pretend that we sent the term + * exchange. + */ + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; + } else { + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + } } - cmd->aborted = 1; - cmd->trc_flags |= TRC_ABORT; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_send_term_exchange(cmd->qpair, cmd, &cmd->atio, 0, 1); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return 0; } EXPORT_SYMBOL(qlt_abort_cmd); @@ -3856,54 +3911,99 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) qlt_decr_num_pend_cmds(cmd->vha); BUG_ON(cmd->sg_mapped); + if (unlikely(cmd->free_sg)) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + if (unlikely(cmd->srr)) + qlt_srr_abort(cmd, false); + + if (unlikely(cmd->aborted || + (cmd->trc_flags & (TRC_CTIO_STRANGE | TRC_CTIO_ERR | + TRC_SRR_CTIO | TRC_SRR_IMM)))) { + ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xe086, + "qla_target(%d): tag %lld: free cmd (trc_flags %x, aborted %u, sent_term_exchg %u, rsp_sent %u)\n", + cmd->vha->vp_idx, cmd->se_cmd.tag, + cmd->trc_flags, cmd->aborted, cmd->sent_term_exchg, + cmd->rsp_sent); + } + + if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) { + kfree(cmd->cdb); + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + } + cmd->jiffies_at_free = get_jiffies_64(); if (!sess || !sess->se_sess) { WARN_ON(1); return; } - cmd->jiffies_at_free = get_jiffies_64(); cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); } EXPORT_SYMBOL(qlt_free_cmd); /* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire + * Process a CTIO response for a SCSI command that failed due to SRR. + * + * qpair->qp_lock_ptr supposed to be held on entry */ -static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, - struct qla_tgt_cmd *cmd, uint32_t status) +static int qlt_prepare_srr_ctio(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd) { - int term = 0; - struct scsi_qla_host *vha = qpair->vha; + struct scsi_qla_host *vha = cmd->vha; + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_tgt_srr *srr; - if (cmd->se_cmd.prot_op) - ql_dbg(ql_dbg_tgt_dif, vha, 0xe013, - "Term DIF cmd: lba[0x%llx|%lld] len[0x%x] " - "se_cmd=%p tag[%x] op %#x/%s", - cmd->lba, cmd->lba, - cmd->num_blks, &cmd->se_cmd, - cmd->atio.u.isp24.exchange_addr, - cmd->se_cmd.prot_op, - prot_op_str(cmd->se_cmd.prot_op)); - - if (ctio != NULL) { - struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; - - term = !(c->flags & - cpu_to_le16(OF_TERM_EXCH)); - } else - term = 1; + cmd->trc_flags |= TRC_SRR_CTIO; - if (term) - qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1, 0); + srr = cmd->srr; + if (srr != NULL) { + /* qlt_prepare_srr_imm() was called first. */ - return term; -} + WARN_ON(srr->ctio_recvd); + WARN_ON(!srr->imm_ntfy_recvd); + + if (vha->hw->tgt.tgt_ops->get_cmd_ref(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11037, + "qla_target(%d): tag %lld: unable to get cmd ref for SRR processing\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_srr_abort(cmd, true); + return -ESHUTDOWN; + } + + srr->ctio_recvd = true; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100f, + "qla_target(%d): tag %lld: Scheduling SRR work\n", + vha->vp_idx, cmd->se_cmd.tag); + + /* Schedule the srr for processing in qlt_handle_srr(). */ + /* IRQ is already OFF */ + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &tgt->srr_work); + spin_unlock(&tgt->srr_lock); + return 0; + } + srr = kzalloc_obj(*srr, GFP_ATOMIC); + if (!srr) + return -ENOMEM; + + /* Expect qlt_prepare_srr_imm() to be called. */ + srr->ctio_recvd = true; + srr->cmd = cmd; + srr->reset_count = cmd->reset_count; + cmd->srr = srr; + return 0; +} /* ha->hardware_lock supposed to be held on entry */ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, - struct rsp_que *rsp, uint32_t handle, void *ctio) + struct rsp_que *rsp, uint32_t handle, uint8_t cmd_type, + const void *ctio) { void *cmd = NULL; struct req_que *req; @@ -3926,29 +4026,97 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, h &= QLA_CMD_HANDLE_MASK; - if (h != QLA_TGT_NULL_HANDLE) { - if (unlikely(h >= req->num_outstanding_cmds)) { - ql_dbg(ql_dbg_tgt, vha, 0xe052, - "qla_target(%d): Wrong handle %x received\n", - vha->vp_idx, handle); - return NULL; - } - - cmd = req->outstanding_cmds[h]; - if (unlikely(cmd == NULL)) { - ql_dbg(ql_dbg_async, vha, 0xe053, - "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", - vha->vp_idx, handle, req->id, rsp->id); - return NULL; - } - req->outstanding_cmds[h] = NULL; - } else if (ctio != NULL) { + if (h == QLA_TGT_NULL_HANDLE) { /* We can't get loop ID from CTIO7 */ ql_dbg(ql_dbg_tgt, vha, 0xe054, "qla_target(%d): Wrong CTIO received: QLA24xx doesn't " "support NULL handles\n", vha->vp_idx); return NULL; } + if (unlikely(h >= req->num_outstanding_cmds)) { + ql_dbg(ql_dbg_tgt, vha, 0xe052, + "qla_target(%d): Wrong handle %x received\n", + vha->vp_idx, handle); + return NULL; + } + + /* + * We passed a numeric handle for a cmd to the hardware, and the + * hardware passed the handle back to us. Look up the associated cmd, + * and validate that the cmd_type and exchange address match what the + * caller expects. This guards against buggy HBA firmware that returns + * the same CTIO multiple times. + */ + + cmd = req->outstanding_cmds[h]; + + if (unlikely(cmd == NULL)) { + if (cmd_type == TYPE_TGT_CMD) { + __le32 ctio_exchange_addr = + ((const struct ctio7_from_24xx *)ctio)-> + exchange_address; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe053, + "qla_target(%d): tag %u: handle %x: cmd detached; ignoring CTIO (handle %x req->id %d rsp->id %d)\n", + vha->vp_idx, le32_to_cpu(ctio_exchange_addr), h, + handle, req->id, rsp->id); + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe053, + "qla_target(%d): cmd detached; ignoring CTIO (handle %x req->id %d rsp->id %d)\n", + vha->vp_idx, handle, req->id, rsp->id); + } + return NULL; + } + + if (unlikely(((srb_t *)cmd)->cmd_type != cmd_type)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe087, + "qla_target(%d): handle %x: cmd detached; ignoring CTIO (cmd_type mismatch)\n", + vha->vp_idx, h); + return NULL; + } + + switch (cmd_type) { + case TYPE_TGT_CMD: { + __le32 ctio_exchange_addr = + ((const struct ctio7_from_24xx *)ctio)-> + exchange_address; + __le32 cmd_exchange_addr = + ((struct qla_tgt_cmd *)cmd)-> + atio.u.isp24.exchange_addr; + + BUILD_BUG_ON(offsetof(struct ctio7_from_24xx, + exchange_address) != + offsetof(struct ctio_crc_from_fw, + exchange_address)); + + if (unlikely(ctio_exchange_addr != cmd_exchange_addr)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe088, + "qla_target(%d): tag %u: handle %x: cmd detached; ignoring CTIO (exchange address mismatch)\n", + vha->vp_idx, le32_to_cpu(ctio_exchange_addr), h); + return NULL; + } + break; + } + + case TYPE_TGT_TMCMD: { + __le32 ctio_exchange_addr = + ((const struct abts_resp_from_24xx_fw *)ctio)-> + exchange_address; + __le32 cmd_exchange_addr = + ((struct qla_tgt_mgmt_cmd *)cmd)-> + orig_iocb.abts.exchange_address; + + if (unlikely(ctio_exchange_addr != cmd_exchange_addr)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe089, + "qla_target(%d): ABTS: handle %x: cmd detached; ignoring CTIO (exchange address mismatch)\n", + vha->vp_idx, h); + return NULL; + } + break; + } + } + + req->outstanding_cmds[h] = NULL; return cmd; } @@ -3957,12 +4125,13 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, - struct rsp_que *rsp, uint32_t handle, uint32_t status, void *ctio) + struct rsp_que *rsp, uint32_t handle, uint32_t status, + struct ctio7_from_24xx *ctio) { struct qla_hw_data *ha = vha->hw; - struct se_cmd *se_cmd; struct qla_tgt_cmd *cmd; struct qla_qpair *qpair = rsp->qpair; + uint16_t ctio_flags; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { /* That could happen only in case of an error/reset/abort */ @@ -3974,45 +4143,92 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, return; } - cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); - if (cmd == NULL) - return; + ctio_flags = le16_to_cpu(ctio->flags); + + cmd = qlt_ctio_to_cmd(vha, rsp, handle, TYPE_TGT_CMD, ctio); + if (unlikely(cmd == NULL)) { + if ((handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE && + (ctio_flags & 0xe1ff) == (CTIO7_FLAGS_STATUS_MODE_1 | + CTIO7_FLAGS_TERMINATE)) { + u32 tag = le32_to_cpu(ctio->exchange_address); - if ((le16_to_cpu(((struct ctio7_from_24xx *)ctio)->flags) & CTIO7_FLAGS_DATA_OUT) && - cmd->sess) { - qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, - (struct ctio7_from_24xx *)ctio); + if (status == CTIO_SUCCESS) + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe083, + "qla_target(%d): tag %u: term exchange successful\n", + vha->vp_idx, tag); + else + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe084, + "qla_target(%d): tag %u: term exchange failed; status = 0x%x\n", + vha->vp_idx, tag, status); + } + return; } - se_cmd = &cmd->se_cmd; + if ((ctio_flags & CTIO7_FLAGS_DATA_OUT) && cmd->sess) + qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, ctio); + cmd->cmd_sent_to_fw = 0; qlt_unmap_sg(vha, cmd); if (unlikely(status != CTIO_SUCCESS)) { + u8 op = cmd->cdb ? cmd->cdb[0] : 0; + bool term_exchg = false; + + /* + * If the hardware terminated the exchange, then we don't need + * to send an explicit term exchange message. + */ + if (ctio_flags & OF_TERM_EXCH) { + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; + } + switch (status & 0xFFFF) { case CTIO_INVALID_RX_ID: + term_exchg = true; if (printk_ratelimit()) dev_info(&vha->hw->pdev->dev, - "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", - vha->vp_idx, cmd->atio.u.isp24.attr, + "qla_target(%d): tag %lld, op %x: CTIO with INVALID_RX_ID status 0x%x received (state %d, port %8phC, LUN %lld, ATIO attr %x, CTIO Flags %x|%x)\n", + vha->vp_idx, cmd->se_cmd.tag, op, + status, cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, cmd->atio.u.isp24.attr, ((cmd->ctio_flags >> 9) & 0xf), cmd->ctio_flags); - break; + case CTIO_LIP_RESET: case CTIO_TARGET_RESET: case CTIO_ABORTED: - /* driver request abort via Terminate exchange */ + term_exchg = true; + fallthrough; case CTIO_TIMEOUT: - /* They are OK */ + { + const char *status_str; + + switch (status & 0xFFFF) { + case CTIO_LIP_RESET: + status_str = "LIP_RESET"; + break; + case CTIO_TARGET_RESET: + status_str = "TARGET_RESET"; + break; + case CTIO_ABORTED: + status_str = "ABORTED"; + break; + case CTIO_TIMEOUT: + default: + status_str = "TIMEOUT"; + break; + } ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, - "qla_target(%d): CTIO with " - "status %#x received, state %x, se_cmd %p, " - "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, " - "TIMEOUT=b, INVALID_RX_ID=8)\n", vha->vp_idx, - status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, + status_str, status, cmd->state, + cmd->sess->port_name, cmd->unpacked_lun); break; + } case CTIO_PORT_LOGGED_OUT: case CTIO_PORT_UNAVAILABLE: @@ -4021,11 +4237,13 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, - "qla_target(%d): CTIO with %s status %x " - "received (state %x, se_cmd %p)\n", vha->vp_idx, + "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE", - status, cmd->state, se_cmd); + status, cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); + term_exchg = true; if (logged_out && cmd->sess) { /* * Session is already logged out, but we need @@ -4040,18 +4258,30 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, } break; } + + case CTIO_SRR_RECEIVED: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100e, + "qla_target(%d): tag %lld, op %x: CTIO with SRR status 0x%x received (state %d, port %8phC, LUN %lld, bufflen %d)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, cmd->bufflen); + + if (qlt_prepare_srr_ctio(qpair, cmd) == 0) + return; + break; + case CTIO_DIF_ERROR: { struct ctio_crc_from_fw *crc = (struct ctio_crc_from_fw *)ctio; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf073, - "qla_target(%d): CTIO with DIF_ERROR status %x " - "received (state %x, ulp_cmd %p) actual_dif[0x%llx] " - "expect_dif[0x%llx]\n", - vha->vp_idx, status, cmd->state, se_cmd, + "qla_target(%d): tag %lld, op %x: CTIO with DIF_ERROR status 0x%x received (state %d, port %8phC, LUN %lld, actual_dif[0x%llx] expect_dif[0x%llx])\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, *((u64 *)&crc->actual_dif[0]), *((u64 *)&crc->expected_dif[0])); - qlt_handle_dif_error(qpair, cmd, ctio); + qlt_handle_dif_error(qpair, cmd, crc); return; } @@ -4060,51 +4290,72 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, case CTIO_FAST_INVALID_REQ: case CTIO_FAST_SPI_ERR: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, - "qla_target(%d): CTIO with EDIF error status 0x%x received (state %x, se_cmd %p\n", - vha->vp_idx, status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with EDIF error status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); break; default: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, - "qla_target(%d): CTIO with error status 0x%x received (state %x, se_cmd %p\n", - vha->vp_idx, status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with error status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); break; } + cmd->trc_flags |= TRC_CTIO_ERR; - /* "cmd->aborted" means - * cmd is already aborted/terminated, we don't - * need to terminate again. The exchange is already - * cleaned up/freed at FW level. Just cleanup at driver - * level. + /* + * In state QLA_TGT_STATE_NEED_DATA the failed CTIO was for + * Data-Out, so either abort the exchange or try sending check + * condition with sense data depending on the severity of + * the error. In state QLA_TGT_STATE_PROCESSED the failed CTIO + * was for status (and possibly Data-In), so don't try sending + * an error status again in that case (if the error was for + * Data-In with status, we could try sending status without + * Data-In, but we don't do that currently). */ - if ((cmd->state != QLA_TGT_STATE_NEED_DATA) && - (!cmd->aborted)) { - cmd->trc_flags |= TRC_CTIO_ERR; - if (qlt_term_ctio_exchange(qpair, ctio, cmd, status)) - return; - } + if (!cmd->sent_term_exchg && + (term_exchg || cmd->state != QLA_TGT_STATE_NEED_DATA)) + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + } + + if (unlikely(cmd->srr != NULL)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11031, + "qla_target(%d): tag %lld, op %x: expected CTIO with SRR status; got status 0x%x: state %d, bufflen %d\n", + vha->vp_idx, cmd->se_cmd.tag, + cmd->cdb ? cmd->cdb[0] : 0, status, cmd->state, + cmd->bufflen); + qlt_srr_abort(cmd, true); } if (cmd->state == QLA_TGT_STATE_PROCESSED) { cmd->trc_flags |= TRC_CTIO_DONE; + + if (likely(status == CTIO_SUCCESS)) + cmd->rsp_sent = 1; + } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { cmd->state = QLA_TGT_STATE_DATA_IN; if (status == CTIO_SUCCESS) cmd->write_data_transferred = 1; + cmd->jiffies_at_hw_st_entry = 0; ha->tgt.tgt_ops->handle_data(cmd); return; } else if (cmd->aborted) { cmd->trc_flags |= TRC_CTIO_ABORTED; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, - "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); + "qla_target(%d): tag %lld: Aborted command finished\n", + vha->vp_idx, cmd->se_cmd.tag); } else { cmd->trc_flags |= TRC_CTIO_STRANGE; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, - "qla_target(%d): A command in state (%d) should " - "not return a CTIO complete\n", vha->vp_idx, cmd->state); + "qla_target(%d): tag %lld: A command in state (%d) should not return a CTIO complete\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); } if (unlikely(status != CTIO_SUCCESS) && @@ -4157,7 +4408,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) struct qla_hw_data *ha = vha->hw; struct fc_port *sess = cmd->sess; struct atio_from_isp *atio = &cmd->atio; - unsigned char *cdb; unsigned long flags; uint32_t data_length; int ret, fcp_task_attr, data_dir, bidi = 0; @@ -4173,8 +4423,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) goto out_term; } - spin_lock_init(&cmd->cmd_lock); - cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; cmd->se_cmd.tag = le32_to_cpu(atio->u.isp24.exchange_addr); if (atio->u.isp24.fcp_cmnd.rddata && @@ -4192,7 +4440,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) atio->u.isp24.fcp_cmnd.task_attr); data_length = get_datalen_for_atio(atio); - ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, + ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cmd->cdb, data_length, fcp_task_attr, data_dir, bidi); if (ret != 0) goto out_term; @@ -4210,9 +4458,14 @@ out_term: */ cmd->trc_flags |= TRC_DO_WORK_ERR; spin_lock_irqsave(qpair->qp_lock_ptr, flags); - qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); + qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1); qlt_decr_num_pend_cmds(vha); + if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) { + kfree(cmd->cdb); + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + } cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -4336,18 +4589,43 @@ out: cmd->se_cmd.cpuid = h->cpuid; } +/* + * Safely make a fixed-length copy of a variable-length atio by truncating the + * CDB if necessary. + */ +static void memcpy_atio(struct atio_from_isp *dst, + const struct atio_from_isp *src) +{ + int len; + + memcpy(dst, src, sizeof(*dst)); + + /* + * If the CDB was truncated, prevent get_datalen_for_atio() from + * accessing invalid memory. + */ + len = src->u.isp24.fcp_cmnd.add_cdb_len; + if (unlikely(len != 0)) { + dst->u.isp24.fcp_cmnd.add_cdb_len = 0; + memcpy(&dst->u.isp24.fcp_cmnd.add_cdb[0], + &src->u.isp24.fcp_cmnd.add_cdb[len * 4], + 4); + } +} + static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, struct fc_port *sess, struct atio_from_isp *atio) { struct qla_tgt_cmd *cmd; + int add_cdb_len; cmd = vha->hw->tgt.tgt_ops->get_cmd(sess); if (!cmd) return NULL; cmd->cmd_type = TYPE_TGT_CMD; - memcpy(&cmd->atio, atio, sizeof(*atio)); + memcpy_atio(&cmd->atio, atio); INIT_LIST_HEAD(&cmd->sess_cmd_list); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -4367,6 +4645,29 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd->vp_idx = vha->vp_idx; cmd->edif = sess->edif.enable; + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + + /* + * NOTE: memcpy_atio() set cmd->atio.u.isp24.fcp_cmnd.add_cdb_len to 0, + * so use the original value here. + */ + add_cdb_len = atio->u.isp24.fcp_cmnd.add_cdb_len; + if (unlikely(add_cdb_len != 0)) { + int cdb_len = 16 + add_cdb_len * 4; + u8 *cdb; + + cdb = kmalloc(cdb_len, GFP_ATOMIC); + if (unlikely(!cdb)) { + vha->hw->tgt.tgt_ops->free_cmd(cmd); + return NULL; + } + /* CAUTION: copy CDB from atio not cmd->atio */ + memcpy(cdb, atio->u.isp24.fcp_cmnd.cdb, cdb_len); + cmd->cdb = cdb; + cmd->cdb_len = cdb_len; + } + return cmd; } @@ -4944,6 +5245,863 @@ out: } /* + * Return true if the HBA firmware version is known to have bugs that + * prevent Sequence Level Error Recovery (SLER) / Sequence Retransmission + * Request (SRR) from working. + * + * Some bad versions are based on testing and some are based on "Marvell Fibre + * Channel Firmware Release Notes". + */ +static bool qlt_has_sler_fw_bug(struct qla_hw_data *ha) +{ + bool has_sler_fw_bug = false; + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + /* + * In the fw release notes: + * ER147301 was added to v9.05.00 causing SLER regressions + * FCD-259 was fixed in v9.08.00 + * FCD-371 was fixed in v9.08.00 + * FCD-1183 was fixed in v9.09.00 + * + * QLE2694L (ISP2071) known bad firmware (tested): + * 9.06.02 + * 9.07.00 + * 9.08.02 + * SRRs trigger hundreds of bogus entries in the response + * queue and various other problems. + * + * QLE2694L known good firmware (tested): + * 8.08.05 + * 9.09.00 + * + * Suspected bad firmware (not confirmed by testing): + * v9.05.xx + * + * unknown firmware: + * 9.00.00 - 9.04.xx + */ + if (ha->fw_major_version == 9 && + ha->fw_minor_version >= 5 && + ha->fw_minor_version <= 8) + has_sler_fw_bug = true; + } + + return has_sler_fw_bug; +} + +/* + * Return true and print a message if the HA has been reset since the SRR + * immediate notify was received; else return false. + */ +static bool qlt_srr_is_chip_reset(struct scsi_qla_host *vha, + struct qla_qpair *qpair, struct qla_tgt_srr *srr) +{ + if (!vha->flags.online || + !qpair->fw_started || + srr->reset_count != qpair->chip_reset) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100d, + "qla_target(%d): chip reset; discarding IMM SRR\n", + vha->vp_idx); + return true; + } + return false; +} + +/* Find and return the command associated with a SRR immediate notify. */ +static struct qla_tgt_cmd *qlt_srr_to_cmd(struct scsi_qla_host *vha, + const struct imm_ntfy_from_isp *iocb) +{ + struct qla_hw_data *ha = vha->hw; + struct fc_port *sess; + struct qla_tgt_cmd *cmd; + uint32_t tag = le32_to_cpu(iocb->u.isp24.exchange_address); + uint16_t loop_id; + be_id_t s_id; + unsigned long flags; + + if (tag == ATIO_EXCHANGE_ADDRESS_UNKNOWN) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11009, + "qla_target(%d): IMM SRR with unknown exchange address; reject SRR\n", + vha->vp_idx); + return NULL; + } + + loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); + + s_id.domain = iocb->u.isp24.port_id[2]; + s_id.area = iocb->u.isp24.port_id[1]; + s_id.al_pa = iocb->u.isp24.port_id[0]; + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); + if (!sess) + sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); + if (!sess || sess->deleted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100a, + "qla_target(%d): could not find session for IMM SRR; reject SRR\n", + vha->vp_idx); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return NULL; + } + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + cmd = ha->tgt.tgt_ops->find_cmd_by_tag(sess, tag); + if (!cmd) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100b, + "qla_target(%d): could not find cmd for IMM SRR; reject SRR\n", + vha->vp_idx); + } else { + u16 srr_ox_id = le16_to_cpu(iocb->u.isp24.srr_ox_id); + u16 cmd_ox_id = be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id); + + if (srr_ox_id != cmd_ox_id) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100c, + "qla_target(%d): tag %lld: IMM SRR: srr_ox_id[%04x] != cmd_ox_id[%04x]; reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag, + srr_ox_id, cmd_ox_id); + cmd = NULL; + } + } + + return cmd; +} + +/* + * Handle an immediate notify SRR (Sequence Retransmission Request) message from + * the hardware. The hardware will also send a CTIO with CTIO_SRR_RECEIVED status + * for the affected command. + * + * This may be called a second time for the same immediate notify SRR if + * CTIO_SRR_RECEIVED is never received and qlt_srr_abort() is called. + * + * Process context, no locks + */ +static void qlt_handle_srr_imm(struct scsi_qla_host *vha, + struct qla_tgt_srr *srr) +{ + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair; + struct qla_tgt_cmd *cmd; + uint8_t srr_explain = NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL; + + /* handle qlt_srr_abort() */ + if (srr->aborted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11004, + "qla_target(%d): IMM SRR: terminating SRR for aborted cmd\n", + vha->vp_idx); + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + kfree(srr); + return; + } + if (srr->reject) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11005, + "qla_target(%d): IMM SRR: rejecting SRR for unknown cmd\n", + vha->vp_idx); + goto out_reject; + } + + /* Find the command associated with the SRR. */ + cmd = qlt_srr_to_cmd(vha, &srr->imm_ntfy); + if (cmd == NULL) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11005, + "qla_target(%d): IMM SRR: rejecting SRR for unknown cmd\n", + vha->vp_idx); + srr_explain = NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_INVALID_OX_ID_RX_ID; + goto out_reject; + } + + if (ha->tgt.tgt_ops->get_cmd_ref(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11038, + "qla_target(%d): IMM SRR: unable to get cmd ref; rejecting SRR\n", + vha->vp_idx); + cmd = NULL; + goto out_reject; + } + + qpair = cmd->qpair; + + spin_lock_irq(qpair->qp_lock_ptr); + + if (cmd->reset_count != srr->reset_count) { + /* force a miscompare */ + srr->reset_count = qpair->chip_reset ^ 1; + } + if (qlt_srr_is_chip_reset(vha, qpair, srr)) { + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + kfree(srr); + return; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11001, + "qla_target(%d): tag %lld, op %x: received IMM SRR\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->cdb ? cmd->cdb[0] : 0); + + cmd->trc_flags |= TRC_SRR_IMM; + + if (cmd->srr != NULL) { + if (cmd->srr->imm_ntfy_recvd) { + /* + * Received another immediate notify SRR message for + * this command before the previous one could be processed + * (not expected to happen). + */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11006, + "qla_target(%d): tag %lld: received multiple IMM SRR; reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag); + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + goto out_reject; + } + + /* qlt_prepare_srr_ctio() was called first. */ + WARN_ON(!cmd->srr->ctio_recvd); + + /* + * The immediate notify and CTIO handlers both allocated + * separate srr structs; combine them. + */ + memcpy(&cmd->srr->imm_ntfy, &srr->imm_ntfy, + sizeof(srr->imm_ntfy)); + kfree(srr); + srr = cmd->srr; + srr->imm_ntfy_recvd = true; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11002, + "qla_target(%d): tag %lld: schedule SRR work\n", + vha->vp_idx, cmd->se_cmd.tag); + + /* Schedule the srr for processing in qlt_handle_srr(). */ + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + /* + * Already running the work function; no need to schedule + * tgt->srr_work. + */ + spin_unlock(&tgt->srr_lock); + spin_unlock_irq(qpair->qp_lock_ptr); + /* return with cmd refcount incremented */ + return; + } + + /* The CTIO SRR for this command has not yet been received. */ + + if (cmd->sent_term_exchg) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11007, + "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", + vha->vp_idx, cmd->se_cmd.tag); + spin_unlock_irq(qpair->qp_lock_ptr); + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + kfree(srr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + return; + } + + /* If not expecting a CTIO, then reject IMM SRR. */ + if (!cmd->cmd_sent_to_fw) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11008, + "qla_target(%d): tag %lld: IMM SRR but !cmd_sent_to_fw (state %d); reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + goto out_reject; + } + + /* Expect qlt_prepare_srr_ctio() to be called. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11003, + "qla_target(%d): tag %lld: wait for CTIO SRR (state %d)\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); + srr->cmd = cmd; + cmd->srr = srr; + + spin_unlock_irq(qpair->qp_lock_ptr); + + ha->tgt.tgt_ops->put_cmd_ref(cmd); + return; + +out_reject: + qpair = vha->hw->base_qpair; + spin_lock_irq(qpair->qp_lock_ptr); + if (!qlt_srr_is_chip_reset(vha, qpair, srr)) + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + srr_explain); + spin_unlock_irq(qpair->qp_lock_ptr); + kfree(srr); +} + +/* + * Handle an immediate notify SRR (Sequence Retransmission Request) message from + * the hardware. The hardware will also send a CTIO with CTIO_SRR_RECEIVED status + * for the affected command. + * + * ha->hardware_lock supposed to be held on entry + */ +static void qlt_prepare_srr_imm(struct scsi_qla_host *vha, + struct imm_ntfy_from_isp *iocb) +{ + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_tgt_srr *srr; + + ql_log(ql_log_warn, vha, 0x11000, "qla_target(%d): received IMM SRR\n", + vha->vp_idx); + + /* + * Need cmd->qpair->qp_lock_ptr, but have ha->hardware_lock. Defer + * processing to a workqueue so that the right lock can be acquired + * safely. + */ + + srr = kzalloc_obj(*srr, GFP_ATOMIC); + if (!srr) + goto out_reject; + + memcpy(&srr->imm_ntfy, iocb, sizeof(srr->imm_ntfy)); + srr->imm_ntfy_recvd = true; + srr->reset_count = vha->hw->base_qpair->chip_reset; + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work(qla_tgt_wq, &tgt->srr_work); + spin_unlock(&tgt->srr_lock); + /* resume processing in qlt_handle_srr_imm() */ + return; + +out_reject: + qlt_send_notify_ack(vha->hw->base_qpair, iocb, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); +} + +/* + * If possible, undo the effect of qlt_set_data_offset() and restore the cmd + * data buffer back to its full size. + */ +static int qlt_restore_orig_sg(struct qla_tgt_cmd *cmd) +{ + struct scsi_qla_host *vha = cmd->vha; + struct se_cmd *se_cmd = &cmd->se_cmd; + + WARN_ON(cmd->sg_mapped); + + if (cmd->offset == 0) { + /* qlt_set_data_offset() has not been called. */ + return 0; + } + + if (se_cmd->t_data_sg == NULL || + se_cmd->t_data_nents == 0 || + se_cmd->data_length == 0) { + /* The original scatterlist is not available. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102c, + "qla_target(%d): tag %lld: cannot restore original cmd buffer; keep modified buffer at offset %d\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + return -ENOENT; + } + + /* Restore the original scatterlist. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102d, + "qla_target(%d): tag %lld: restore original cmd buffer: offset %d -> 0\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + if (cmd->free_sg) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + cmd->offset = 0; + cmd->sg = se_cmd->t_data_sg; + cmd->sg_cnt = se_cmd->t_data_nents; + cmd->bufflen = se_cmd->data_length; + return 0; +} + +/* + * Adjust the data buffer of the given command to skip over offset bytes from + * the beginning while also reducing the length by offset bytes. + * + * This may be called multiple times for a single command if there are multiple + * SRRs, which each call reducing the buffer size further relative to the + * previous call. Note that the buffer may be reset back to its original size + * by calling qlt_restore_orig_sg(). + */ +static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) +{ + struct scsi_qla_host *vha = cmd->vha; + struct scatterlist *sg_srr_start = NULL, *sg; + uint32_t first_offset = offset; + int sg_srr_cnt, i; + int bufflen = 0; + + WARN_ON(cmd->sg_mapped); + + ql_dbg(ql_dbg_tgt, vha, 0x11020, + "qla_target(%d): tag %lld: %s: sg %p sg_cnt %d dir %d cmd->offset %d cmd->bufflen %d add offset %u\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->sg, + cmd->sg_cnt, cmd->dma_data_direction, cmd->offset, cmd->bufflen, + offset); + + if (cmd->se_cmd.prot_op != TARGET_PROT_NORMAL) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11021, + "qla_target(%d): tag %lld: %s: SRR with protection information at nonzero offset not implemented\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + return -EINVAL; + } + + if (!cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11022, + "qla_target(%d): tag %lld: %s: Missing cmd->sg or zero cmd->sg_cnt\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + return -EINVAL; + } + + /* + * Walk the current cmd->sg list until we locate the new sg_srr_start + */ + for_each_sg(cmd->sg, sg, cmd->sg_cnt, i) { + ql_dbg(ql_dbg_tgt, vha, 0x11023, + "sg[%d]: %p page: %p, length: %d, offset: %d\n", + i, sg, sg_page(sg), sg->length, sg->offset); + + if (first_offset < sg->length) { + sg_srr_start = sg; + break; + } + first_offset -= sg->length; + } + + if (!sg_srr_start) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11024, + "qla_target(%d): tag %lld: Unable to locate sg_srr_start for offset: %u\n", + vha->vp_idx, cmd->se_cmd.tag, offset); + return -EINVAL; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11025, + "qla_target(%d): tag %lld: prepare SRR sgl at sg index %d of %d byte offset %u of %u\n", + vha->vp_idx, cmd->se_cmd.tag, i, cmd->sg_cnt, + first_offset, sg_srr_start->length); + + sg_srr_cnt = cmd->sg_cnt - i; + + if (first_offset == 0 && !cmd->free_sg) { + /* + * The offset points to the beginning of a scatterlist element. + * In this case there is no need to modify the first scatterlist + * element, so we can just point directly inside the original + * unmodified scatterlist. + */ + ql_dbg(ql_dbg_tgt, vha, 0x11026, "point directly to old sgl\n"); + cmd->sg = sg_srr_start; + } else { + /* + * Allocate at most 2 new scatterlist elements to reduce memory + * requirements. + */ + int n_alloc_sg = min(sg_srr_cnt, 2); + struct scatterlist *sg_srr = + kmalloc_objs(*sg_srr, n_alloc_sg, GFP_ATOMIC); + if (!sg_srr) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11027, + "qla_target(%d): tag %lld: Unable to allocate SRR scatterlist\n", + vha->vp_idx, cmd->se_cmd.tag); + return -ENOMEM; + } + sg_init_table(sg_srr, n_alloc_sg); + + /* Init the first sg element to skip over the unneeded data. */ + sg_set_page(&sg_srr[0], sg_page(sg_srr_start), + sg_srr_start->length - first_offset, + sg_srr_start->offset + first_offset); + if (sg_srr_cnt == 1) { + ql_dbg(ql_dbg_tgt, vha, 0x11028, + "single-element array\n"); + } else if (sg_srr_cnt == 2) { + /* Only two elements; copy the last element. */ + ql_dbg(ql_dbg_tgt, vha, 0x11029, + "complete two-element array\n"); + sg = sg_next(sg_srr_start); + sg_set_page(&sg_srr[1], sg_page(sg), sg->length, + sg->offset); + } else { + /* + * Three or more elements; chain our newly-allocated + * 2-entry array to the rest of the original + * scatterlist at the splice point. + */ + ql_dbg(ql_dbg_tgt, vha, 0x1102a, + "chain to original scatterlist\n"); + sg = sg_next(sg_srr_start); + sg_chain(sg_srr, 2, sg); + } + + /* + * If the previous scatterlist was allocated here on a previous + * call, then it should be safe to free now. + */ + if (cmd->free_sg) + qlt_free_sg(cmd); + cmd->sg = sg_srr; + cmd->free_sg = 1; + } + + /* Note that sg_cnt doesn't include any extra chain elements. */ + cmd->sg_cnt = sg_srr_cnt; + cmd->offset += offset; + cmd->bufflen -= offset; + + /* Check the scatterlist length for consistency. */ + for_each_sg(cmd->sg, sg, cmd->sg_cnt, i) { + bufflen += sg->length; + } + if (bufflen != cmd->bufflen) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102b, + "qla_target(%d): tag %lld: %s: bad sgl length: expected %d got %d\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->bufflen, bufflen); + return -EINVAL; + } + + return 0; +} + +/* + * Given the "SRR relative offset" (offset of data to retry), determine what + * needs to be retransmitted (data and/or status) and return the mask in + * xmit_type. If retrying data, adjust the command buffer to point to only the + * data that need to be retried, skipping over the data that don't need to be + * retried. + * + * Returns 0 for success or a negative error number. + */ +static inline int qlt_srr_adjust_data(struct qla_tgt_cmd *cmd, + uint32_t srr_rel_offs, int *xmit_type) +{ + struct scsi_qla_host *vha = cmd->vha; + int res = 0, rel_offs; + + if (srr_rel_offs < cmd->offset || + srr_rel_offs > cmd->offset + cmd->bufflen) { + *xmit_type = 0; + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101e, + "qla_target(%d): tag %lld: srr_rel_offs %u outside accepted range %u - %u\n", + vha->vp_idx, cmd->se_cmd.tag, srr_rel_offs, + cmd->offset, cmd->offset + cmd->bufflen); + return -EINVAL; + } + + /* + * srr_rel_offs is the offset of the data we need from the beginning of + * the *original* buffer. + * + * cmd->offset is the offset of the current cmd scatterlist from the + * beginning of the *original* buffer, which might be nonzero if there + * was a previous SRR and the buffer could not be reset back to its + * original size. + * + * rel_offs is the offset of the data we need from the beginning of the + * current cmd scatterlist. + */ + rel_offs = srr_rel_offs - cmd->offset; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101f, + "qla_target(%d): tag %lld: current buffer [%u - %u); srr_rel_offs=%d, rel_offs=%d\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset, + cmd->offset + cmd->bufflen, srr_rel_offs, rel_offs); + + *xmit_type = QLA_TGT_XMIT_ALL; + + if (rel_offs == cmd->bufflen) + *xmit_type = QLA_TGT_XMIT_STATUS; + else if (rel_offs > 0) + res = qlt_set_data_offset(cmd, rel_offs); + + return res; +} + +/* + * Process a SRR (Sequence Retransmission Request) for a SCSI command once both + * the immediate notify SRR and CTIO SRR have been received from the hw. + * + * Process context, no locks + */ +static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) +{ + struct qla_tgt_cmd *cmd = srr->cmd; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct qla_qpair *qpair = cmd->qpair; + struct qla_hw_data *ha = vha->hw; + uint8_t op = cmd->cdb ? cmd->cdb[0] : 0; + uint32_t srr_rel_offs = le32_to_cpu(srr->imm_ntfy.u.isp24.srr_rel_offs); + uint16_t srr_ui = le16_to_cpu(srr->imm_ntfy.u.isp24.srr_ui); + int xmit_type = 0; + bool xmit_response = false; + bool rdy_to_xfer = false; + bool did_timeout; + bool send_term_exch = false; + + spin_lock_irq(qpair->qp_lock_ptr); + + WARN_ON(cmd->cmd_sent_to_fw); + + cmd->srr = NULL; + + if (qlt_srr_is_chip_reset(vha, qpair, srr)) + goto out_advance_cmd; + + if (cmd->sent_term_exchg || cmd->sess->deleted || srr->aborted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11010, + "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", + vha->vp_idx, cmd->se_cmd.tag); + + spin_unlock_irq(qpair->qp_lock_ptr); + + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + + send_term_exch = true; + + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + + if (srr->reject) + goto out_reject; + + /* + * If we receive multiple SRRs for the same command, place a time limit + * on how long we are willing to retry. This timeout should be less + * than SQA_MAX_HW_PENDING_TIME in scst_qla2xxx.c. + */ + did_timeout = time_is_before_jiffies64((cmd->jiffies_at_hw_st_entry ? : + cmd->jiffies_at_alloc) + 30 * HZ); + + qlt_restore_orig_sg(cmd); + + switch (srr_ui) { + case SRR_IU_STATUS: + if (cmd->state != QLA_TGT_STATE_PROCESSED) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11011, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, op, + cmd->state); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11033, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11012, + "qla_target(%d): tag %lld, op %x: accept SRR_IU_STATUS and retransmit scsi_status=%x\n", + vha->vp_idx, se_cmd->tag, op, + se_cmd->scsi_status); + xmit_type = QLA_TGT_XMIT_STATUS; + xmit_response = true; + cmd->trc_flags |= TRC_SRR_RSP; + break; + + case SRR_IU_DATA_IN: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11013, + "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_IN: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d, scsi_status=%x\n", + vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + cmd->sg_cnt, cmd->offset, srr_rel_offs, + se_cmd->scsi_status); + + if (cmd->state != QLA_TGT_STATE_PROCESSED) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11014, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, cmd->state); + goto out_reject; + } + + /* + * QLA_TGT_STATE_PROCESSED does not necessarily imply data-in + */ + if (!qlt_has_data(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11015, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because cmd has no data to send\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (!cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11016, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because buffer is missing\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11034, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_IN due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + if (qlt_srr_adjust_data(cmd, srr_rel_offs, &xmit_type) != 0) + goto out_reject; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11017, + "qla_target(%d): tag %lld: accept SRR_IU_DATA_IN and retransmit data: bufflen=%d, offset=%d\n", + vha->vp_idx, se_cmd->tag, cmd->bufflen, + cmd->offset); + xmit_response = true; + cmd->trc_flags |= TRC_SRR_RSP; + break; + + case SRR_IU_DATA_OUT: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11018, + "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_OUT: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d\n", + vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + cmd->sg_cnt, cmd->offset, srr_rel_offs); + + if (cmd->state != QLA_TGT_STATE_NEED_DATA) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11019, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, cmd->state); + goto out_reject; + } + + /* + * QLA_TGT_STATE_NEED_DATA implies there should be data-out + */ + if (!qlt_has_data(cmd) || !cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101a, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT because buffer is missing\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11035, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_OUT due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + if (qlt_srr_adjust_data(cmd, srr_rel_offs, &xmit_type) != 0) + goto out_reject; + + if (!(xmit_type & QLA_TGT_XMIT_DATA)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101b, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT: bad offset\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101c, + "qla_target(%d): tag %lld: accept SRR_IU_DATA_OUT and receive data again: bufflen=%d, offset=%d\n", + vha->vp_idx, se_cmd->tag, cmd->bufflen, + cmd->offset); + cmd->trc_flags |= TRC_SRR_XRDY; + rdy_to_xfer = true; + break; + + default: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101d, + "qla_target(%d): tag %lld, op %x: reject unknown srr_ui value 0x%x: state=%d, bufflen=%d, offset=%d, srr_offset=%d\n", + vha->vp_idx, se_cmd->tag, op, srr_ui, cmd->state, + cmd->bufflen, cmd->offset, srr_rel_offs); + goto out_reject; + } + + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_ACCEPT, 0, 0); + + spin_unlock_irq(qpair->qp_lock_ptr); + + if (xmit_response) { + /* For status and data-in, retransmit the response. */ + if (qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status)) { + send_term_exch = true; + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + } else if (rdy_to_xfer) { + /* For data-out, receive data again. */ + if (qlt_rdy_to_xfer(cmd)) { + send_term_exch = true; + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + } + + return; + +out_reject: + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); + +out_advance_cmd: + if (!cmd->sent_term_exchg && + (send_term_exch || cmd->state != QLA_TGT_STATE_NEED_DATA) && + !qlt_srr_is_chip_reset(vha, qpair, srr)) { + cmd->trc_flags |= TRC_SRR_TERM; + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + } + if (cmd->state == QLA_TGT_STATE_NEED_DATA) { + /* + * The initiator should abort the command, but if not, try to + * return an error. + */ + cmd->srr_failed = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; + vha->hw->tgt.tgt_ops->handle_data(cmd); + } else { + vha->hw->tgt.tgt_ops->free_cmd(cmd); + } + spin_unlock_irq(qpair->qp_lock_ptr); +} + +/* Workqueue function for processing SRR work in process context. */ +static void qlt_handle_srr_work(struct work_struct *work) +{ + struct qla_tgt *tgt = container_of(work, struct qla_tgt, srr_work); + struct scsi_qla_host *vha = tgt->vha; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11032, + "qla_target(%d): Entering SRR work\n", vha->vp_idx); + + for (;;) { + struct qla_tgt_srr *srr; + + spin_lock_irq(&tgt->srr_lock); + srr = list_first_entry_or_null(&tgt->srr_list, typeof(*srr), + srr_list_entry); + if (!srr) { + spin_unlock_irq(&tgt->srr_lock); + break; + } + list_del(&srr->srr_list_entry); + spin_unlock_irq(&tgt->srr_lock); + + if (!srr->cmd) { + qlt_handle_srr_imm(vha, srr); + } else { + qlt_handle_srr(vha, srr); + vha->hw->tgt.tgt_ops->put_cmd_ref(srr->cmd); + kfree(srr); + } + } +} + +/* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, @@ -5369,6 +6527,12 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, if (qlt_24xx_handle_els(vha, iocb) == 0) send_notify_ack = 0; break; + + case IMM_NTFY_SRR: + qlt_prepare_srr_imm(vha, iocb); + send_notify_ack = 0; + break; + default: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06d, "qla_target(%d): Received unknown immediate " @@ -5403,7 +6567,7 @@ static int __qlt_send_busy(struct qla_qpair *qpair, sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); if (!sess) { - qlt_send_term_exchange(qpair, NULL, atio, 1, 0); + qlt_send_term_exchange(qpair, NULL, atio, 1); return 0; } /* Sending marker isn't necessary, since we called from ISR */ @@ -5513,13 +6677,15 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); - memcpy(&cmd->atio, atio, sizeof(*atio)); + memcpy_atio(&cmd->atio, atio); cmd->tgt = vha->vha_tgt.qla_tgt; cmd->vha = vha; cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; cmd->qpair = ha->base_qpair; + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; if (qfull) { cmd->q_full = 1; @@ -5539,81 +6705,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); } -int -qlt_free_qfull_cmds(struct qla_qpair *qpair) -{ - struct scsi_qla_host *vha = qpair->vha; - struct qla_hw_data *ha = vha->hw; - unsigned long flags; - struct qla_tgt_cmd *cmd, *tcmd; - struct list_head free_list, q_full_list; - int rc = 0; - - if (list_empty(&ha->tgt.q_full_list)) - return 0; - - INIT_LIST_HEAD(&free_list); - INIT_LIST_HEAD(&q_full_list); - - spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); - if (list_empty(&ha->tgt.q_full_list)) { - spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); - return 0; - } - - list_splice_init(&vha->hw->tgt.q_full_list, &q_full_list); - spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); - - spin_lock_irqsave(qpair->qp_lock_ptr, flags); - list_for_each_entry_safe(cmd, tcmd, &q_full_list, cmd_list) { - if (cmd->q_full) - /* cmd->state is a borrowed field to hold status */ - rc = __qlt_send_busy(qpair, &cmd->atio, cmd->state); - else if (cmd->term_exchg) - rc = __qlt_send_term_exchange(qpair, NULL, &cmd->atio); - - if (rc == -ENOMEM) - break; - - if (cmd->q_full) - ql_dbg(ql_dbg_io, vha, 0x3006, - "%s: busy sent for ox_id[%04x]\n", __func__, - be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); - else if (cmd->term_exchg) - ql_dbg(ql_dbg_io, vha, 0x3007, - "%s: Term exchg sent for ox_id[%04x]\n", __func__, - be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); - else - ql_dbg(ql_dbg_io, vha, 0x3008, - "%s: Unexpected cmd in QFull list %p\n", __func__, - cmd); - - list_move_tail(&cmd->cmd_list, &free_list); - - /* piggy back on hardware_lock for protection */ - vha->hw->tgt.num_qfull_cmds_alloc--; - } - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - - cmd = NULL; - - list_for_each_entry_safe(cmd, tcmd, &free_list, cmd_list) { - list_del(&cmd->cmd_list); - /* This cmd was never sent to TCM. There is no need - * to schedule free or call free_cmd - */ - qlt_free_cmd(cmd); - } - - if (!list_empty(&q_full_list)) { - spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); - list_splice(&q_full_list, &vha->hw->tgt.q_full_list); - spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); - } - - return rc; -} - static void qlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, uint16_t status) @@ -5707,7 +6798,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe05f, "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); qlt_send_term_exchange(ha->base_qpair, NULL, - atio, 1, 0); + atio, 1); break; case -EBUSY: ql_dbg(ql_dbg_tgt, vha, 0xe060, @@ -5816,7 +6907,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, struct qla_tgt_mgmt_cmd *mcmd; struct qla_hw_data *ha = vha->hw; - mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, pkt); + mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, TYPE_TGT_TMCMD, pkt); if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { ql_dbg(ql_dbg_async, vha, 0xe064, "qla_target(%d): ABTS Comp without mcmd\n", @@ -5836,7 +6927,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, if (le32_to_cpu(entry->error_subcode1) == 0x1E && le32_to_cpu(entry->error_subcode2) == 0) { if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) { - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); return; } qlt_24xx_retry_term_exchange(vha, rsp->qpair, @@ -5847,10 +6938,10 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, vha->vp_idx, entry->compl_status, entry->error_subcode1, entry->error_subcode2); - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); } } else if (mcmd) { - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); } } @@ -5914,7 +7005,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe05f, "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); qlt_send_term_exchange(rsp->qpair, NULL, - atio, 1, 0); + atio, 1); break; case -EBUSY: ql_dbg(ql_dbg_tgt, vha, 0xe060, @@ -5935,26 +7026,6 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, } break; - case CONTINUE_TGT_IO_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - - qlt_do_ctio_completion(vha, rsp, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - - case CTIO_A64_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - - qlt_do_ctio_completion(vha, rsp, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - case IMMED_NOTIFY_TYPE: ql_dbg(ql_dbg_tgt, vha, 0xe035, "%s", "IMMED_NOTIFY\n"); qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)pkt); @@ -6387,16 +7458,14 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) BUG_ON(base_vha->vha_tgt.qla_tgt != NULL); - tgt = kzalloc(sizeof(struct qla_tgt), GFP_KERNEL); + tgt = kzalloc_obj(struct qla_tgt); if (!tgt) { ql_dbg(ql_dbg_tgt, base_vha, 0xe066, "Unable to allocate struct qla_tgt\n"); return -ENOMEM; } - tgt->qphints = kcalloc(ha->max_qpairs + 1, - sizeof(struct qla_qpair_hint), - GFP_KERNEL); + tgt->qphints = kzalloc_objs(struct qla_qpair_hint, ha->max_qpairs + 1); if (!tgt->qphints) { kfree(tgt); ql_log(ql_log_warn, base_vha, 0x0197, @@ -6442,6 +7511,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) spin_lock_init(&tgt->sess_work_lock); INIT_WORK(&tgt->sess_work, qlt_sess_work_fn); INIT_LIST_HEAD(&tgt->sess_works_list); + spin_lock_init(&tgt->srr_lock); + INIT_LIST_HEAD(&tgt->srr_list); + INIT_WORK(&tgt->srr_work, qlt_handle_srr_work); atomic_set(&tgt->tgt_global_resets_count, 0); base_vha->vha_tgt.qla_tgt = tgt; @@ -6824,7 +7896,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) adjust_corrupted_atio(pkt); qlt_send_term_exchange(ha->base_qpair, NULL, pkt, - ha_locked, 0); + ha_locked); } else { qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt, ha_locked); @@ -7090,15 +8162,31 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, } } +/* Update any settings that depend on ha->fw_*_version. */ void -qlt_83xx_iospace_config(struct qla_hw_data *ha) +qlt_config_nvram_with_fw_version(struct scsi_qla_host *vha) { + struct qla_hw_data *ha = vha->hw; + if (!QLA_TGT_MODE_ENABLED()) return; - ha->msix_count += 1; /* For ATIO Q */ -} + if (ql2xtgt_tape_enable && qlt_has_sler_fw_bug(ha)) { + ql_log(ql_log_warn, vha, 0x11036, + "WARNING: ignoring ql2xtgt_tape_enable due to buggy HBA firmware; please upgrade FW\n"); + /* Disable FC Tape support */ + if (ha->isp_ops->nvram_config == qla81xx_nvram_config) { + struct init_cb_81xx *icb = + (struct init_cb_81xx *)ha->init_cb; + icb->firmware_options_2 &= cpu_to_le32(~BIT_12); + } else { + struct init_cb_24xx *icb = + (struct init_cb_24xx *)ha->init_cb; + icb->firmware_options_2 &= cpu_to_le32(~BIT_12); + } + } +} void qlt_modify_vp_config(struct scsi_qla_host *vha, @@ -7190,7 +8278,7 @@ qlt_handle_abts_recv(struct scsi_qla_host *vha, struct rsp_que *rsp, { struct qla_tgt_sess_op *op; - op = kzalloc(sizeof(*op), GFP_ATOMIC); + op = kzalloc_obj(*op, GFP_ATOMIC); if (!op) { /* do not reach for ATIO queue here. This is best effort err @@ -7300,7 +8388,7 @@ int __init qlt_init(void) goto out_plogi_cachep; } - qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0); + qla_tgt_wq = alloc_workqueue("qla_tgt_wq", WQ_PERCPU, 0); if (!qla_tgt_wq) { ql_log(ql_log_fatal, NULL, 0xe06f, "alloc_workqueue for qla_tgt_wq failed\n"); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 354fca2e7feb..61072fb41b29 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -184,6 +184,7 @@ struct nack_to_isp { #define NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM 0x9 #define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL 0 +#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_INVALID_OX_ID_RX_ID 0x17 #define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_UNABLE_TO_SUPPLY_DATA 0x2a #define NOTIFY_ACK_SUCCESS 0x01 @@ -686,6 +687,8 @@ struct qla_tgt_func_tmpl { int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t, uint32_t); struct qla_tgt_cmd *(*get_cmd)(struct fc_port *); + int (*get_cmd_ref)(struct qla_tgt_cmd *cmd); + void (*put_cmd_ref)(struct qla_tgt_cmd *cmd); void (*rel_cmd)(struct qla_tgt_cmd *); void (*free_cmd)(struct qla_tgt_cmd *); void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); @@ -754,6 +757,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *); #define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */ #define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */ #define QLA_TGT_STATE_PROCESSED 3 /* target done processing */ +#define QLA_TGT_STATE_DONE 4 /* cmd being freed */ /* ATIO task_codes field */ #define ATIO_SIMPLE_QUEUE 0 @@ -822,18 +826,26 @@ struct qla_tgt { int notify_ack_expected; int abts_resp_expected; int modify_lun_expected; + + spinlock_t srr_lock; + struct list_head srr_list; + struct work_struct srr_work; + atomic_t tgt_global_resets_count; + struct list_head tgt_list_entry; }; struct qla_tgt_sess_op { struct scsi_qla_host *vha; uint32_t chip_reset; - struct atio_from_isp atio; struct work_struct work; struct list_head cmd_list; bool aborted; struct rsp_que *rsp; + + struct atio_from_isp atio; + /* DO NOT ADD ANYTHING ELSE HERE - atio must be last member */ }; enum trace_flags { @@ -858,6 +870,7 @@ enum trace_flags { TRC_DATA_IN = BIT_18, TRC_ABORT = BIT_19, TRC_DIF_ERR = BIT_20, + TRC_SRR_IMM = BIT_21, }; struct qla_tgt_cmd { @@ -876,25 +889,36 @@ struct qla_tgt_cmd { /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; - spinlock_t cmd_lock; - /* to save extra sess dereferences */ unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; + + /* Call qlt_free_sg() if set. */ + unsigned int free_sg:1; + unsigned int write_data_transferred:1; + + /* Set if the SCSI status was sent successfully. */ + unsigned int rsp_sent:1; + unsigned int q_full:1; unsigned int term_exchg:1; unsigned int cmd_sent_to_fw:1; unsigned int cmd_in_wq:1; unsigned int edif:1; + /* Set if a SRR was rejected. */ + unsigned int srr_failed:1; + + /* Set if the exchange has been terminated. */ + unsigned int sent_term_exchg:1; + /* - * This variable may be set from outside the LIO and I/O completion - * callback functions. Do not declare this member variable as a - * bitfield to avoid a read-modify-write operation when this variable - * is set. + * Set if sent_term_exchg is set, or if the cmd was aborted by a TMR, + * or if some other error prevents normal processing of the command. */ - unsigned int aborted; + unsigned int aborted:1; + struct qla_tgt_srr *srr; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ int bufflen; /* cmd buffer length */ @@ -925,13 +949,23 @@ struct qla_tgt_cmd { uint8_t scsi_status, sense_key, asc, ascq; struct crc_context *ctx; - const uint8_t *cdb; + uint8_t *cdb; uint64_t lba; + int cdb_len; uint16_t a_guard, e_guard, a_app_tag, e_app_tag; uint32_t a_ref_tag, e_ref_tag; #define DIF_BUNDL_DMA_VALID 1 uint16_t prot_flags; + unsigned long jiffies_at_term_exchg; + + /* + * jiffies64 when qlt_rdy_to_xfer() or qlt_xmit_response() first + * called, or 0 when not in those states. Used to limit the number of + * SRR retries. + */ + uint64_t jiffies_at_hw_st_entry; + uint64_t jiffies_at_alloc; uint64_t jiffies_at_free; @@ -965,6 +999,7 @@ struct qla_tgt_mgmt_cmd { unsigned int flags; #define QLA24XX_MGMT_SEND_NACK BIT_0 #define QLA24XX_MGMT_ABORT_IO_ATTR_VALID BIT_1 +#define QLA24XX_MGMT_LLD_OWNED BIT_2 uint32_t reset_count; struct work_struct work; uint64_t unpacked_lun; @@ -993,6 +1028,45 @@ struct qla_tgt_prm { uint16_t tot_dsds; }; +/* + * SRR (Sequence Retransmission Request) - resend or re-receive some or all + * data or status to recover from a transient I/O error. + */ +struct qla_tgt_srr { + /* + * Copy of immediate notify SRR message received from hw; valid only if + * imm_ntfy_recvd is true. + */ + struct imm_ntfy_from_isp imm_ntfy; + + struct list_head srr_list_entry; + + /* The command affected by this SRR, or NULL if not yet determined. */ + struct qla_tgt_cmd *cmd; + + /* Used to detect if the HBA has been reset since receiving the SRR. */ + uint32_t reset_count; + + /* + * The hardware sends two messages for each SRR - an immediate notify + * and a CTIO with CTIO_SRR_RECEIVED status. These keep track of which + * messages have been received. The SRR can be processed once both of + * these are true. + */ + bool imm_ntfy_recvd; + bool ctio_recvd; + + /* + * This is set to true if the affected command was aborted (cmd may be + * set to NULL), in which case the immediate notify exchange also needs + * to be aborted. + */ + bool aborted; + + /* This is set to true to force the SRR to be rejected. */ + bool reject; +}; + /* Check for Switch reserved address */ #define IS_SW_RESV_ADDR(_s_id) \ ((_s_id.b.domain == 0xff) && ((_s_id.b.area & 0xf0) == 0xf0)) @@ -1014,7 +1088,6 @@ extern int qlt_lport_register(void *, u64, u64, u64, extern void qlt_lport_deregister(struct scsi_qla_host *); extern void qlt_unreg_sess(struct fc_port *); extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); -extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int); extern int __init qlt_init(void); extern void qlt_exit(void); extern void qlt_free_session_done(struct work_struct *); @@ -1049,6 +1122,20 @@ static inline uint32_t sid_to_key(const be_id_t s_id) } /* + * Free the scatterlist allocated by qlt_set_data_offset(). Call this only if + * cmd->free_sg is set. + */ +static inline void qlt_free_sg(struct qla_tgt_cmd *cmd) +{ + /* + * The scatterlist may be chained to the original scatterlist, but we + * only need to free the first segment here since that is the only part + * allocated by qlt_set_data_offset(). + */ + kfree(cmd->sg); +} + +/* * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. */ extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *, @@ -1056,9 +1143,14 @@ extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *, extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); extern int qlt_abort_cmd(struct qla_tgt_cmd *); +void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject); +void qlt_send_term_exchange(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); +void qlt_free_ul_mcmd(struct qla_hw_data *ha, struct qla_tgt_mgmt_cmd *mcmd); extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); +extern void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd); extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *); extern void qlt_enable_vha(struct scsi_qla_host *); extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *); @@ -1074,6 +1166,7 @@ extern void qlt_81xx_config_nvram_stage2(struct scsi_qla_host *, struct init_cb_81xx *); extern void qlt_81xx_config_nvram_stage1(struct scsi_qla_host *, struct nvram_81xx *); +void qlt_config_nvram_with_fw_version(struct scsi_qla_host *vha); extern void qlt_modify_vp_config(struct scsi_qla_host *, struct vp_config_entry_24xx *); extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *); @@ -1082,8 +1175,6 @@ extern void qlt_mem_free(struct qla_hw_data *); extern int qlt_stop_phase1(struct qla_tgt *); extern void qlt_stop_phase2(struct qla_tgt *); extern irqreturn_t qla83xx_msix_atio_q(int, void *); -extern void qlt_83xx_iospace_config(struct qla_hw_data *); -extern int qlt_free_qfull_cmds(struct qla_qpair *); extern void qlt_logo_completion_handler(fc_port_t *, int); extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index a491d6ee5c94..9564beafdab7 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.09.400-k" +#define QLA2XXX_VERSION "10.02.10.100-k" #define QLA_DRIVER_MAJOR_VER 10 -#define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 9 -#define QLA_DRIVER_BETA_VER 400 +#define QLA_DRIVER_MINOR_VER 02 +#define QLA_DRIVER_PATCH_VER 10 +#define QLA_DRIVER_BETA_VER 100 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index ceaf1c7b1d17..3be23ed067e6 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/utsname.h> #include <linux/vmalloc.h> +#include <linux/hex.h> #include <linux/list.h> #include <linux/slab.h> #include <linux/types.h> @@ -291,6 +292,16 @@ static struct qla_tgt_cmd *tcm_qla2xxx_get_cmd(struct fc_port *sess) return cmd; } +static int tcm_qla2xxx_get_cmd_ref(struct qla_tgt_cmd *cmd) +{ + return target_get_sess_cmd(&cmd->se_cmd, true); +} + +static void tcm_qla2xxx_put_cmd_ref(struct qla_tgt_cmd *cmd) +{ + target_put_sess_cmd(&cmd->se_cmd); +} + static void tcm_qla2xxx_rel_cmd(struct qla_tgt_cmd *cmd) { target_free_tag(cmd->sess->se_sess, &cmd->se_cmd); @@ -303,6 +314,8 @@ static void tcm_qla2xxx_rel_cmd(struct qla_tgt_cmd *cmd) */ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) { + cmd->state = QLA_TGT_STATE_DONE; + cmd->qpair->tgt_counters.core_qla_free_cmd++; cmd->cmd_in_wq = 1; @@ -529,6 +542,9 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) if (cmd->se_cmd.pi_err) transport_generic_request_failure(&cmd->se_cmd, cmd->se_cmd.pi_err); + else if (cmd->srr_failed) + transport_generic_request_failure(&cmd->se_cmd, + TCM_SNACK_REJECTED); else transport_generic_request_failure(&cmd->se_cmd, TCM_CHECK_CONDITION_ABORT_CMD); @@ -999,7 +1015,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(struct se_wwn *wwn, return ERR_PTR(-ENOSYS); } - tpg = kzalloc(sizeof(struct tcm_qla2xxx_tpg), GFP_KERNEL); + tpg = kzalloc_obj(struct tcm_qla2xxx_tpg); if (!tpg) { pr_err("Unable to allocate struct tcm_qla2xxx_tpg\n"); return ERR_PTR(-ENOMEM); @@ -1090,7 +1106,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(struct se_wwn *wwn, if (kstrtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX) return ERR_PTR(-EINVAL); - tpg = kzalloc(sizeof(struct tcm_qla2xxx_tpg), GFP_KERNEL); + tpg = kzalloc_obj(struct tcm_qla2xxx_tpg); if (!tpg) { pr_err("Unable to allocate struct tcm_qla2xxx_tpg\n"); return ERR_PTR(-ENOMEM); @@ -1524,6 +1540,8 @@ static const struct qla_tgt_func_tmpl tcm_qla2xxx_template = { .handle_data = tcm_qla2xxx_handle_data, .handle_tmr = tcm_qla2xxx_handle_tmr, .get_cmd = tcm_qla2xxx_get_cmd, + .get_cmd_ref = tcm_qla2xxx_get_cmd_ref, + .put_cmd_ref = tcm_qla2xxx_put_cmd_ref, .rel_cmd = tcm_qla2xxx_rel_cmd, .free_cmd = tcm_qla2xxx_free_cmd, .free_mcmd = tcm_qla2xxx_free_mcmd, @@ -1591,7 +1609,7 @@ static struct se_wwn *tcm_qla2xxx_make_lport( if (tcm_qla2xxx_parse_wwn(name, &wwpn, 1) < 0) return ERR_PTR(-EINVAL); - lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL); + lport = kzalloc_obj(struct tcm_qla2xxx_lport); if (!lport) { pr_err("Unable to allocate struct tcm_qla2xxx_lport\n"); return ERR_PTR(-ENOMEM); @@ -1717,7 +1735,7 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport( &npiv_wwpn, &npiv_wwnn) < 0) return ERR_PTR(-EINVAL); - lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL); + lport = kzalloc_obj(struct tcm_qla2xxx_lport); if (!lport) { pr_err("Unable to allocate struct tcm_qla2xxx_lport for NPIV\n"); return ERR_PTR(-ENOMEM); @@ -1823,6 +1841,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs, .tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; @@ -1863,6 +1882,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; @@ -1884,7 +1904,7 @@ static int tcm_qla2xxx_register_configfs(void) goto out_fabric; tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", - WQ_MEM_RECLAIM, 0); + WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!tcm_qla2xxx_free_wq) { ret = -ENOMEM; goto out_fabric_npiv; diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c index e3f85d6ea0db..84f99ff8e69a 100644 --- a/drivers/scsi/qla4xxx/ql4_attr.c +++ b/drivers/scsi/qla4xxx/ql4_attr.c @@ -110,8 +110,8 @@ static const struct bin_attribute sysfs_fw_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla4_8xxx_sysfs_read_fw_dump, - .write_new = qla4_8xxx_sysfs_write_fw_dump, + .read = qla4_8xxx_sysfs_read_fw_dump, + .write = qla4_8xxx_sysfs_write_fw_dump, }; static struct sysfs_entry { diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index 28eab07935ba..c40441b12db9 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -451,7 +451,7 @@ static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha) { struct mrb *mrb; - mrb = kzalloc(sizeof(*mrb), GFP_KERNEL); + mrb = kzalloc_obj(*mrb); if (!mrb) return mrb; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 75125d2021f5..7febc0baa9d6 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1016,7 +1016,7 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha) uint32_t crash_record_size = 0; memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); /* Get size of crash record. */ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; @@ -1099,7 +1099,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) /* Get Crash Record. */ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; mbox_cmd[2] = LSDW(event_log_dma); diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 47adff9f0506..f7340cfc990a 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -973,11 +973,6 @@ qla4_82xx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) unsigned long off; unsigned offset, n; - struct crb_addr_pair { - long addr; - long data; - }; - /* Halt all the indiviual PEGs and other blocks of the ISP */ qla4_82xx_rom_lock(ha); @@ -1063,7 +1058,7 @@ qla4_82xx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) ql4_printk(KERN_INFO, ha, "%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n); - buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL); + buf = kmalloc_objs(struct crb_addr_pair, n); if (buf == NULL) { ql4_printk(KERN_WARNING, ha, "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME); @@ -1557,7 +1552,7 @@ static int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val) (val == PHAN_INITIALIZE_ACK)) return 0; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(500); + schedule_timeout(msecs_to_jiffies(500)); } while (--retries); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6b0e6b4cd8af..d598ab4126f8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -155,7 +155,8 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len); /* * SCSI host template entry points */ -static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); @@ -3420,6 +3421,8 @@ static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, task->data_count, DMA_TO_DEVICE); + if (dma_mapping_error(&ha->pdev->dev, task_data->data_dma)) + return -ENOMEM; } DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", @@ -4021,7 +4024,7 @@ static void qla4xxx_start_timer(struct scsi_qla_host *ha, static void qla4xxx_stop_timer(struct scsi_qla_host *ha) { - del_timer_sync(&ha->timer); + timer_delete_sync(&ha->timer); ha->timer_active = 0; } @@ -4102,10 +4105,11 @@ void qla4xxx_srb_compl(struct kref *ref) * The mid-level driver tries to ensure that queuecommand never gets * invoked concurrently with itself or the interrupt handler (although * the interrupt handler may call this routine as part of request- - * completion handling). Unfortunely, it sometimes calls the scheduler + * completion handling). Unfortunately, it sometimes calls the scheduler * in interrupt context which is a big NO! NO!. **/ -static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct scsi_qla_host *ha = to_qla_host(host); struct ddb_entry *ddb_entry = cmd->device->hostdata; @@ -4551,7 +4555,7 @@ static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) **/ static void qla4xxx_timer(struct timer_list *t) { - struct scsi_qla_host *ha = from_timer(ha, t, timer); + struct scsi_qla_host *ha = timer_container_of(ha, t, timer); int start_dpc = 0; uint16_t w; @@ -4645,7 +4649,7 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) cmd = scsi_host_find_tag(ha->host, index); /* * We cannot just check if the index is valid, - * becase if we are run from the scsi eh, then + * because if we are run from the scsi eh, then * the scsi/block layer is going to prevent * the tag from being released. */ @@ -4950,7 +4954,7 @@ recover_ha_init_adapter: /* Upon successful firmware/chip reset, re-initialize the adapter */ if (status == QLA_SUCCESS) { /* For ISP-4xxx, force function 1 to always initialize - * before function 3 to prevent both funcions from + * before function 3 to prevent both functions from * stepping on top of the other */ if (is_qla40XX(ha) && (ha->mac_index == 3)) ssleep(6); @@ -6604,6 +6608,8 @@ static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0); vfree(dst_addr); + if (IS_ERR(ep)) + return NULL; return ep; } @@ -6910,7 +6916,7 @@ static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry = NULL; /* Create session object, with INVALID_ENTRY, - * the targer_id would get set when we issue the login + * the target_id would get set when we issue the login */ cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, cmds_max, sizeof(struct ddb_entry), @@ -8815,7 +8821,7 @@ skip_retry_init: } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1, + ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM | WQ_PERCPU, 1, ha->host_no); if (!ha->task_wq) { ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); @@ -9792,11 +9798,6 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev) */ pci_restore_state(pdev); - /* pci_restore_state() clears the saved_state flag of the device - * save restored state which resets saved_state flag - */ - pci_save_state(pdev); - /* Initialize device or resume if in suspended state */ rc = pci_enable_device(pdev); if (rc) { diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 3e065d5fc80c..d36293bc2717 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -464,7 +464,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) * Queued command */ -static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); @@ -492,7 +492,7 @@ DEF_SCSI_QCMD(qlogicfas408_queuecommand) * Return bios parameters */ -int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev, +int qlogicfas408_biosparam(struct scsi_device *disk, struct gendisk *unused, sector_t capacity, int ip[]) { /* This should mimic the DOS Qlogic driver's behavior exactly */ diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index a971db11d293..a589c7656f57 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -104,9 +104,10 @@ struct qlogicfas408_priv { #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); -int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd); +enum scsi_qc_status qlogicfas408_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); int qlogicfas408_biosparam(struct scsi_device * disk, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int ip[]); int qlogicfas408_abort(struct scsi_cmnd * cmd); extern int qlogicfas408_host_reset(struct scsi_cmnd *cmd); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c9984ef57f26..ea0a2b5a0a42 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1015,7 +1015,7 @@ static int qlogicpti_sdev_configure(struct scsi_device *sdev, * * "This code must fly." -davem */ -static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) +static enum scsi_qc_status qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct Scsi_Host *host = Cmnd->device->host; diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 95a86e0dfd77..94f76e358634 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -81,7 +81,7 @@ static int raid_setup(struct transport_container *tc, struct device *dev, BUG_ON(dev_get_drvdata(cdev)); - rd = kzalloc(sizeof(*rd), GFP_KERNEL); + rd = kzalloc_obj(*rd); if (!rd) return -ENOMEM; @@ -212,8 +212,7 @@ raid_attr_ro_state_fn(state); struct raid_template * raid_class_attach(struct raid_function_template *ft) { - struct raid_internal *i = kzalloc(sizeof(struct raid_internal), - GFP_KERNEL); + struct raid_internal *i = kzalloc_obj(struct raid_internal); int count = 0; if (unlikely(!i)) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a77e0499b738..76cdad063f7b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -216,6 +216,9 @@ int scsi_device_max_queue_depth(struct scsi_device *sdev) */ int scsi_change_queue_depth(struct scsi_device *sdev, int depth) { + if (!sdev->budget_map.map) + return -EINVAL; + depth = min_t(int, depth, scsi_device_max_queue_depth(sdev)); if (depth > 0) { @@ -242,9 +245,11 @@ EXPORT_SYMBOL(scsi_change_queue_depth); * specific SCSI device to determine if and when there is a * need to adjust the queue depth on the device. * - * Returns: 0 - No change needed, >0 - Adjust queue depth to this new depth, - * -1 - Drop back to untagged operation using host->cmd_per_lun - * as the untagged command depth + * Returns: + * * 0 - No change needed + * * >0 - Adjust queue depth to this new depth, + * * -1 - Drop back to untagged operation using host->cmd_per_lun as the + * untagged command depth * * Lock Status: None held on entry * @@ -253,6 +258,8 @@ EXPORT_SYMBOL(scsi_change_queue_depth); */ int scsi_track_queue_full(struct scsi_device *sdev, int depth) { + if (!sdev->budget_map.map) + return 0; /* * Don't let QUEUE_FULLs on the same @@ -510,22 +517,34 @@ void scsi_attach_vpd(struct scsi_device *sdev) return; for (i = 4; i < vpd_buf->len; i++) { - if (vpd_buf->data[i] == 0x0) + switch (vpd_buf->data[i]) { + case 0x0: scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0); - if (vpd_buf->data[i] == 0x80) + break; + case 0x80: scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80); - if (vpd_buf->data[i] == 0x83) + break; + case 0x83: scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83); - if (vpd_buf->data[i] == 0x89) + break; + case 0x89: scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89); - if (vpd_buf->data[i] == 0xb0) + break; + case 0xb0: scsi_update_vpd_page(sdev, 0xb0, &sdev->vpd_pgb0); - if (vpd_buf->data[i] == 0xb1) + break; + case 0xb1: scsi_update_vpd_page(sdev, 0xb1, &sdev->vpd_pgb1); - if (vpd_buf->data[i] == 0xb2) + break; + case 0xb2: scsi_update_vpd_page(sdev, 0xb2, &sdev->vpd_pgb2); - if (vpd_buf->data[i] == 0xb7) + break; + case 0xb7: scsi_update_vpd_page(sdev, 0xb7, &sdev->vpd_pgb7); + break; + default: + break; + } } kfree(vpd_buf); } @@ -695,26 +714,18 @@ void scsi_cdl_check(struct scsi_device *sdev) */ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) { - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - struct scsi_vpd *vpd; - bool is_ata = false; char buf[64]; int ret; if (!sdev->cdl_supported) return -EOPNOTSUPP; - rcu_read_lock(); - vpd = rcu_dereference(sdev->vpd_pg89); - if (vpd) - is_ata = true; - rcu_read_unlock(); - /* * For ATA devices, CDL needs to be enabled with a SET FEATURES command. */ - if (is_ata) { + if (sdev->is_ata) { + struct scsi_mode_data data; + struct scsi_sense_hdr sshdr; char *buf_data; int len; @@ -723,16 +734,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) if (ret) return -EINVAL; - /* Enable CDL using the ATA feature page */ + /* Enable or disable CDL using the ATA feature page */ len = min_t(size_t, sizeof(buf), data.length - data.header_length - data.block_descriptor_length); buf_data = buf + data.header_length + data.block_descriptor_length; - if (enable) - buf_data[4] = 0x02; - else - buf_data[4] = 0; + + /* + * If we want to enable CDL and CDL is already enabled on the + * device, do nothing. This avoids needlessly resetting the CDL + * statistics on the device as that is implied by the CDL enable + * action. Similar to this, there is no need to do anything if + * we want to disable CDL and CDL is already disabled. + */ + if (enable) { + if ((buf_data[4] & 0x03) == 0x02) + goto out; + buf_data[4] &= ~0x03; + buf_data[4] |= 0x02; + } else { + if ((buf_data[4] & 0x03) == 0x00) + goto out; + buf_data[4] &= ~0x03; + } ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3, &data, &sshdr); @@ -744,6 +769,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) } } +out: sdev->cdl_enable = enable; return 0; @@ -805,8 +831,11 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, spin_lock_irqsave(shost->host_lock, flags); while (list->next != &shost->__devices) { next = list_entry(list->next, struct scsi_device, siblings); - /* skip devices that we can't get a reference to */ - if (!scsi_device_get(next)) + /* + * Skip pseudo devices and also devices we can't get a + * reference to. + */ + if (!scsi_device_is_pseudo_dev(next) && !scsi_device_get(next)) break; next = NULL; list = list->next; diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c index a9a9ec086a7e..e80dec53174e 100644 --- a/drivers/scsi/scsi_bsg.c +++ b/drivers/scsi/scsi_bsg.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/bsg.h> +#include <linux/io_uring/cmd.h> #include <scsi/scsi.h> #include <scsi/scsi_ioctl.h> #include <scsi/scsi_cmnd.h> @@ -9,6 +10,178 @@ #define uptr64(val) ((void __user *)(uintptr_t)(val)) +/* + * Per-command BSG SCSI PDU stored in io_uring_cmd.pdu[32]. + * Holds temporary state between submission, completion and task_work. + */ +struct scsi_bsg_uring_cmd_pdu { + struct bio *bio; /* mapped user buffer, unmap in task work */ + struct request *req; /* block request, freed in task work */ + u64 response_addr; /* user space response buffer address */ +}; +static_assert(sizeof(struct scsi_bsg_uring_cmd_pdu) <= sizeof_field(struct io_uring_cmd, pdu)); + +static inline struct scsi_bsg_uring_cmd_pdu *scsi_bsg_uring_cmd_pdu( + struct io_uring_cmd *ioucmd) +{ + return io_uring_cmd_to_pdu(ioucmd, struct scsi_bsg_uring_cmd_pdu); +} + +/* Task work: build res2 (layout in uapi/linux/bsg.h) and copy sense to user. */ +static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw) +{ + struct io_uring_cmd *ioucmd = io_uring_cmd_from_tw(tw_req); + struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd); + struct request *rq = pdu->req; + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + u64 res2; + int ret = 0; + u8 driver_status = 0; + u8 sense_len_wr = 0; + + if (pdu->bio) + blk_rq_unmap_user(pdu->bio); + + if (scsi_status_is_check_condition(scmd->result)) { + driver_status = DRIVER_SENSE; + if (pdu->response_addr) + sense_len_wr = min_t(u8, scmd->sense_len, + SCSI_SENSE_BUFFERSIZE); + } + + if (sense_len_wr) { + if (copy_to_user(uptr64(pdu->response_addr), scmd->sense_buffer, + sense_len_wr)) + ret = -EFAULT; + } + + res2 = bsg_scsi_res2_build(status_byte(scmd->result), driver_status, + host_byte(scmd->result), sense_len_wr, + scmd->resid_len); + + blk_mq_free_request(rq); + io_uring_cmd_done32(ioucmd, ret, res2, + IO_URING_CMD_TASK_WORK_ISSUE_FLAGS); +} + +static enum rq_end_io_ret scsi_bsg_uring_cmd_done(struct request *req, + blk_status_t status, + const struct io_comp_batch *iocb) +{ + struct io_uring_cmd *ioucmd = req->end_io_data; + + io_uring_cmd_do_in_task_lazy(ioucmd, scsi_bsg_uring_task_cb); + return RQ_END_IO_NONE; +} + +static int scsi_bsg_map_user_buffer(struct request *req, + struct io_uring_cmd *ioucmd, + unsigned int issue_flags, gfp_t gfp_mask) +{ + const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd); + bool is_write = cmd->dout_xfer_len > 0; + u64 buf_addr = is_write ? cmd->dout_xferp : cmd->din_xferp; + unsigned long buf_len = is_write ? cmd->dout_xfer_len : cmd->din_xfer_len; + struct iov_iter iter; + int ret; + + if (ioucmd->flags & IORING_URING_CMD_FIXED) { + ret = io_uring_cmd_import_fixed(buf_addr, buf_len, + is_write ? WRITE : READ, + &iter, ioucmd, issue_flags); + if (ret < 0) + return ret; + ret = blk_rq_map_user_iov(req->q, req, NULL, &iter, gfp_mask); + } else { + ret = blk_rq_map_user(req->q, req, NULL, uptr64(buf_addr), + buf_len, gfp_mask); + } + + return ret; +} + +static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *ioucmd, + unsigned int issue_flags, bool open_for_write) +{ + struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd); + const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd); + struct scsi_cmnd *scmd; + struct request *req; + blk_mq_req_flags_t blk_flags = 0; + gfp_t gfp_mask = GFP_KERNEL; + int ret; + + if (cmd->protocol != BSG_PROTOCOL_SCSI || + cmd->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD) + return -EINVAL; + + if (!cmd->request || cmd->request_len == 0) + return -EINVAL; + + if (cmd->dout_xfer_len && cmd->din_xfer_len) { + pr_warn_once("BIDI support in bsg has been removed.\n"); + return -EOPNOTSUPP; + } + + if (cmd->dout_iovec_count > 0 || cmd->din_iovec_count > 0) + return -EOPNOTSUPP; + + if (issue_flags & IO_URING_F_NONBLOCK) { + blk_flags = BLK_MQ_REQ_NOWAIT; + gfp_mask = GFP_NOWAIT; + } + + req = scsi_alloc_request(q, cmd->dout_xfer_len ? + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, blk_flags); + if (IS_ERR(req)) + return PTR_ERR(req); + + scmd = blk_mq_rq_to_pdu(req); + if (cmd->request_len > sizeof(scmd->cmnd)) { + ret = -EINVAL; + goto out_free_req; + } + scmd->cmd_len = cmd->request_len; + scmd->allowed = SG_DEFAULT_RETRIES; + + if (copy_from_user(scmd->cmnd, uptr64(cmd->request), cmd->request_len)) { + ret = -EFAULT; + goto out_free_req; + } + + if (!scsi_cmd_allowed(scmd->cmnd, open_for_write)) { + ret = -EPERM; + goto out_free_req; + } + + pdu->response_addr = cmd->response; + scmd->sense_len = cmd->max_response_len ? + min(cmd->max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE; + + if (cmd->dout_xfer_len || cmd->din_xfer_len) { + ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, gfp_mask); + if (ret) + goto out_free_req; + pdu->bio = req->bio; + } else { + pdu->bio = NULL; + } + + req->timeout = cmd->timeout_ms ? + msecs_to_jiffies(cmd->timeout_ms) : BLK_DEFAULT_SG_TIMEOUT; + + req->end_io = scsi_bsg_uring_cmd_done; + req->end_io_data = ioucmd; + pdu->req = req; + + blk_execute_rq_nowait(req, false); + return -EIOCBQUEUED; + +out_free_req: + blk_mq_free_request(req); + return ret; +} + static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, bool open_for_write, unsigned int timeout) { @@ -99,5 +272,6 @@ out_put_request: struct bsg_device *scsi_bsg_register_queue(struct scsi_device *sdev) { return bsg_register_queue(sdev->request_queue, &sdev->sdev_gendev, - dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn); + dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn, + scsi_bsg_uring_cmd); } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 5ceaa4665e5d..1515495fd9ea 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -71,6 +71,10 @@ static const char *sdebug_version_date = "20210520"; #define NO_ADDITIONAL_SENSE 0x0 #define OVERLAP_ATOMIC_COMMAND_ASC 0x0 #define OVERLAP_ATOMIC_COMMAND_ASCQ 0x23 +#define FILEMARK_DETECTED_ASCQ 0x1 +#define EOP_EOM_DETECTED_ASCQ 0x2 +#define BEGINNING_OF_P_M_DETECTED_ASCQ 0x4 +#define EOD_DETECTED_ASCQ 0x5 #define LOGICAL_UNIT_NOT_READY 0x4 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 #define UNRECOVERED_READ_ERR 0x11 @@ -80,8 +84,10 @@ static const char *sdebug_version_date = "20210520"; #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define WRITE_PROTECTED 0x27 +#define UA_READY_ASC 0x28 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a +#define TOO_MANY_IN_PARTITION_ASC 0x3b #define TARGET_CHANGED_ASC 0x3f #define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 @@ -156,7 +162,7 @@ static const char *sdebug_version_date = "20210520"; #define DEF_VPD_USE_HOSTNO 1 #define DEF_WRITESAME_LENGTH 0xFFFF #define DEF_ATOMIC_WR 0 -#define DEF_ATOMIC_WR_MAX_LENGTH 8192 +#define DEF_ATOMIC_WR_MAX_LENGTH 128 #define DEF_ATOMIC_WR_ALIGN 2 #define DEF_ATOMIC_WR_GRAN 2 #define DEF_ATOMIC_WR_MAX_LENGTH_BNDRY (DEF_ATOMIC_WR_MAX_LENGTH) @@ -173,6 +179,37 @@ static const char *sdebug_version_date = "20210520"; #define DEF_ZBC_MAX_OPEN_ZONES 8 #define DEF_ZBC_NR_CONV_ZONES 1 +/* Default parameters for tape drives */ +#define TAPE_DEF_DENSITY 0x0 +#define TAPE_BAD_DENSITY 0x65 +#define TAPE_DEF_BLKSIZE 0 +#define TAPE_MIN_BLKSIZE 512 +#define TAPE_MAX_BLKSIZE 1048576 +#define TAPE_EW 20 +#define TAPE_MAX_PARTITIONS 2 +#define TAPE_UNITS 10000 +#define TAPE_PARTITION_1_UNITS 1000 + +/* The tape block data definitions */ +#define TAPE_BLOCK_FM_FLAG ((u32)0x1 << 30) +#define TAPE_BLOCK_EOD_FLAG ((u32)0x2 << 30) +#define TAPE_BLOCK_MARK_MASK ((u32)0x3 << 30) +#define TAPE_BLOCK_SIZE_MASK (~TAPE_BLOCK_MARK_MASK) +#define TAPE_BLOCK_MARK(a) (a & TAPE_BLOCK_MARK_MASK) +#define TAPE_BLOCK_SIZE(a) (a & TAPE_BLOCK_SIZE_MASK) +#define IS_TAPE_BLOCK_FM(a) ((a & TAPE_BLOCK_FM_FLAG) != 0) +#define IS_TAPE_BLOCK_EOD(a) ((a & TAPE_BLOCK_EOD_FLAG) != 0) + +struct tape_block { + u32 fl_size; + unsigned char data[4]; +}; + +/* Flags for sense data */ +#define SENSE_FLAG_FILEMARK 0x80 +#define SENSE_FLAG_EOM 0x40 +#define SENSE_FLAG_ILI 0x20 + #define SDEBUG_LUN_0_VAL 0 /* bit mask values for sdebug_opts */ @@ -193,6 +230,7 @@ static const char *sdebug_version_date = "20210520"; #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 #define SDEBUG_OPT_HOST_BUSY 0x8000 #define SDEBUG_OPT_CMD_ABORT 0x10000 +#define SDEBUG_OPT_UNALIGNED_WRITE 0x20000 #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ SDEBUG_OPT_RESET_NOISE) #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ @@ -200,7 +238,8 @@ static const char *sdebug_version_date = "20210520"; SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ SDEBUG_OPT_SHORT_TRANSFER | \ SDEBUG_OPT_HOST_BUSY | \ - SDEBUG_OPT_CMD_ABORT) + SDEBUG_OPT_CMD_ABORT | \ + SDEBUG_OPT_UNALIGNED_WRITE) #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \ SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR) @@ -216,7 +255,8 @@ static const char *sdebug_version_date = "20210520"; #define SDEBUG_UA_LUNS_CHANGED 5 #define SDEBUG_UA_MICROCODE_CHANGED 6 /* simulate firmware change */ #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7 -#define SDEBUG_NUM_UAS 8 +#define SDEBUG_UA_NOT_READY_TO_READY 8 +#define SDEBUG_NUM_UAS 9 /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this * sector on read commands: */ @@ -256,17 +296,20 @@ static const char *sdebug_version_date = "20210520"; #define FF_SA (F_SA_HIGH | F_SA_LOW) #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) +/* Device selection bit mask */ +#define DS_ALL 0xffffffff +#define DS_SBC (1 << TYPE_DISK) +#define DS_SSC (1 << TYPE_TAPE) +#define DS_ZBC (1 << TYPE_ZBC) + +#define DS_NO_SSC (DS_ALL & ~DS_SSC) + #define SDEBUG_MAX_PARTS 4 #define SDEBUG_MAX_CMD_LEN 32 #define SDEB_XA_NOT_IN_USE XA_MARK_1 -static struct kmem_cache *queued_cmd_cache; - -#define TO_QUEUED_CMD(scmd) ((void *)(scmd)->host_scribble) -#define ASSIGN_QUEUED_CMD(scmnd, qc) { (scmnd)->host_scribble = (void *) qc; } - /* Zone types (zbcr05 table 25) */ enum sdebug_z_type { ZBC_ZTYPE_CNV = 0x1, @@ -363,6 +406,19 @@ struct sdebug_dev_info { ktime_t create_ts; /* time since bootup that this device was created */ struct sdeb_zone_state *zstate; + /* For tapes */ + unsigned int tape_blksize; + unsigned int tape_density; + unsigned char tape_partition; + unsigned char tape_nbr_partitions; + unsigned char tape_pending_nbr_partitions; + unsigned int tape_pending_part_0_size; + unsigned int tape_pending_part_1_size; + unsigned char tape_dce; + unsigned int tape_location[TAPE_MAX_PARTITIONS]; + unsigned int tape_eop[TAPE_MAX_PARTITIONS]; + struct tape_block *tape_blocks[TAPE_MAX_PARTITIONS]; + struct dentry *debugfs_entry; struct spinlock list_lock; struct list_head inject_err_list; @@ -409,24 +465,9 @@ struct sdebug_defer { enum sdeb_defer_type defer_t; }; -struct sdebug_device_access_info { - bool atomic_write; - u64 lba; - u32 num; - struct scsi_cmnd *self; -}; - -struct sdebug_queued_cmd { - /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue - * instance indicates this slot is in use. - */ - struct sdebug_defer sd_dp; - struct scsi_cmnd *scmd; - struct sdebug_device_access_info *i; -}; - struct sdebug_scsi_cmd { spinlock_t lock; + struct sdebug_defer sd_dp; }; static atomic_t sdebug_cmnd_count; /* number of incoming commands */ @@ -441,6 +482,7 @@ struct opcode_info_t { /* for terminating element */ u8 opcode; /* if num_attached > 0, preferred */ u16 sa; /* service action */ + u32 devsel; /* device type mask for this definition */ u32 flags; /* OR-ed set of SDEB_F_* */ int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); const struct opcode_info_t *arrp; /* num_attached elements or NULL */ @@ -483,22 +525,28 @@ enum sdeb_opcode_index { SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ SDEB_I_ATOMIC_WRITE_16 = 32, - SDEB_I_LAST_ELEM_P1 = 33, /* keep this last (previous + 1) */ + SDEB_I_READ_BLOCK_LIMITS = 33, + SDEB_I_LOCATE = 34, + SDEB_I_WRITE_FILEMARKS = 35, + SDEB_I_SPACE = 36, + SDEB_I_FORMAT_MEDIUM = 37, + SDEB_I_ERASE = 38, + SDEB_I_LAST_ELEM_P1 = 39, /* keep this last (previous + 1) */ }; static const unsigned char opcode_ind_arr[256] = { /* 0x0; 0x0->0x1f: 6 byte cdbs */ SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, - 0, 0, 0, 0, + SDEB_I_FORMAT_MEDIUM, SDEB_I_READ_BLOCK_LIMITS, 0, 0, SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, - 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, - SDEB_I_RELEASE, - 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, + SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0, + SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE, + 0, SDEB_I_ERASE, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, SDEB_I_ALLOW_REMOVAL, 0, /* 0x20; 0x20->0x3f: 10 byte cdbs */ 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, - SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, + SDEB_I_READ, 0, SDEB_I_WRITE, SDEB_I_LOCATE, 0, 0, 0, SDEB_I_VERIFY, 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, /* 0x40; 0x40->0x5f: 10 byte cdbs */ @@ -549,7 +597,9 @@ static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_read_tape(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_write_tape(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); @@ -573,6 +623,14 @@ static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_read_blklimits(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_read_position(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_format_medium(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_erase(struct scsi_cmnd *, struct sdebug_dev_info *); static int sdebug_do_add_host(bool mk_new_store); static int sdebug_add_host_helper(int per_host_idx); @@ -581,121 +639,127 @@ static int sdebug_add_store(void); static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); static void sdebug_erase_all_stores(bool apart_from_first); -static void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp); - /* * The following are overflow arrays for cdbs that "hit" the same index in * the opcode_info_arr array. The most time sensitive (or commonly used) cdb * should be placed in opcode_info_arr[], the others should be placed here. */ static const struct opcode_info_t msense_iarr[] = { - {0, 0x1a, 0, F_D_IN, NULL, NULL, + {0, 0x1a, 0, DS_ALL, F_D_IN, NULL, NULL, {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; static const struct opcode_info_t mselect_iarr[] = { - {0, 0x15, 0, F_D_OUT, NULL, NULL, + {0, 0x15, 0, DS_ALL, F_D_OUT, NULL, NULL, {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; static const struct opcode_info_t read_iarr[] = { - {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ + {0, 0x28, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ + {0, 0x8, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) disk */ {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ + {0, 0x8, 0, DS_SSC, F_D_IN | FF_MEDIA_IO, resp_read_tape, NULL, /* READ(6) tape */ + {6, 0x03, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0xa8, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7, 0, 0, 0, 0} }, }; static const struct opcode_info_t write_iarr[] = { - {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ + {0, 0x2a, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ + {0, 0xa, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) disk */ NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ + {0, 0xa, 0, DS_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_tape, /* WRITE(6) tape */ + NULL, {6, 0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0} }, + {0, 0xaa, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7, 0, 0, 0, 0} }, }; static const struct opcode_info_t verify_iarr[] = { - {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ + {0, 0x2f, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, }; static const struct opcode_info_t sa_in_16_iarr[] = { - {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, + {0, 0x9e, 0x12, DS_NO_SSC, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ - {0, 0x9e, 0x16, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, + {0, 0x9e, 0x16, DS_NO_SSC, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0} }, /* GET STREAM STATUS */ }; static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ - {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, + {0, 0x7f, 0xb, DS_NO_SSC, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ - {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, + {0, 0x7f, 0x11, DS_NO_SSC, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ }; static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ - {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, + {0, 0xa3, 0xc, DS_ALL, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ - {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, + {0, 0xa3, 0xd, DS_ALL, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ }; static const struct opcode_info_t write_same_iarr[] = { - {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, + {0, 0x93, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ }; static const struct opcode_info_t reserve_iarr[] = { - {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ + {0, 0x16, 0, DS_ALL, F_D_OUT, NULL, NULL, /* RESERVE(6) */ {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; static const struct opcode_info_t release_iarr[] = { - {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ + {0, 0x17, 0, DS_ALL, F_D_OUT, NULL, NULL, /* RELEASE(6) */ {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; static const struct opcode_info_t sync_cache_iarr[] = { - {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, + {0, 0x91, 0, DS_NO_SSC, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ }; static const struct opcode_info_t pre_fetch_iarr[] = { - {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, + {0, 0x90, 0, DS_NO_SSC, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ + {0, 0x34, 0, DS_SSC, F_SYNC_DELAY | FF_MEDIA_IO, resp_read_position, NULL, + {10, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc7, 0, 0, + 0, 0, 0, 0} }, /* READ POSITION (10) */ }; static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ - {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, + {0, 0x94, 0x1, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ - {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, + {0, 0x94, 0x2, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ - {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, + {0, 0x94, 0x4, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ }; static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ - {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, + {0, 0x95, 0x6, DS_NO_SSC, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ }; @@ -706,117 +770,132 @@ static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ * REPORT SUPPORTED OPERATION CODES. */ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { /* 0 */ - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ + {0, 0, 0, DS_ALL, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ + {0, 0x12, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, + {0, 0xa0, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_report_luns, NULL, {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, /* REPORT LUNS */ - {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, + {0, 0x3, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_requests, NULL, {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ + {0, 0x0, 0, DS_ALL, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, /* 5 */ - {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ + {ARRAY_SIZE(msense_iarr), 0x5a, 0, DS_ALL, F_D_IN, /* MODE SENSE(10) */ resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ + {ARRAY_SIZE(mselect_iarr), 0x55, 0, DS_ALL, F_D_OUT, /* MODE SELECT(10) */ resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ + {0, 0x4d, 0, DS_NO_SSC, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ + {0, 0x25, 0, DS_NO_SSC, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ + {ARRAY_SIZE(read_iarr), 0x88, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, /* READ(16) */ resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* 10 */ - {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, + {ARRAY_SIZE(write_iarr), 0x8a, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, write_iarr, /* WRITE(16) */ {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, - {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ + {0, 0x1b, 0, DS_ALL, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, + {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, DS_NO_SSC, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, - {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, + {0, 0x9f, 0x12, DS_NO_SSC, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ - {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, + {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, DS_ALL, F_SA_LOW | F_D_IN, resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, /* 15 */ - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ + {0, 0, 0, DS_ALL, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(verify_iarr), 0x8f, 0, + {ARRAY_SIZE(verify_iarr), 0x8f, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, - {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, + {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, DS_NO_SSC, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 0xff, 0xff} }, - {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, + {ARRAY_SIZE(reserve_iarr), 0x56, 0, DS_ALL, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) <no response function> */ {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, + {ARRAY_SIZE(release_iarr), 0x57, 0, DS_ALL, F_D_OUT, NULL, release_iarr, /* RELEASE(10) <no response function> */ {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* 20 */ - {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ + {0, 0x1e, 0, DS_ALL, 0, NULL, NULL, /* ALLOW REMOVAL */ {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ + {0, 0x1, 0, DS_SSC, 0, resp_rewind, NULL, {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ + {0, 0, 0, DS_NO_SSC, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ + {0, 0x1d, 0, DS_ALL, F_D_OUT, NULL, NULL, /* SEND DIAGNOSTIC */ {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ + {0, 0x42, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* 25 */ - {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, + {0, 0x3b, 0, DS_NO_SSC, F_D_OUT_MAYBE, resp_write_buffer, NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* WRITE_BUFFER */ - {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, + {ARRAY_SIZE(write_same_iarr), 0x41, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, + {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, DS_NO_SSC, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, sync_cache_iarr, {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ - {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, + {0, 0x89, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ - {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, + {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, DS_NO_SSC, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, pre_fetch_iarr, {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* PRE-FETCH (10) */ + /* READ POSITION (10) */ /* 30 */ - {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, + {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, - {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, + {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, -/* 31 */ - {0, 0x0, 0x0, F_D_OUT | FF_MEDIA_IO, +/* 32 */ + {0, 0x9c, 0x0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_atomic_write, NULL, /* ATOMIC WRITE 16 */ {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }, + {0, 0x05, 0, DS_SSC, F_D_IN, resp_read_blklimits, NULL, /* READ BLOCK LIMITS (6) */ + {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x2b, 0, DS_SSC, F_D_UNKN, resp_locate, NULL, /* LOCATE (10) */ + {10, 0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0, + 0, 0, 0, 0} }, + {0, 0x10, 0, DS_SSC, F_D_IN, resp_write_filemarks, NULL, /* WRITE FILEMARKS (6) */ + {6, 0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x11, 0, DS_SSC, F_D_IN, resp_space, NULL, /* SPACE (6) */ + {6, 0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x4, 0, DS_SSC, 0, resp_format_medium, NULL, /* FORMAT MEDIUM (6) */ + {6, 0x3, 0x7, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x19, 0, DS_SSC, F_D_IN, resp_erase, NULL, /* ERASE (6) */ + {6, 0x03, 0x33, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +/* 39 */ /* sentinel */ - {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ + {0xff, 0, 0, 0, 0, NULL, NULL, /* terminating element */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; @@ -962,6 +1041,19 @@ static const int condition_met_result = SAM_STAT_CONDITION_MET; static struct dentry *sdebug_debugfs_root; static ASYNC_DOMAIN_EXCLUSIVE(sdebug_async_domain); +static u32 sdebug_get_devsel(struct scsi_device *sdp) +{ + unsigned char devtype = sdp->type; + u32 devsel; + + if (devtype < 32) + devsel = (1 << devtype); + else + devsel = DS_ALL; + + return devsel; +} + static void sdebug_err_free(struct rcu_head *head) { struct sdebug_err_inject *inject = @@ -1065,14 +1157,9 @@ static ssize_t sdebug_error_write(struct file *file, const char __user *ubuf, struct sdebug_err_inject *inject; struct scsi_device *sdev = (struct scsi_device *)file->f_inode->i_private; - buf = kzalloc(count + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, ubuf, count)) { - kfree(buf); - return -EFAULT; - } + buf = memdup_user_nul(ubuf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); if (buf[0] == '-') return sdebug_err_remove(sdev, buf, count); @@ -1082,7 +1169,7 @@ static ssize_t sdebug_error_write(struct file *file, const char __user *ubuf, return -EINVAL; } - inject = kzalloc(sizeof(struct sdebug_err_inject), GFP_KERNEL); + inject = kzalloc_obj(struct sdebug_err_inject); if (!inject) { kfree(buf); return -ENOMEM; @@ -1179,7 +1266,7 @@ static int sdebug_target_alloc(struct scsi_target *starget) { struct sdebug_target_info *targetip; - targetip = kzalloc(sizeof(struct sdebug_target_info), GFP_KERNEL); + targetip = kzalloc_obj(struct sdebug_target_info); if (!targetip) return -ENOMEM; @@ -1284,8 +1371,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, sbuff = scp->sense_buffer; if (!sbuff) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; @@ -1317,8 +1403,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) { if (!scp->sense_buffer) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -1331,6 +1416,29 @@ static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) my_name, key, asc, asq); } +/* Sense data that has information fields for tapes */ +static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq, + unsigned int information, unsigned char tape_flags) +{ + if (!scp->sense_buffer) { + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); + return; + } + memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + + scsi_build_sense(scp, /* sdebug_dsense */ 0, key, asc, asq); + /* only fixed format so far */ + + scp->sense_buffer[0] |= 0x80; /* valid */ + scp->sense_buffer[2] |= tape_flags; + put_unaligned_be32(information, &scp->sense_buffer[3]); + + if (sdebug_verbose) + sdev_printk(KERN_INFO, scp->device, + "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", + my_name, key, asc, asq); +} + static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) { mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); @@ -1341,15 +1449,12 @@ static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, { if (sdebug_verbose) { if (0x1261 == cmd) - sdev_printk(KERN_INFO, dev, - "%s: BLKFLSBUF [0x1261]\n", __func__); + sdev_printk(KERN_INFO, dev, "BLKFLSBUF [0x1261]\n"); else if (0x5331 == cmd) sdev_printk(KERN_INFO, dev, - "%s: CDROM_GET_CAPABILITY [0x5331]\n", - __func__); + "CDROM_GET_CAPABILITY [0x5331]\n"); else - sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", - __func__, cmd); + sdev_printk(KERN_INFO, dev, "cmd=0x%x\n", cmd); } return -EINVAL; /* return -ENOTTY; // correct return but upsets fdisk */ @@ -1493,6 +1598,12 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (sdebug_verbose) cp = "reported luns data has changed"; break; + case SDEBUG_UA_NOT_READY_TO_READY: + mk_sense_buffer(scp, UNIT_ATTENTION, UA_READY_ASC, + 0); + if (sdebug_verbose) + cp = "not ready to ready transition/media change"; + break; default: pr_warn("unexpected unit attention code=%d\n", k); if (sdebug_verbose) @@ -1547,8 +1658,8 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, arr, arr_len, skip); - pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", - __func__, off_dst, scsi_bufflen(scp), act_len, + pr_debug("off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", + off_dst, scsi_bufflen(scp), act_len, scsi_get_resid(scp)); n = scsi_bufflen(scp) - (off_dst + act_len); scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); @@ -1949,13 +2060,19 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) unsigned char *cmd = scp->cmnd; u32 alloc_len, n; int ret; - bool have_wlun, is_disk, is_zbc, is_disk_zbc; + bool have_wlun, is_disk, is_zbc, is_disk_zbc, is_tape; alloc_len = get_unaligned_be16(cmd + 3); arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); if (! arr) return DID_REQUEUE << 16; - is_disk = (sdebug_ptype == TYPE_DISK); + if (scp->device->type >= 32) { + is_disk = (sdebug_ptype == TYPE_DISK); + is_tape = (sdebug_ptype == TYPE_TAPE); + } else { + is_disk = (scp->device->type == TYPE_DISK); + is_tape = (scp->device->type == TYPE_TAPE); + } is_zbc = devip->zoned; is_disk_zbc = (is_disk || is_zbc); have_wlun = scsi_is_wlun(scp->device->lun); @@ -1964,7 +2081,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ else - pq_pdt = (sdebug_ptype & 0x1f); + pq_pdt = ((scp->device->type >= 32 ? + sdebug_ptype : scp->device->type) & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); @@ -2087,7 +2205,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (is_disk) { /* SBC-4 no version claimed */ put_unaligned_be16(0x600, arr + n); n += 2; - } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ + } else if (is_tape) { /* SSC-4 rev 3 */ put_unaligned_be16(0x525, arr + n); n += 2; } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ @@ -2196,6 +2314,14 @@ static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) changing = (stopped_state != want_stop); if (changing) atomic_xchg(&devip->stopped, want_stop); + if (scp->device->type == TYPE_TAPE && !want_stop) { + int i; + + set_bit(SDEBUG_UA_NOT_READY_TO_READY, devip->uas_bm); /* not legal! */ + for (i = 0; i < TAPE_MAX_PARTITIONS; i++) + devip->tape_location[i] = 0; + devip->tape_partition = 0; + } if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ return SDEG_RES_IMMED_MASK; else @@ -2363,11 +2489,12 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, u8 reporting_opts, req_opcode, sdeb_i, supp; u16 req_sa, u; u32 alloc_len, a_len; - int k, offset, len, errsts, count, bump, na; + int k, offset, len, errsts, bump, na; const struct opcode_info_t *oip; const struct opcode_info_t *r_oip; u8 *arr; u8 *cmd = scp->cmnd; + u32 devsel = sdebug_get_devsel(scp->device); rctd = !!(cmd[2] & 0x80); reporting_opts = cmd[2] & 0x7; @@ -2390,34 +2517,30 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, } switch (reporting_opts) { case 0: /* all commands */ - /* count number of commands */ - for (count = 0, oip = opcode_info_arr; - oip->num_attached != 0xff; ++oip) { - if (F_INV_OP & oip->flags) - continue; - count += (oip->num_attached + 1); - } bump = rctd ? 20 : 8; - put_unaligned_be32(count * bump, arr); for (offset = 4, oip = opcode_info_arr; oip->num_attached != 0xff && offset < a_len; ++oip) { if (F_INV_OP & oip->flags) continue; + if ((devsel & oip->devsel) != 0) { + arr[offset] = oip->opcode; + put_unaligned_be16(oip->sa, arr + offset + 2); + if (rctd) + arr[offset + 5] |= 0x2; + if (FF_SA & oip->flags) + arr[offset + 5] |= 0x1; + put_unaligned_be16(oip->len_mask[0], arr + offset + 6); + if (rctd) + put_unaligned_be16(0xa, arr + offset + 8); + offset += bump; + } na = oip->num_attached; - arr[offset] = oip->opcode; - put_unaligned_be16(oip->sa, arr + offset + 2); - if (rctd) - arr[offset + 5] |= 0x2; - if (FF_SA & oip->flags) - arr[offset + 5] |= 0x1; - put_unaligned_be16(oip->len_mask[0], arr + offset + 6); - if (rctd) - put_unaligned_be16(0xa, arr + offset + 8); r_oip = oip; for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { if (F_INV_OP & oip->flags) continue; - offset += bump; + if ((devsel & oip->devsel) == 0) + continue; arr[offset] = oip->opcode; put_unaligned_be16(oip->sa, arr + offset + 2); if (rctd) @@ -2425,14 +2548,15 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, if (FF_SA & oip->flags) arr[offset + 5] |= 0x1; put_unaligned_be16(oip->len_mask[0], - arr + offset + 6); + arr + offset + 6); if (rctd) put_unaligned_be16(0xa, arr + offset + 8); + offset += bump; } oip = r_oip; - offset += bump; } + put_unaligned_be32(offset - 4, arr); break; case 1: /* one command: opcode only */ case 2: /* one command: opcode plus service action */ @@ -2458,13 +2582,15 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, return check_condition_result; } if (0 == (FF_SA & oip->flags) && - req_opcode == oip->opcode) + (devsel & oip->devsel) != 0 && + req_opcode == oip->opcode) supp = 3; else if (0 == (FF_SA & oip->flags)) { na = oip->num_attached; for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { - if (req_opcode == oip->opcode) + if (req_opcode == oip->opcode && + (devsel & oip->devsel) != 0) break; } supp = (k >= na) ? 1 : 3; @@ -2472,7 +2598,8 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, na = oip->num_attached; for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { - if (req_sa == oip->sa) + if (req_sa == oip->sa && + (devsel & oip->devsel) != 0) break; } supp = (k >= na) ? 1 : 3; @@ -2538,8 +2665,10 @@ static int resp_rsup_tmfs(struct scsi_cmnd *scp, static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) { /* Read-Write Error Recovery page for mode_sense */ - unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, - 5, 0, 0xff, 0xff}; + static const unsigned char err_recov_pg[] = { + 0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, + 5, 0, 0xff, 0xff + }; memcpy(p, err_recov_pg, sizeof(err_recov_pg)); if (1 == pcontrol) @@ -2549,8 +2678,10 @@ static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) { /* Disconnect-Reconnect page for mode_sense */ - unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; + static const unsigned char disconnect_pg[] = { + 0x2, 0xe, 128, 128, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; memcpy(p, disconnect_pg, sizeof(disconnect_pg)); if (1 == pcontrol) @@ -2560,9 +2691,11 @@ static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) static int resp_format_pg(unsigned char *p, int pcontrol, int target) { /* Format device page for mode_sense */ - unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x40, 0, 0, 0}; + static const unsigned char format_pg[] = { + 0x3, 0x16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x40, 0, 0, 0 + }; memcpy(p, format_pg, sizeof(format_pg)); put_unaligned_be16(sdebug_sectors_per, p + 10); @@ -2580,10 +2713,14 @@ static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, static int resp_caching_pg(unsigned char *p, int pcontrol, int target) { /* Caching page for mode_sense */ - unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; + static const unsigned char ch_caching_pg[] = { + /* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + static const unsigned char d_caching_pg[] = { + 0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0 + }; if (SDEBUG_OPT_N_WCE & sdebug_opts) caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ @@ -2602,8 +2739,10 @@ static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) { /* Control mode page for mode_sense */ unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, - 0, 0, 0x2, 0x4b}; + static const unsigned char d_ctrl_m_pg[] = { + 0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b + }; if (sdebug_dsense) ctrl_m_pg[2] |= 0x4; @@ -2658,10 +2797,14 @@ static int resp_grouping_m_pg(unsigned char *p, int pcontrol, int target) static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ - unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; - unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; + static const unsigned char ch_iec_m_pg[] = { + /* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, + 0, 0, 0x0, 0x0 + }; + static const unsigned char d_iec_m_pg[] = { + 0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0 + }; memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) @@ -2673,8 +2816,9 @@ static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) { /* SAS SSP mode page - short format for mode_sense */ - unsigned char sas_sf_m_pg[] = {0x19, 0x6, - 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; + static const unsigned char sas_sf_m_pg[] = { + 0x19, 0x6, 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0 + }; memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); if (1 == pcontrol) @@ -2718,9 +2862,10 @@ static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) { /* SAS SSP shared protocol specific port mode subpage */ - unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; + static const unsigned char sas_sha_m_pg[] = { + 0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); if (1 == pcontrol) @@ -2728,6 +2873,78 @@ static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) return sizeof(sas_sha_m_pg); } +static unsigned char partition_pg[] = {0x11, 12, 1, 0, 0x24, 3, 9, 0, + 0xff, 0xff, 0x00, 0x00}; + +static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target) +{ /* Partition page for mode_sense (tape) */ + memcpy(p, partition_pg, sizeof(partition_pg)); + if (pcontrol == 1) + memset(p + 2, 0, sizeof(partition_pg) - 2); + return sizeof(partition_pg); +} + +static int process_medium_part_m_pg(struct sdebug_dev_info *devip, + unsigned char *new, int pg_len) +{ + int new_nbr, p0_size, p1_size; + + if ((new[4] & 0x80) != 0) { /* FDP */ + partition_pg[4] |= 0x80; + devip->tape_pending_nbr_partitions = TAPE_MAX_PARTITIONS; + devip->tape_pending_part_0_size = TAPE_UNITS - TAPE_PARTITION_1_UNITS; + devip->tape_pending_part_1_size = TAPE_PARTITION_1_UNITS; + } else { + new_nbr = new[3] + 1; + if (new_nbr > TAPE_MAX_PARTITIONS) + return 3; + if ((new[4] & 0x40) != 0) { /* SDP */ + p1_size = TAPE_PARTITION_1_UNITS; + p0_size = TAPE_UNITS - p1_size; + if (p0_size < 100) + return 4; + } else if ((new[4] & 0x20) != 0) { + if (new_nbr > 1) { + p0_size = get_unaligned_be16(new + 8); + p1_size = get_unaligned_be16(new + 10); + if (p1_size == 0xFFFF) + p1_size = TAPE_UNITS - p0_size; + else if (p0_size == 0xFFFF) + p0_size = TAPE_UNITS - p1_size; + if (p0_size < 100 || p1_size < 100) + return 8; + } else { + p0_size = TAPE_UNITS; + p1_size = 0; + } + } else + return 6; + devip->tape_pending_nbr_partitions = new_nbr; + devip->tape_pending_part_0_size = p0_size; + devip->tape_pending_part_1_size = p1_size; + partition_pg[3] = new_nbr; + devip->tape_pending_nbr_partitions = new_nbr; + } + + return 0; +} + +static int resp_compression_m_pg(unsigned char *p, int pcontrol, int target, + unsigned char dce) +{ /* Compression page for mode_sense (tape) */ + static const unsigned char compression_pg[] = { + 0x0f, 14, 0x40, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + }; + + memcpy(p, compression_pg, sizeof(compression_pg)); + if (dce) + p[2] |= 0x80; + if (pcontrol == 1) + memset(p + 2, 0, sizeof(compression_pg) - 2); + return sizeof(compression_pg); +} + /* PAGE_SIZE is more than necessary but provides room for future expansion. */ #define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE @@ -2740,11 +2957,11 @@ static int resp_mode_sense(struct scsi_cmnd *scp, int target_dev_id; int target = scp->device->id; unsigned char *ap; - unsigned char *arr __free(kfree); unsigned char *cmd = scp->cmnd; - bool dbd, llbaa, msense_6, is_disk, is_zbc; + bool dbd, llbaa, msense_6, is_disk, is_zbc, is_tape; + + unsigned char *arr __free(kfree) = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC); - arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC); if (!arr) return -ENOMEM; dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ @@ -2753,9 +2970,10 @@ static int resp_mode_sense(struct scsi_cmnd *scp, subpcode = cmd[3]; msense_6 = (MODE_SENSE == cmd[0]); llbaa = msense_6 ? false : !!(cmd[1] & 0x10); - is_disk = (sdebug_ptype == TYPE_DISK); + is_disk = (scp->device->type == TYPE_DISK); is_zbc = devip->zoned; - if ((is_disk || is_zbc) && !dbd) + is_tape = (scp->device->type == TYPE_TAPE); + if ((is_disk || is_zbc || is_tape) && !dbd) bd_len = llbaa ? 16 : 8; else bd_len = 0; @@ -2793,15 +3011,25 @@ static int resp_mode_sense(struct scsi_cmnd *scp, put_unaligned_be32(0xffffffff, ap + 0); else put_unaligned_be32(sdebug_capacity, ap + 0); - put_unaligned_be16(sdebug_sector_size, ap + 6); + if (is_tape) { + ap[0] = devip->tape_density; + put_unaligned_be16(devip->tape_blksize, ap + 6); + } else + put_unaligned_be16(sdebug_sector_size, ap + 6); offset += bd_len; ap = arr + offset; } else if (16 == bd_len) { + if (is_tape) { + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, 4); + return check_condition_result; + } put_unaligned_be64((u64)sdebug_capacity, ap + 0); put_unaligned_be32(sdebug_sector_size, ap + 12); offset += bd_len; ap = arr + offset; } + if (cmd[2] == 0) + goto only_bd; /* Only block descriptor requested */ /* * N.B. If len>0 before resp_*_pg() call, then form of that call should be: @@ -2857,6 +3085,18 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } offset += len; break; + case 0xf: /* Compression Mode Page (tape) */ + if (!is_tape) + goto bad_pcode; + len = resp_compression_m_pg(ap, pcontrol, target, devip->tape_dce); + offset += len; + break; + case 0x11: /* Partition Mode Page (tape) */ + if (!is_tape) + goto bad_pcode; + len = resp_partition_m_pg(ap, pcontrol, target); + offset += len; + break; case 0x19: /* if spc==1 then sas phy, control+discover */ if (subpcode > 0x2 && subpcode < 0xff) goto bad_subpcode; @@ -2902,6 +3142,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, default: goto bad_pcode; } +only_bd: if (msense_6) arr[0] = offset - 1; else @@ -2941,12 +3182,38 @@ static int resp_mode_select(struct scsi_cmnd *scp, return DID_ERROR << 16; else if (sdebug_verbose && (res < param_len)) sdev_printk(KERN_INFO, scp->device, - "%s: cdb indicated=%d, IO sent=%d bytes\n", - __func__, param_len, res); + "cdb indicated=%d, IO sent=%d bytes\n", + param_len, res); md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); - off = bd_len + (mselect6 ? 4 : 8); - if (md_len > 2 || off >= res) { + off = (mselect6 ? 4 : 8); + if (scp->device->type == TYPE_TAPE) { + int blksize; + + if (bd_len != 8) { + mk_sense_invalid_fld(scp, SDEB_IN_DATA, + mselect6 ? 3 : 6, -1); + return check_condition_result; + } + if (arr[off] == TAPE_BAD_DENSITY) { + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); + return check_condition_result; + } + blksize = get_unaligned_be16(arr + off + 6); + if (blksize != 0 && + (blksize < TAPE_MIN_BLKSIZE || + blksize > TAPE_MAX_BLKSIZE || + (blksize % 4) != 0)) { + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, -1); + return check_condition_result; + } + devip->tape_density = arr[off]; + devip->tape_blksize = blksize; + } + off += bd_len; + if (off >= res) + return 0; /* No page written, just descriptors */ + if (md_len > 2) { mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); return check_condition_result; } @@ -2984,6 +3251,25 @@ static int resp_mode_select(struct scsi_cmnd *scp, goto set_mode_changed_ua; } break; + case 0xf: /* Compression mode page */ + if (scp->device->type != TYPE_TAPE) + goto bad_pcode; + if ((arr[off + 2] & 0x40) != 0) { + devip->tape_dce = (arr[off + 2] & 0x80) != 0; + return 0; + } + break; + case 0x11: /* Medium Partition Mode Page (tape) */ + if (scp->device->type == TYPE_TAPE) { + int fld; + + fld = process_medium_part_m_pg(devip, &arr[off], pg_len); + if (fld == 0) + return 0; + mk_sense_invalid_fld(scp, SDEB_IN_DATA, fld, -1); + return check_condition_result; + } + break; case 0x1c: /* Informational Exceptions Mode page */ if (iec_m_pg[1] == arr[off + 1]) { memcpy(iec_m_pg + 2, arr + off + 2, @@ -2999,13 +3285,18 @@ static int resp_mode_select(struct scsi_cmnd *scp, set_mode_changed_ua: set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); return 0; + +bad_pcode: + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); + return check_condition_result; } static int resp_temp_l_pg(unsigned char *arr) { - unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, - 0x0, 0x1, 0x3, 0x2, 0x0, 65, - }; + static const unsigned char temp_l_pg[] = { + 0x0, 0x0, 0x3, 0x2, 0x0, 38, + 0x0, 0x1, 0x3, 0x2, 0x0, 65, + }; memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); return sizeof(temp_l_pg); @@ -3013,8 +3304,9 @@ static int resp_temp_l_pg(unsigned char *arr) static int resp_ie_l_pg(unsigned char *arr) { - unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, - }; + static const unsigned char ie_l_pg[] = { + 0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, + }; memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); if (iec_m_pg[2] & 0x4) { /* TEST bit set */ @@ -3026,11 +3318,12 @@ static int resp_ie_l_pg(unsigned char *arr) static int resp_env_rep_l_spg(unsigned char *arr) { - unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8, - 0x0, 40, 72, 0xff, 45, 18, 0, 0, - 0x1, 0x0, 0x23, 0x8, - 0x0, 55, 72, 35, 55, 45, 0, 0, - }; + static const unsigned char env_rep_l_spg[] = { + 0x0, 0x0, 0x23, 0x8, + 0x0, 40, 72, 0xff, 45, 18, 0, 0, + 0x1, 0x0, 0x23, 0x8, + 0x0, 55, 72, 35, 55, 45, 0, 0, + }; memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg)); return sizeof(env_rep_l_spg); @@ -3138,6 +3431,298 @@ static int resp_log_sense(struct scsi_cmnd *scp, min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); } +enum {SDEBUG_READ_BLOCK_LIMITS_ARR_SZ = 6}; +static int resp_read_blklimits(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + unsigned char arr[SDEBUG_READ_BLOCK_LIMITS_ARR_SZ]; + + arr[0] = 4; + put_unaligned_be24(TAPE_MAX_BLKSIZE, arr + 1); + put_unaligned_be16(TAPE_MIN_BLKSIZE, arr + 4); + return fill_from_dev_buffer(scp, arr, SDEBUG_READ_BLOCK_LIMITS_ARR_SZ); +} + +static int resp_locate(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + unsigned char *cmd = scp->cmnd; + unsigned int i, pos; + struct tape_block *blp; + int partition; + + if ((cmd[1] & 0x02) != 0) { + if (cmd[8] >= devip->tape_nbr_partitions) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1); + return check_condition_result; + } + devip->tape_partition = cmd[8]; + } + pos = get_unaligned_be32(cmd + 3); + partition = devip->tape_partition; + + for (i = 0, blp = devip->tape_blocks[partition]; + i < pos && i < devip->tape_eop[partition]; i++, blp++) + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) + break; + if (i < pos) { + devip->tape_location[partition] = i; + mk_sense_buffer(scp, BLANK_CHECK, 0x05, 0); + return check_condition_result; + } + devip->tape_location[partition] = pos; + + return 0; +} + +static int resp_write_filemarks(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + unsigned char *cmd = scp->cmnd; + unsigned int i, count, pos; + u32 data; + int partition = devip->tape_partition; + + if ((cmd[1] & 0xfe) != 0) { /* probably write setmarks, not in >= SCSI-3 */ + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); + return check_condition_result; + } + count = get_unaligned_be24(cmd + 2); + data = TAPE_BLOCK_FM_FLAG; + for (i = 0, pos = devip->tape_location[partition]; i < count; i++, pos++) { + if (pos >= devip->tape_eop[partition] - 1) { /* don't overwrite EOD */ + devip->tape_location[partition] = devip->tape_eop[partition] - 1; + mk_sense_info_tape(scp, VOLUME_OVERFLOW, NO_ADDITIONAL_SENSE, + EOP_EOM_DETECTED_ASCQ, count, SENSE_FLAG_EOM); + return check_condition_result; + } + (devip->tape_blocks[partition] + pos)->fl_size = data; + } + (devip->tape_blocks[partition] + pos)->fl_size = + TAPE_BLOCK_EOD_FLAG; + devip->tape_location[partition] = pos; + + return 0; +} + +static int resp_space(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + unsigned char *cmd = scp->cmnd, code; + int i = 0, pos, count; + struct tape_block *blp; + int partition = devip->tape_partition; + + count = get_unaligned_be24(cmd + 2); + if ((count & 0x800000) != 0) /* extend negative to 32-bit count */ + count |= 0xff000000; + code = cmd[1] & 0x0f; + + pos = devip->tape_location[partition]; + if (code == 0) { /* blocks */ + if (count < 0) { + count = (-count); + pos -= 1; + for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count; + i++) { + if (pos < 0) + goto is_bop; + else if (IS_TAPE_BLOCK_FM(blp->fl_size)) + goto is_fm; + if (i > 0) { + pos--; + blp--; + } + } + } else if (count > 0) { + for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count; + i++, pos++, blp++) { + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) + goto is_eod; + if (IS_TAPE_BLOCK_FM(blp->fl_size)) { + pos += 1; + goto is_fm; + } + if (pos >= devip->tape_eop[partition]) + goto is_eop; + } + } + } else if (code == 1) { /* filemarks */ + if (count < 0) { + count = (-count); + if (pos == 0) + goto is_bop; + else { + for (i = 0, blp = devip->tape_blocks[partition] + pos; + i < count && pos >= 0; i++, pos--, blp--) { + for (pos--, blp-- ; !IS_TAPE_BLOCK_FM(blp->fl_size) && + pos >= 0; pos--, blp--) + ; /* empty */ + if (pos < 0) + goto is_bop; + } + } + pos += 1; + } else if (count > 0) { + for (i = 0, blp = devip->tape_blocks[partition] + pos; + i < count; i++, pos++, blp++) { + for ( ; !IS_TAPE_BLOCK_FM(blp->fl_size) && + !IS_TAPE_BLOCK_EOD(blp->fl_size) && + pos < devip->tape_eop[partition]; + pos++, blp++) + ; /* empty */ + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) + goto is_eod; + if (pos >= devip->tape_eop[partition]) + goto is_eop; + } + } + } else if (code == 3) { /* EOD */ + for (blp = devip->tape_blocks[partition] + pos; + !IS_TAPE_BLOCK_EOD(blp->fl_size) && pos < devip->tape_eop[partition]; + pos++, blp++) + ; /* empty */ + if (pos >= devip->tape_eop[partition]) + goto is_eop; + } else { + /* sequential filemarks not supported */ + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1); + return check_condition_result; + } + devip->tape_location[partition] = pos; + return 0; + +is_fm: + devip->tape_location[partition] = pos; + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + FILEMARK_DETECTED_ASCQ, count - i, + SENSE_FLAG_FILEMARK); + return check_condition_result; + +is_eod: + devip->tape_location[partition] = pos; + mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE, + EOD_DETECTED_ASCQ, count - i, + 0); + return check_condition_result; + +is_bop: + devip->tape_location[partition] = 0; + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + BEGINNING_OF_P_M_DETECTED_ASCQ, count - i, + SENSE_FLAG_EOM); + devip->tape_location[partition] = 0; + return check_condition_result; + +is_eop: + devip->tape_location[partition] = devip->tape_eop[partition] - 1; + mk_sense_info_tape(scp, MEDIUM_ERROR, NO_ADDITIONAL_SENSE, + EOP_EOM_DETECTED_ASCQ, (unsigned int)i, + SENSE_FLAG_EOM); + return check_condition_result; +} + +enum {SDEBUG_READ_POSITION_ARR_SZ = 20}; +static int resp_read_position(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + u8 *cmd = scp->cmnd; + int all_length; + unsigned char arr[20]; + unsigned int pos; + + all_length = get_unaligned_be16(cmd + 7); + if ((cmd[1] & 0xfe) != 0 || + all_length != 0) { /* only short form */ + mk_sense_invalid_fld(scp, SDEB_IN_CDB, + all_length ? 7 : 1, 0); + return check_condition_result; + } + memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ); + arr[1] = devip->tape_partition; + pos = devip->tape_location[devip->tape_partition]; + put_unaligned_be32(pos, arr + 4); + put_unaligned_be32(pos, arr + 8); + return fill_from_dev_buffer(scp, arr, SDEBUG_READ_POSITION_ARR_SZ); +} + +static int resp_rewind(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + devip->tape_location[devip->tape_partition] = 0; + + return 0; +} + +static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions, + int part_0_size, int part_1_size) +{ + int i; + + if (part_0_size + part_1_size > TAPE_UNITS) + return -1; + devip->tape_eop[0] = part_0_size; + devip->tape_blocks[0]->fl_size = TAPE_BLOCK_EOD_FLAG; + devip->tape_eop[1] = part_1_size; + devip->tape_blocks[1] = devip->tape_blocks[0] + + devip->tape_eop[0]; + devip->tape_blocks[1]->fl_size = TAPE_BLOCK_EOD_FLAG; + + for (i = 0 ; i < TAPE_MAX_PARTITIONS; i++) + devip->tape_location[i] = 0; + + devip->tape_nbr_partitions = nbr_partitions; + devip->tape_partition = 0; + + partition_pg[3] = nbr_partitions - 1; + put_unaligned_be16(devip->tape_eop[0], partition_pg + 8); + put_unaligned_be16(devip->tape_eop[1], partition_pg + 10); + + return nbr_partitions; +} + +static int resp_format_medium(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + int res = 0; + unsigned char *cmd = scp->cmnd; + + if (cmd[2] > 2) { + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 2, -1); + return check_condition_result; + } + if (cmd[2] != 0) { + if (devip->tape_pending_nbr_partitions > 0) { + res = partition_tape(devip, + devip->tape_pending_nbr_partitions, + devip->tape_pending_part_0_size, + devip->tape_pending_part_1_size); + } else + res = partition_tape(devip, devip->tape_nbr_partitions, + devip->tape_eop[0], devip->tape_eop[1]); + } else + res = partition_tape(devip, 1, TAPE_UNITS, 0); + if (res < 0) + return -EINVAL; + + devip->tape_pending_nbr_partitions = -1; + + return 0; +} + +static int resp_erase(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + int partition = devip->tape_partition; + int pos = devip->tape_location[partition]; + struct tape_block *blp; + + blp = devip->tape_blocks[partition] + pos; + blp->fl_size = TAPE_BLOCK_EOD_FLAG; + + return 0; +} + static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) { return devip->nr_zones != 0; @@ -3871,6 +4456,98 @@ static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, return ret; } +static int resp_read_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + u32 i, num, transfer, size; + u8 *cmd = scp->cmnd; + struct scsi_data_buffer *sdb = &scp->sdb; + int partition = devip->tape_partition; + u32 pos = devip->tape_location[partition]; + struct tape_block *blp; + bool fixed, sili; + + if (cmd[0] != READ_6) { /* Only Read(6) supported */ + mk_sense_invalid_opcode(scp); + return illegal_condition_result; + } + fixed = (cmd[1] & 0x1) != 0; + sili = (cmd[1] & 0x2) != 0; + if (fixed && sili) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); + return check_condition_result; + } + + transfer = get_unaligned_be24(cmd + 2); + if (fixed) { + num = transfer; + size = devip->tape_blksize; + } else { + if (transfer < TAPE_MIN_BLKSIZE || + transfer > TAPE_MAX_BLKSIZE) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); + return check_condition_result; + } + num = 1; + size = transfer; + } + + for (i = 0, blp = devip->tape_blocks[partition] + pos; + i < num && pos < devip->tape_eop[partition]; + i++, pos++, blp++) { + devip->tape_location[partition] = pos + 1; + if (IS_TAPE_BLOCK_FM(blp->fl_size)) { + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + FILEMARK_DETECTED_ASCQ, fixed ? num - i : size, + SENSE_FLAG_FILEMARK); + scsi_set_resid(scp, (num - i) * size); + return check_condition_result; + } + /* Assume no REW */ + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) { + mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE, + EOD_DETECTED_ASCQ, fixed ? num - i : size, + 0); + devip->tape_location[partition] = pos; + scsi_set_resid(scp, (num - i) * size); + return check_condition_result; + } + sg_zero_buffer(sdb->table.sgl, sdb->table.nents, + size, i * size); + sg_copy_buffer(sdb->table.sgl, sdb->table.nents, + &(blp->data), 4, i * size, false); + if (fixed) { + if (blp->fl_size != devip->tape_blksize) { + scsi_set_resid(scp, (num - i) * size); + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + 0, num - i, + SENSE_FLAG_ILI); + return check_condition_result; + } + } else { + if (blp->fl_size != size) { + if (blp->fl_size < size) + scsi_set_resid(scp, size - blp->fl_size); + if (!sili) { + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + 0, size - blp->fl_size, + SENSE_FLAG_ILI); + return check_condition_result; + } + } + } + } + if (pos >= devip->tape_eop[partition]) { + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, + EOP_EOM_DETECTED_ASCQ, fixed ? num - i : size, + SENSE_FLAG_EOM); + devip->tape_location[partition] = pos - 1; + return check_condition_result; + } + devip->tape_location[partition] = pos; + + return 0; +} + static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { bool check_prot; @@ -4178,6 +4855,67 @@ static void unmap_region(struct sdeb_store_info *sip, sector_t lba, } } +static int resp_write_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + u32 i, num, transfer, size, written = 0; + u8 *cmd = scp->cmnd; + struct scsi_data_buffer *sdb = &scp->sdb; + int partition = devip->tape_partition; + int pos = devip->tape_location[partition]; + struct tape_block *blp; + bool fixed, ew; + + if (cmd[0] != WRITE_6) { /* Only Write(6) supported */ + mk_sense_invalid_opcode(scp); + return illegal_condition_result; + } + + fixed = (cmd[1] & 1) != 0; + transfer = get_unaligned_be24(cmd + 2); + if (fixed) { + num = transfer; + size = devip->tape_blksize; + } else { + if (transfer < TAPE_MIN_BLKSIZE || + transfer > TAPE_MAX_BLKSIZE) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); + return check_condition_result; + } + num = 1; + size = transfer; + } + + scsi_set_resid(scp, num * transfer); + for (i = 0, blp = devip->tape_blocks[partition] + pos, ew = false; + i < num && pos < devip->tape_eop[partition] - 1; i++, pos++, blp++) { + blp->fl_size = size; + sg_copy_buffer(sdb->table.sgl, sdb->table.nents, + &(blp->data), 4, i * size, true); + written += size; + scsi_set_resid(scp, num * transfer - written); + ew |= (pos == devip->tape_eop[partition] - TAPE_EW); + } + + devip->tape_location[partition] = pos; + blp->fl_size = TAPE_BLOCK_EOD_FLAG; + if (pos >= devip->tape_eop[partition] - 1) { + mk_sense_info_tape(scp, VOLUME_OVERFLOW, + NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ, + fixed ? num - i : transfer, + SENSE_FLAG_EOM); + return check_condition_result; + } + if (ew) { /* early warning */ + mk_sense_info_tape(scp, NO_SENSE, + NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ, + fixed ? num - i : transfer, + SENSE_FLAG_EOM); + return check_condition_result; + } + + return 0; +} + static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { bool check_prot; @@ -4190,6 +4928,14 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) u8 *cmd = scp->cmnd; bool meta_data_locked = false; + if (unlikely(sdebug_opts & SDEBUG_OPT_UNALIGNED_WRITE && + atomic_read(&sdeb_inject_pending))) { + atomic_set(&sdeb_inject_pending, 0); + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, + UNALIGNED_WRITE_ASCQ); + return check_condition_result; + } + switch (cmd[0]) { case WRITE_16: ei_lba = 0; @@ -4381,8 +5127,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if (lbdof == 0) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LB Data Offset field bad\n", - my_name, __func__); + "%s: LB Data Offset field bad\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -4390,8 +5135,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LBA range descriptors don't fit\n", - my_name, __func__); + "%s: LBA range descriptors don't fit\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -4400,8 +5144,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, return SCSI_MLQUEUE_HOST_BUSY; if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", - my_name, __func__, lbdof_blen); + "%s: Fetch header+scatter_list, lbdof_blen=%u\n", + my_name, lbdof_blen); res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); if (res == -1) { ret = DID_ERROR << 16; @@ -4418,8 +5162,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, num = get_unaligned_be32(up + 8); if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", - my_name, __func__, k, lba, num, sg_off); + "%s: k=%d LBA=0x%llx num=%u sg_off=%u\n", + my_name, k, lba, num, sg_off); if (num == 0) continue; ret = check_device_access_params(scp, lba, num, true); @@ -4431,8 +5175,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((cum_lb + num) > bt_len) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: sum of blocks > data provided\n", - my_name, __func__); + "%s: sum of blocks > data provided\n", + my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 0); ret = illegal_condition_result; @@ -4918,6 +5662,8 @@ static int resp_sync_cache(struct scsi_cmnd *scp, * a GOOD status otherwise. Model a disk with a big cache and yield * CONDITION MET. Actually tries to bring range in main memory into the * cache associated with the CPU(s). + * + * The pcode 0x34 is also used for READ POSITION by tape devices. */ static int resp_pre_fetch(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) @@ -5122,8 +5868,8 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) goto cleanup; } else if (sdebug_verbose && (ret < (a_num * lb_size))) { sdev_printk(KERN_INFO, scp->device, - "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", - my_name, __func__, a_num * lb_size, ret); + "%s: cdb indicated=%u, IO sent=%d bytes\n", + my_name, a_num * lb_size, ret); } if (is_bytchk3) { for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) @@ -5638,10 +6384,10 @@ static u32 get_tag(struct scsi_cmnd *cmnd) /* Queued (deferred) command completions converge here. */ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) { - struct sdebug_queued_cmd *sqcp = container_of(sd_dp, struct sdebug_queued_cmd, sd_dp); + struct sdebug_scsi_cmd *sdsc = container_of(sd_dp, + typeof(*sdsc), sd_dp); + struct scsi_cmnd *scp = (struct scsi_cmnd *)sdsc - 1; unsigned long flags; - struct scsi_cmnd *scp = sqcp->scmd; - struct sdebug_scsi_cmd *sdsc; bool aborted; if (sdebug_statistics) { @@ -5650,29 +6396,20 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) atomic_inc(&sdebug_miss_cpus); } - if (!scp) { - pr_err("scmd=NULL\n"); - goto out; - } - - sdsc = scsi_cmd_priv(scp); spin_lock_irqsave(&sdsc->lock, flags); aborted = sd_dp->aborted; if (unlikely(aborted)) sd_dp->aborted = false; - ASSIGN_QUEUED_CMD(scp, NULL); spin_unlock_irqrestore(&sdsc->lock, flags); if (aborted) { pr_info("bypassing scsi_done() due to aborted cmd, kicking-off EH\n"); blk_abort_request(scsi_cmd_to_rq(scp)); - goto out; + return; } scsi_done(scp); /* callback to mid level */ -out: - sdebug_free_queued_cmd(sqcp); } /* When high resolution timer goes off this function is called. */ @@ -5767,8 +6504,7 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) devip->max_open = sdeb_zbc_max_open; } - devip->zstate = kcalloc(devip->nr_zones, - sizeof(struct sdeb_zone_state), GFP_KERNEL); + devip->zstate = kzalloc_objs(struct sdeb_zone_state, devip->nr_zones); if (!devip->zstate) return -ENOMEM; @@ -5812,7 +6548,7 @@ static struct sdebug_dev_info *sdebug_device_create( { struct sdebug_dev_info *devip; - devip = kzalloc(sizeof(*devip), flags); + devip = kzalloc_obj(*devip, flags); if (devip) { if (sdebug_uuid_ctl == 1) uuid_gen(&devip->lu_name); @@ -5835,6 +6571,10 @@ static struct sdebug_dev_info *sdebug_device_create( } else { devip->zoned = false; } + if (sdebug_ptype == TYPE_TAPE) { + devip->tape_density = TAPE_DEF_DENSITY; + devip->tape_blksize = TAPE_DEF_BLKSIZE; + } devip->create_ts = ktime_get_boottime(); atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); spin_lock_init(&devip->list_lock); @@ -5905,6 +6645,20 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, if (devip == NULL) return 1; /* no resources, will be marked offline */ } + if (sdebug_ptype == TYPE_TAPE) { + if (!devip->tape_blocks[0]) { + devip->tape_blocks[0] = + kzalloc_objs(struct tape_block, TAPE_UNITS); + if (!devip->tape_blocks[0]) + return 1; + } + devip->tape_pending_nbr_partitions = -1; + if (partition_tape(devip, 1, TAPE_UNITS, 0) < 0) { + kfree(devip->tape_blocks[0]); + devip->tape_blocks[0] = NULL; + return 1; + } + } sdp->hostdata = devip; if (sdebug_no_uld) sdp->no_uld_attach = 1; @@ -5916,14 +6670,14 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, devip->debugfs_entry = debugfs_create_dir(dev_name(&sdp->sdev_dev), sdebug_debugfs_root); if (IS_ERR_OR_NULL(devip->debugfs_entry)) - pr_info("%s: failed to create debugfs directory for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create debugfs directory for device %s\n", + dev_name(&sdp->sdev_gendev)); dentry = debugfs_create_file("error", 0600, devip->debugfs_entry, sdp, &sdebug_error_fops); if (IS_ERR_OR_NULL(dentry)) - pr_info("%s: failed to create error file for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create error file for device %s\n", + dev_name(&sdp->sdev_gendev)); return 0; } @@ -5950,31 +6704,41 @@ static void scsi_debug_sdev_destroy(struct scsi_device *sdp) debugfs_remove(devip->debugfs_entry); + if (sdp->type == TYPE_TAPE) { + kfree(devip->tape_blocks[0]); + devip->tape_blocks[0] = NULL; + } + /* make this slot available for re-use */ devip->used = false; sdp->hostdata = NULL; } -/* Returns true if we require the queued memory to be freed by the caller. */ -static bool stop_qc_helper(struct sdebug_defer *sd_dp, - enum sdeb_defer_type defer_t) +/* Returns true if cancelled or not running callback. */ +static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) { + struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); + struct sdebug_defer *sd_dp = &sdsc->sd_dp; + enum sdeb_defer_type defer_t = sd_dp->defer_t; + + lockdep_assert_held(&sdsc->lock); + if (defer_t == SDEB_DEFER_HRT) { int res = hrtimer_try_to_cancel(&sd_dp->hrt); switch (res) { - case 0: /* Not active, it must have already run */ case -1: /* -1 It's executing the CB */ return false; + case 0: /* Not active, it must have already run */ case 1: /* Was active, we've now cancelled */ default: return true; } } else if (defer_t == SDEB_DEFER_WQ) { /* Cancel if pending */ - if (cancel_work_sync(&sd_dp->ew.work)) + if (cancel_work(&sd_dp->ew.work)) return true; - /* Was not pending, so it must have run */ + /* callback may be running, so return false */ return false; } else if (defer_t == SDEB_DEFER_POLL) { return true; @@ -5983,42 +6747,59 @@ static bool stop_qc_helper(struct sdebug_defer *sd_dp, return false; } +struct sdebug_abort_cmd { + u32 unique_tag; +}; -static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) -{ - enum sdeb_defer_type l_defer_t; - struct sdebug_defer *sd_dp; - struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); - struct sdebug_queued_cmd *sqcp = TO_QUEUED_CMD(cmnd); - - lockdep_assert_held(&sdsc->lock); +enum sdebug_internal_cmd_type { + SCSI_DEBUG_ABORT_CMD, +}; - if (!sqcp) - return false; - sd_dp = &sqcp->sd_dp; - l_defer_t = READ_ONCE(sd_dp->defer_t); - ASSIGN_QUEUED_CMD(cmnd, NULL); +struct sdebug_internal_cmd { + enum sdebug_internal_cmd_type type; - if (stop_qc_helper(sd_dp, l_defer_t)) - sdebug_free_queued_cmd(sqcp); + union { + struct sdebug_abort_cmd abort_cmd; + }; +}; - return true; -} +union sdebug_priv { + struct sdebug_scsi_cmd cmd; + struct sdebug_internal_cmd internal_cmd; +}; /* - * Called from scsi_debug_abort() only, which is for timed-out cmd. + * Abort SCSI command @cmnd. Only called from scsi_debug_abort(). Although + * it would be possible to call scsi_debug_stop_cmnd() directly, an internal + * command is allocated and submitted to trigger the reserved command + * infrastructure. */ static bool scsi_debug_abort_cmnd(struct scsi_cmnd *cmnd) { - struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); - unsigned long flags; - bool res; - - spin_lock_irqsave(&sdsc->lock, flags); - res = scsi_debug_stop_cmnd(cmnd); - spin_unlock_irqrestore(&sdsc->lock, flags); - - return res; + struct Scsi_Host *shost = cmnd->device->host; + struct request *rq = scsi_cmd_to_rq(cmnd); + u32 unique_tag = blk_mq_unique_tag(rq); + struct sdebug_internal_cmd *internal_cmd; + struct scsi_cmnd *abort_cmd; + struct request *abort_rq; + blk_status_t res; + + abort_cmd = scsi_get_internal_cmd(shost->pseudo_sdev, DMA_NONE, + BLK_MQ_REQ_RESERVED); + if (!abort_cmd) + return false; + internal_cmd = scsi_cmd_priv(abort_cmd); + *internal_cmd = (struct sdebug_internal_cmd) { + .type = SCSI_DEBUG_ABORT_CMD, + .abort_cmd = { + .unique_tag = unique_tag, + }, + }; + abort_rq = scsi_cmd_to_rq(abort_cmd); + abort_rq->timeout = secs_to_jiffies(3); + res = blk_execute_rq(abort_rq, true); + scsi_put_internal_cmd(abort_cmd); + return res == BLK_STS_OK; } /* @@ -6076,7 +6857,7 @@ static int sdebug_fail_abort(struct scsi_cmnd *cmnd) static int scsi_debug_abort(struct scsi_cmnd *SCpnt) { - bool ok = scsi_debug_abort_cmnd(SCpnt); + bool aborted = scsi_debug_abort_cmnd(SCpnt); u8 *cmd = SCpnt->cmnd; u8 opcode = cmd[0]; @@ -6084,8 +6865,9 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: command%s found\n", __func__, - ok ? "" : " not"); + "command%s found\n", + aborted ? "" : " not"); + if (sdebug_fail_abort(SCpnt)) { scmd_printk(KERN_INFO, SCpnt, "fail abort command 0x%x\n", @@ -6093,6 +6875,9 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) return FAILED; } + if (aborted == false) + return FAILED; + return SUCCESS; } @@ -6144,6 +6929,20 @@ static int sdebug_fail_lun_reset(struct scsi_cmnd *cmnd) return 0; } +static void scsi_tape_reset_clear(struct sdebug_dev_info *devip) +{ + int i; + + devip->tape_blksize = TAPE_DEF_BLKSIZE; + devip->tape_density = TAPE_DEF_DENSITY; + devip->tape_partition = 0; + devip->tape_dce = 0; + for (i = 0; i < TAPE_MAX_PARTITIONS; i++) + devip->tape_location[i] = 0; + devip->tape_pending_nbr_partitions = -1; + /* Don't reset partitioning? */ +} + static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) { struct scsi_device *sdp = SCpnt->device; @@ -6154,11 +6953,14 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) ++num_dev_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing device reset"); scsi_debug_stop_all_queued(sdp); - if (devip) + if (devip) { set_bit(SDEBUG_UA_POR, devip->uas_bm); + if (SCpnt->device->type == TYPE_TAPE) + scsi_tape_reset_clear(devip); + } if (sdebug_fail_lun_reset(SCpnt)) { scmd_printk(KERN_INFO, SCpnt, "fail lun reset 0x%x\n", opcode); @@ -6191,18 +6993,20 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) ++num_target_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing target reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { if (devip->target == sdp->id) { set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); + if (SCpnt->device->type == TYPE_TAPE) + scsi_tape_reset_clear(devip); ++k; } } if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in target\n", __func__, k); + "%d device(s) found in target\n", k); if (sdebug_fail_target_reset(SCpnt)) { scmd_printk(KERN_INFO, SCpnt, "fail target reset 0x%x\n", @@ -6223,16 +7027,18 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) ++num_bus_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing bus reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); + if (SCpnt->device->type == TYPE_TAPE) + scsi_tape_reset_clear(devip); ++k; } if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in host\n", __func__, k); + "%d device(s) found in host\n", k); return SUCCESS; } @@ -6244,12 +7050,14 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) ++num_host_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); + sdev_printk(KERN_INFO, SCpnt->device, "doing host reset\n"); mutex_lock(&sdebug_host_list_mutex); list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); + if (SCpnt->device->type == TYPE_TAPE) + scsi_tape_reset_clear(devip); ++k; } } @@ -6257,7 +7065,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) stop_all_queued(); if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: %d device(s) found\n", __func__, k); + "%d device(s) found\n", k); return SUCCESS; } @@ -6366,33 +7174,6 @@ static bool inject_on_this_cmd(void) #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ - -void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp) -{ - if (sqcp) - kmem_cache_free(queued_cmd_cache, sqcp); -} - -static struct sdebug_queued_cmd *sdebug_alloc_queued_cmd(struct scsi_cmnd *scmd) -{ - struct sdebug_queued_cmd *sqcp; - struct sdebug_defer *sd_dp; - - sqcp = kmem_cache_zalloc(queued_cmd_cache, GFP_ATOMIC); - if (!sqcp) - return NULL; - - sd_dp = &sqcp->sd_dp; - - hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); - sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; - INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); - - sqcp->scmd = scmd; - - return sqcp; -} - /* Complete the processing of the thread that queued a SCSI command to this * driver. It either completes the command by calling cmnd_done() or * schedules a hr timer or work queue then returns 0. Returns @@ -6409,7 +7190,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); unsigned long flags; u64 ns_from_boot = 0; - struct sdebug_queued_cmd *sqcp; struct scsi_device *sdp; struct sdebug_defer *sd_dp; @@ -6436,17 +7216,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, scsi_result = device_qfull_result; if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts)) - sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, <inject> status: TASK SET FULL\n", - __func__, num_in_q); + sdev_printk(KERN_INFO, sdp, "num_in_q=%d +1, <inject> status: TASK SET FULL\n", + num_in_q); } } - sqcp = sdebug_alloc_queued_cmd(cmnd); - if (!sqcp) { - pr_err("%s no alloc\n", __func__); - return SCSI_MLQUEUE_HOST_BUSY; - } - sd_dp = &sqcp->sd_dp; + sd_dp = &sdsc->sd_dp; if (polled || (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)) ns_from_boot = ktime_get_boottime_ns(); @@ -6468,8 +7243,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } if (unlikely(sdebug_verbose && cmnd->result)) - sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", - __func__, cmnd->result); + sdev_printk(KERN_INFO, sdp, "non-zero result=0x%x\n", + cmnd->result); if (delta_jiff > 0 || ndelay > 0) { ktime_t kt; @@ -6494,7 +7269,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (kt <= d) { /* elapsed duration >= kt */ /* call scsi_done() from this thread */ - sdebug_free_queued_cmd(sqcp); scsi_done(cmnd); return 0; } @@ -6507,14 +7281,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (polled) { spin_lock_irqsave(&sdsc->lock, flags); sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); - ASSIGN_QUEUED_CMD(cmnd, sqcp); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { /* schedule the invocation of scsi_done() for a later time */ spin_lock_irqsave(&sdsc->lock, flags); - ASSIGN_QUEUED_CMD(cmnd, sqcp); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); + sd_dp->defer_t = SDEB_DEFER_HRT; hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); /* * The completion handler will try to grab sqcp->lock, @@ -6537,14 +7309,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, sd_dp->issuing_cpu = raw_smp_processor_id(); if (polled) { spin_lock_irqsave(&sdsc->lock, flags); - ASSIGN_QUEUED_CMD(cmnd, sqcp); sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { spin_lock_irqsave(&sdsc->lock, flags); - ASSIGN_QUEUED_CMD(cmnd, sqcp); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); + sd_dp->defer_t = SDEB_DEFER_WQ; schedule_work(&sd_dp->ew.work); spin_unlock_irqrestore(&sdsc->lock, flags); } @@ -6674,7 +7444,7 @@ MODULE_PARM_DESC(lbprz, MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(atomic_write, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); +MODULE_PARM_DESC(atomic_wr, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); @@ -6835,7 +7605,7 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) blk_mq_tagset_busy_iter(&host->tag_set, sdebug_submit_queue_iter, &data); if (f >= 0) { - seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", + seq_printf(m, " BUSY: %s: %d,%d\n", "first,last bits", f, l); } } @@ -7910,15 +8680,9 @@ static int __init scsi_debug_init(void) hosts_to_add = sdebug_add_host; sdebug_add_host = 0; - queued_cmd_cache = KMEM_CACHE(sdebug_queued_cmd, SLAB_HWCACHE_ALIGN); - if (!queued_cmd_cache) { - ret = -ENOMEM; - goto driver_unreg; - } - sdebug_debugfs_root = debugfs_create_dir("scsi_debug", NULL); if (IS_ERR_OR_NULL(sdebug_debugfs_root)) - pr_info("%s: failed to create initial debugfs directory\n", __func__); + pr_info("failed to create initial debugfs directory\n"); for (k = 0; k < hosts_to_add; k++) { if (want_store && k == 0) { @@ -7942,8 +8706,6 @@ static int __init scsi_debug_init(void) return 0; -driver_unreg: - driver_unregister(&sdebug_driverfs_driver); bus_unreg: bus_unregister(&pseudo_lld_bus); dev_unreg: @@ -7959,7 +8721,6 @@ static void __exit scsi_debug_exit(void) for (; k; k--) sdebug_do_remove_host(true); - kmem_cache_destroy(queued_cmd_cache); driver_unregister(&sdebug_driverfs_driver); bus_unregister(&pseudo_lld_bus); root_device_unregister(pseudo_primary); @@ -8028,7 +8789,7 @@ static int sdebug_add_store(void) struct sdeb_store_info *sip = NULL; struct xa_limit xal = { .max = 1 << 16, .min = 0 }; - sip = kzalloc(sizeof(*sip), GFP_KERNEL); + sip = kzalloc_obj(*sip); if (!sip) return -ENOMEM; @@ -8037,7 +8798,7 @@ static int sdebug_add_store(void) if (unlikely(res < 0)) { xa_unlock_irqrestore(per_store_ap, iflags); kfree(sip); - pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); + pr_warn("xa_alloc() errno=%d\n", -res); return res; } sdeb_most_recent_idx = n_idx; @@ -8061,7 +8822,7 @@ static int sdebug_add_store(void) dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); sip->dif_storep = vmalloc(dif_size); - pr_info("dif_storep %u bytes @ %pK\n", dif_size, + pr_info("dif_storep %u bytes @ %p\n", dif_size, sip->dif_storep); if (!sip->dif_storep) { @@ -8073,8 +8834,8 @@ static int sdebug_add_store(void) /* Logical Block Provisioning */ if (scsi_debug_lbp()) { map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; - sip->map_storep = vmalloc(array_size(sizeof(long), - BITS_TO_LONGS(map_size))); + sip->map_storep = vcalloc(BITS_TO_LONGS(map_size), + sizeof(long)); pr_info("%lu provisioning blocks\n", map_size); @@ -8083,8 +8844,6 @@ static int sdebug_add_store(void) goto err; } - bitmap_zero(sip->map_storep, map_size); - /* Map first 1KB for partition table */ if (sdebug_num_parts) map_region(sip, 0, 2); @@ -8096,7 +8855,7 @@ static int sdebug_add_store(void) return (int)n_idx; err: sdebug_erase_store((int)n_idx, sip); - pr_warn("%s: failed, errno=%d\n", __func__, -res); + pr_warn("failed, errno=%d\n", -res); return res; } @@ -8107,7 +8866,7 @@ static int sdebug_add_host_helper(int per_host_idx) struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *sdbg_devinfo, *tmp; - sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); + sdbg_host = kzalloc_obj(*sdbg_host); if (!sdbg_host) return -ENOMEM; idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; @@ -8155,7 +8914,7 @@ clean: put_device(&sdbg_host->dev); else kfree(sdbg_host); - pr_warn("%s: failed, errno=%d\n", __func__, -error); + pr_warn("failed, errno=%d\n", -error); return error; } @@ -8223,7 +8982,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) if (qdepth > SDEBUG_CANQUEUE) { qdepth = SDEBUG_CANQUEUE; - pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, + pr_warn("requested qdepth [%d] exceeds canqueue [%d], trim\n", qdepth, SDEBUG_CANQUEUE); } if (qdepth < 1) @@ -8235,7 +8994,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) mutex_unlock(&sdebug_host_list_mutex); if (SDEBUG_OPT_Q_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth); + sdev_printk(KERN_INFO, sdev, "qdepth=%d\n", qdepth); return sdev->queue_depth; } @@ -8343,7 +9102,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) struct sdebug_defer *sd_dp; u32 unique_tag = blk_mq_unique_tag(rq); u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag); - struct sdebug_queued_cmd *sqcp; unsigned long flags; int queue_num = data->queue_num; ktime_t time; @@ -8359,14 +9117,8 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) time = ktime_get_boottime(); spin_lock_irqsave(&sdsc->lock, flags); - sqcp = TO_QUEUED_CMD(cmd); - if (!sqcp) { - spin_unlock_irqrestore(&sdsc->lock, flags); - return true; - } - - sd_dp = &sqcp->sd_dp; - if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) { + sd_dp = &sdsc->sd_dp; + if (sd_dp->defer_t != SDEB_DEFER_POLL) { spin_unlock_irqrestore(&sdsc->lock, flags); return true; } @@ -8375,8 +9127,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) spin_unlock_irqrestore(&sdsc->lock, flags); return true; } - - ASSIGN_QUEUED_CMD(cmd, NULL); spin_unlock_irqrestore(&sdsc->lock, flags); if (sdebug_statistics) { @@ -8385,8 +9135,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) atomic_inc(&sdebug_miss_cpus); } - sdebug_free_queued_cmd(sqcp); - scsi_done(cmd); /* callback to mid level */ (*data->num_entries)++; return true; @@ -8506,8 +9254,56 @@ out_handle: return ret; } -static int scsi_debug_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scp) +/* Process @scp, a request to abort a SCSI command by tag. */ +static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) +{ + struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp); + struct sdebug_abort_cmd *abort_cmd = &internal_cmd->abort_cmd; + const u32 unique_tag = abort_cmd->unique_tag; + struct scsi_cmnd *to_be_aborted_scmd = + scsi_host_find_tag(shost, unique_tag); + struct sdebug_scsi_cmd *to_be_aborted_sdsc = + scsi_cmd_priv(to_be_aborted_scmd); + bool res = false; + + if (!to_be_aborted_scmd) { + pr_err("command with tag %#x not found\n", unique_tag); + return; + } + + scoped_guard(spinlock_irqsave, &to_be_aborted_sdsc->lock) + res = scsi_debug_stop_cmnd(to_be_aborted_scmd); + + if (res) + pr_info("aborted command with tag %#x\n", unique_tag); + else + pr_err("failed to abort command with tag %#x\n", unique_tag); + + set_host_byte(scp, res ? DID_OK : DID_ERROR); +} + +static enum scsi_qc_status +scsi_debug_process_reserved_command(struct Scsi_Host *shost, + struct scsi_cmnd *scp) +{ + struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp); + + switch (internal_cmd->type) { + case SCSI_DEBUG_ABORT_CMD: + scsi_debug_abort_cmd(shost, scp); + break; + default: + WARN_ON_ONCE(true); + set_host_byte(scp, DID_ERROR); + break; + } + + scsi_done(scp); + return 0; +} + +static enum scsi_qc_status scsi_debug_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scp) { u8 sdeb_i; struct scsi_device *sdp = scp->device; @@ -8523,6 +9319,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, u32 flags; u16 sa; u8 opcode = cmd[0]; + u32 devsel = sdebug_get_devsel(scp->device); bool has_wlun_rl; bool inject_now; int ret = 0; @@ -8602,12 +9399,14 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, else sa = get_unaligned_be16(cmd + 8); for (k = 0; k <= na; oip = r_oip->arrp + k++) { - if (opcode == oip->opcode && sa == oip->sa) + if (opcode == oip->opcode && sa == oip->sa && + (devsel & oip->devsel) != 0) break; } } else { /* since no service action only check opcode */ for (k = 0; k <= na; oip = r_oip->arrp + k++) { - if (opcode == oip->opcode) + if (opcode == oip->opcode && + (devsel & oip->devsel) != 0) break; } } @@ -8701,8 +9500,15 @@ err_out: static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) { struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd); + struct sdebug_defer *sd_dp = &sdsc->sd_dp; + + if (blk_mq_is_reserved_rq(scsi_cmd_to_rq(cmd))) + return 0; spin_lock_init(&sdsc->lock); + hrtimer_setup(&sd_dp->hrt, sdebug_q_cmd_hrt_complete, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); return 0; } @@ -8718,6 +9524,7 @@ static const struct scsi_host_template sdebug_driver_template = { .sdev_destroy = scsi_debug_sdev_destroy, .ioctl = scsi_debug_ioctl, .queuecommand = scsi_debug_queuecommand, + .queue_reserved_command = scsi_debug_process_reserved_command, .change_queue_depth = sdebug_change_qdepth, .map_queues = sdebug_map_queues, .mq_poll = sdebug_blk_mq_poll, @@ -8727,6 +9534,7 @@ static const struct scsi_host_template sdebug_driver_template = { .eh_bus_reset_handler = scsi_debug_bus_reset, .eh_host_reset_handler = scsi_debug_host_reset, .can_queue = SDEBUG_CANQUEUE, + .nr_reserved_cmds = 1, .this_id = 7, .sg_tablesize = SG_MAX_SEGMENTS, .cmd_per_lun = DEF_CMD_PER_LUN, @@ -8735,7 +9543,7 @@ static const struct scsi_host_template sdebug_driver_template = { .module = THIS_MODULE, .skip_settle_delay = 1, .track_queue_depth = 1, - .cmd_size = sizeof(struct sdebug_scsi_cmd), + .cmd_size = sizeof(union sdebug_priv), .init_cmd_priv = sdebug_init_cmd_priv, .target_alloc = sdebug_target_alloc, .target_destroy = sdebug_target_destroy, diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 90f1393a23f8..68a992494b12 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -190,7 +190,7 @@ static struct { {"IBM", "2076", NULL, BLIST_NO_VPD_SIZE}, {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN}, + {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN | BLIST_SKIP_IO_HINTS}, {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, {"INSITE", "I325VM", NULL, BLIST_KEY}, @@ -269,17 +269,12 @@ static struct { static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key) { struct scsi_dev_info_list_table *devinfo_table; - int found = 0; list_for_each_entry(devinfo_table, &scsi_dev_info_list, node) - if (devinfo_table->key == key) { - found = 1; - break; - } - if (!found) - return ERR_PTR(-EINVAL); + if (devinfo_table->key == key) + return devinfo_table; - return devinfo_table; + return ERR_PTR(-EINVAL); } /* @@ -360,7 +355,7 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, if (IS_ERR(devinfo_table)) return PTR_ERR(devinfo_table); - devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); + devinfo = kmalloc_obj(*devinfo); if (!devinfo) { printk(KERN_ERR "%s: no memory\n", __func__); return -ENOMEM; @@ -486,33 +481,6 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, } /** - * scsi_dev_info_list_del_keyed - remove one dev_info list entry. - * @vendor: vendor string - * @model: model (product) string - * @key: specify list to use - * - * Description: - * Remove and destroy one dev_info entry for @vendor, @model - * in list specified by @key. - * - * Returns: 0 OK, -error on failure. - **/ -int scsi_dev_info_list_del_keyed(char *vendor, char *model, - enum scsi_devinfo_key key) -{ - struct scsi_dev_info_list *found; - - found = scsi_dev_info_list_find(vendor, model, key); - if (IS_ERR(found)) - return PTR_ERR(found); - - list_del(&found->dev_info_list); - kfree(found); - return 0; -} -EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); - -/** * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. * @dev_list: string of device flags to add * @@ -647,7 +615,7 @@ static int devinfo_seq_show(struct seq_file *m, void *v) static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos) { - struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL); + struct double_list *dl = kmalloc_obj(*dl); loff_t pos = *ppos; if (!dl) @@ -791,7 +759,7 @@ int scsi_dev_info_add_list(enum scsi_devinfo_key key, const char *name) /* list already exists */ return -EEXIST; - devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL); + devinfo_table = kmalloc_obj(*devinfo_table); if (!devinfo_table) return -ENOMEM; @@ -863,7 +831,7 @@ int __init scsi_init_devinfo(void) goto out; for (i = 0; scsi_static_device_list[i].vendor; i++) { - error = scsi_dev_info_list_add(1 /* compatibile */, + error = scsi_dev_info_list_add(1 /* compatible */, scsi_static_device_list[i].vendor, scsi_static_device_list[i].model, NULL, diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 7b56e00c7df6..b9d805317814 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -353,7 +353,8 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach); * that may have a device handler attached * @gfp - the GFP mask used in the kmalloc() call when allocating memory * - * Returns name of attached handler, NULL if no handler is attached. + * Returns name of attached handler, NULL if no handler is attached, or + * and error pointer if an error occurred. * Caller must take care to free the returned string. */ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) @@ -363,10 +364,11 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) sdev = scsi_device_from_queue(q); if (!sdev) - return NULL; + return ERR_PTR(-ENODEV); if (sdev->handler) - handler_name = kstrdup(sdev->handler->name, gfp); + handler_name = kstrdup(sdev->handler->name, gfp) ? : + ERR_PTR(-ENOMEM); put_device(&sdev->sdev_gendev); return handler_name; } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 815e7d63f3e2..147127fb4db9 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -282,11 +282,20 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head) { struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu); struct Scsi_Host *shost = scmd->device->host; - unsigned int busy = scsi_host_busy(shost); + unsigned int busy; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); shost->host_failed++; + spin_unlock_irqrestore(shost->host_lock, flags); + /* + * The counting of busy requests needs to occur after adding to + * host_failed or after the lock acquire for adding to host_failed + * to prevent a race with host unbusy and missing an eh wakeup. + */ + busy = scsi_host_busy(shost); + + spin_lock_irqsave(shost->host_lock, flags); scsi_eh_wakeup(shost, busy); spin_unlock_irqrestore(shost->host_lock, flags); } @@ -547,6 +556,18 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) scsi_report_sense(sdev, &sshdr); + if (sshdr.sense_key == UNIT_ATTENTION) { + /* + * Increment the counters for Power on/Reset or New Media so + * that all ULDs interested in these can see that those have + * happened, even if someone else gets the sense data. + */ + if (sshdr.asc == 0x28) + atomic_inc(&sdev->ua_new_media_ctr); + else if (sshdr.asc == 0x29) + atomic_inc(&sdev->ua_por_ctr); + } + if (scsi_sense_is_deferred(&sshdr)) return NEEDS_RETRY; @@ -653,7 +674,8 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) * if the device is in the process of becoming ready, we * should retry. */ - if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01)) + if ((sshdr.asc == 0x04) && + (sshdr.ascq == 0x01 || sshdr.ascq == 0x0a)) return NEEDS_RETRY; /* * if the device is not started, we need to wake @@ -711,6 +733,13 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) return SUCCESS; case COMPLETED: + /* + * A command using command duration limits (CDL) with a + * descriptor set with policy 0xD may be completed with success + * and the sense data DATA CURRENTLY UNAVAILABLE, indicating + * that the command was in fact aborted because it exceeded its + * duration limit. Never retry these commands. + */ if (sshdr.asc == 0x55 && sshdr.ascq == 0x0a) { set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT); req->cmd_flags |= REQ_FAILFAST_DEV; @@ -729,6 +758,9 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) const struct scsi_host_template *sht = sdev->host->hostt; struct scsi_device *tmp_sdev; + if (!sdev->budget_map.map) + return; + if (!sht->track_queue_depth || sdev->queue_depth >= sdev->max_queue_depth) return; @@ -1040,6 +1072,9 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct request *rq = scsi_cmd_to_rq(scmd); +#endif /* * We need saved copies of a number of fields - this is because @@ -1092,6 +1127,18 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, (sdev->lun << 5 & 0xe0); /* + * Encryption must be disabled for the commands submitted by the error handler. + * Hence, clear the encryption context information. + */ +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + ses->rq_crypt_keyslot = rq->crypt_keyslot; + ses->rq_crypt_ctx = rq->crypt_ctx; + + rq->crypt_keyslot = NULL; + rq->crypt_ctx = NULL; +#endif + + /* * Zero the sense buffer. The scsi spec mandates that any * untransferred sense data should be interpreted as being zero. */ @@ -1108,6 +1155,10 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd); */ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) { +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct request *rq = scsi_cmd_to_rq(scmd); +#endif + /* * Restore original data */ @@ -1120,6 +1171,11 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->underflow = ses->underflow; scmd->prot_op = ses->prot_op; scmd->eh_eflags = ses->eh_eflags; + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + rq->crypt_keyslot = ses->rq_crypt_keyslot; + rq->crypt_ctx = ses->rq_crypt_ctx; +#endif } EXPORT_SYMBOL(scsi_eh_restore_cmnd); @@ -2062,7 +2118,8 @@ maybe_retry: } static enum rq_end_io_ret eh_lock_door_done(struct request *req, - blk_status_t status) + blk_status_t status, + const struct io_comp_batch *iob) { blk_mq_free_request(req); return RQ_END_IO_NONE; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 2fa45556e1ea..0ddc95bafc71 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -601,7 +601,7 @@ static int sg_scsi_ioctl(struct request_queue *q, bool open_for_write, } if (bytes) { - err = blk_rq_map_kern(q, rq, buffer, bytes, GFP_NOIO); + err = blk_rq_map_kern(rq, buffer, bytes, GFP_NOIO); if (err) goto error; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f1cfe0bb89b2..6e8c7a42603e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -13,6 +13,7 @@ #include <linux/bitops.h> #include <linux/blkdev.h> #include <linux/completion.h> +#include <linux/ctype.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/init.h> @@ -76,7 +77,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) } static void -scsi_set_blocked(struct scsi_cmnd *cmd, int reason) +scsi_set_blocked(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; @@ -139,7 +140,8 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd, unsigned long msecs) * for a requeue after completion, which should only occur in this * file. */ -static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) +static void __scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason, bool unbusy) { struct scsi_device *device = cmd->device; @@ -179,7 +181,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) * Context: This could be called either from an interrupt context or a normal * process context. */ -void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +void scsi_queue_insert(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { __scsi_queue_insert(cmd, reason, true); } @@ -313,8 +315,7 @@ retry: return PTR_ERR(req); if (bufflen) { - ret = blk_rq_map_kern(sdev->request_queue, req, - buffer, bufflen, GFP_NOIO); + ret = blk_rq_map_kern(req, buffer, bufflen, GFP_NOIO); if (ret) goto out; } @@ -377,6 +378,14 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd) rcu_read_lock(); __clear_bit(SCMD_STATE_INFLIGHT, &cmd->state); if (unlikely(scsi_host_in_recovery(shost))) { + /* + * Ensure the clear of SCMD_STATE_INFLIGHT is visible to + * other CPUs before counting busy requests. Otherwise, + * reordering can cause CPUs to race and miss an eh wakeup + * when no CPU sees all busy requests as done or timed out. + */ + smp_mb(); + unsigned int busy = scsi_host_busy(shost); spin_lock_irqsave(shost->host_lock, flags); @@ -397,7 +406,8 @@ void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd) if (starget->can_queue > 0) atomic_dec(&starget->target_busy); - sbitmap_put(&sdev->budget_map, cmd->budget_token); + if (sdev->budget_map.map) + sbitmap_put(&sdev->budget_map, cmd->budget_token); cmd->budget_token = -1; } @@ -1149,7 +1159,7 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd) * Next, walk the list, and fill in the addresses and sizes of * each segment. */ - count = __blk_rq_map_sg(rq->q, rq, cmd->sdb.table.sgl, &last_sg); + count = __blk_rq_map_sg(rq, cmd->sdb.table.sgl, &last_sg); if (blk_rq_bytes(rq) & rq->q->limits.dma_pad_mask) { unsigned int pad_len = @@ -1253,8 +1263,12 @@ EXPORT_SYMBOL_GPL(scsi_alloc_request); */ static void scsi_cleanup_rq(struct request *rq) { + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + + cmd->flags = 0; + if (rq->rq_flags & RQF_DONTPREP) { - scsi_mq_uninit_cmd(blk_mq_rq_to_pdu(rq)); + scsi_mq_uninit_cmd(cmd); rq->rq_flags &= ~RQF_DONTPREP; } } @@ -1357,6 +1371,9 @@ static inline int scsi_dev_queue_ready(struct request_queue *q, { int token; + if (!sdev->budget_map.map) + return INT_MAX; + token = sbitmap_get(&sdev->budget_map); if (token < 0) return -1; @@ -1527,6 +1544,14 @@ static void scsi_complete(struct request *rq) struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); enum scsi_disposition disposition; + if (blk_mq_is_reserved_rq(rq)) { + /* Only pass-through requests are supported in this code path. */ + WARN_ON_ONCE(!blk_rq_is_passthrough(scsi_cmd_to_rq(cmd))); + scsi_mq_uninit_cmd(cmd); + __blk_mq_end_request(rq, scsi_result_to_blk_status(cmd->result)); + return; + } + INIT_LIST_HEAD(&cmd->eh_entry); atomic_inc(&cmd->device->iodone_cnt); @@ -1562,7 +1587,7 @@ static void scsi_complete(struct request *rq) * Return: nonzero return request was rejected and device's queue needs to be * plugged. */ -static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) +static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; int rtn = 0; @@ -1746,7 +1771,8 @@ static void scsi_mq_put_budget(struct request_queue *q, int budget_token) { struct scsi_device *sdev = q->queuedata; - sbitmap_put(&sdev->budget_map, budget_token); + if (sdev->budget_map.map) + sbitmap_put(&sdev->budget_map, budget_token); } /* @@ -1810,37 +1836,43 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct Scsi_Host *shost = sdev->host; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); blk_status_t ret; - int reason; + enum scsi_qc_status reason; WARN_ON_ONCE(cmd->budget_token < 0); /* - * If the device is not in running state we will reject some or all - * commands. + * Bypass the SCSI device, SCSI target and SCSI host checks for + * reserved commands. */ - if (unlikely(sdev->sdev_state != SDEV_RUNNING)) { - ret = scsi_device_state_check(sdev, req); - if (ret != BLK_STS_OK) - goto out_put_budget; - } + if (!blk_mq_is_reserved_rq(req)) { + /* + * If the device is not in running state we will reject some or + * all commands. + */ + if (unlikely(sdev->sdev_state != SDEV_RUNNING)) { + ret = scsi_device_state_check(sdev, req); + if (ret != BLK_STS_OK) + goto out_put_budget; + } - ret = BLK_STS_RESOURCE; - if (!scsi_target_queue_ready(shost, sdev)) - goto out_put_budget; - if (unlikely(scsi_host_in_recovery(shost))) { - if (cmd->flags & SCMD_FAIL_IF_RECOVERING) - ret = BLK_STS_OFFLINE; - goto out_dec_target_busy; + ret = BLK_STS_RESOURCE; + if (!scsi_target_queue_ready(shost, sdev)) + goto out_put_budget; + if (unlikely(scsi_host_in_recovery(shost))) { + if (cmd->flags & SCMD_FAIL_IF_RECOVERING) + ret = BLK_STS_OFFLINE; + goto out_dec_target_busy; + } + if (!scsi_host_queue_ready(q, shost, sdev, cmd)) + goto out_dec_target_busy; } - if (!scsi_host_queue_ready(q, shost, sdev, cmd)) - goto out_dec_target_busy; /* * Only clear the driver-private command data if the LLD does not supply * a function to initialize that data. */ if (shost->hostt->cmd_size && !shost->hostt->init_cmd_priv) - memset(cmd + 1, 0, shost->hostt->cmd_size); + memset(scsi_cmd_priv(cmd), 0, shost->hostt->cmd_size); if (!(req->rq_flags & RQF_DONTPREP)) { ret = scsi_prepare_cmd(req); @@ -1862,6 +1894,14 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, cmd->submitter = SUBMITTED_BY_BLOCK_LAYER; blk_mq_start_request(req); + if (blk_mq_is_reserved_rq(req)) { + reason = shost->hostt->queue_reserved_command(shost, cmd); + if (reason) { + ret = BLK_STS_RESOURCE; + goto out_put_budget; + } + return BLK_STS_OK; + } reason = scsi_dispatch_cmd(cmd); if (reason) { scsi_set_blocked(cmd, reason); @@ -2000,9 +2040,6 @@ void scsi_init_limits(struct Scsi_Host *shost, struct queue_limits *lim) lim->dma_alignment = max_t(unsigned int, shost->dma_alignment, dma_get_cache_alignment() - 1); - if (shost->no_highmem) - lim->features |= BLK_FEAT_BOUNCE_HIGH; - /* * Propagate the DMA formation properties to the dma-mapping layer as * a courtesy service to the LLDDs. This needs to check that the buses @@ -2083,7 +2120,8 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost) tag_set->ops = &scsi_mq_ops_no_commit; tag_set->nr_hw_queues = shost->nr_hw_queues ? : 1; tag_set->nr_maps = shost->nr_maps ? : 1; - tag_set->queue_depth = shost->can_queue; + tag_set->queue_depth = shost->can_queue + shost->nr_reserved_cmds; + tag_set->reserved_tags = shost->nr_reserved_cmds; tag_set->cmd_size = cmd_size; tag_set->numa_node = dev_to_node(shost->dma_dev); if (shost->hostt->tag_alloc_policy_rr) @@ -2107,6 +2145,44 @@ void scsi_mq_free_tags(struct kref *kref) } /** + * scsi_get_internal_cmd() - Allocate an internal SCSI command. + * @sdev: SCSI device from which to allocate the command + * @data_direction: Data direction for the allocated command + * @flags: request allocation flags, e.g. BLK_MQ_REQ_RESERVED or + * BLK_MQ_REQ_NOWAIT. + * + * Allocates a SCSI command for internal LLDD use. + */ +struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev, + enum dma_data_direction data_direction, + blk_mq_req_flags_t flags) +{ + enum req_op op = data_direction == DMA_TO_DEVICE ? REQ_OP_DRV_OUT : + REQ_OP_DRV_IN; + struct scsi_cmnd *scmd; + struct request *rq; + + rq = scsi_alloc_request(sdev->request_queue, op, flags); + if (IS_ERR(rq)) + return NULL; + scmd = blk_mq_rq_to_pdu(rq); + scmd->device = sdev; + + return scmd; +} +EXPORT_SYMBOL_GPL(scsi_get_internal_cmd); + +/** + * scsi_put_internal_cmd() - Free an internal SCSI command. + * @scmd: SCSI command to be freed + */ +void scsi_put_internal_cmd(struct scsi_cmnd *scmd) +{ + blk_mq_free_request(blk_mq_rq_from_pdu(scmd)); +} +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd); + +/** * scsi_device_from_queue - return sdev associated with a request_queue * @q: The request queue to return the sdev from * @@ -2393,7 +2469,7 @@ EXPORT_SYMBOL(scsi_mode_sense); * @retries: number of retries before failing * @sshdr: outpout pointer for decoded sense information. * - * Returns zero if unsuccessful or an error if TUR failed. For + * Returns zero if successful or an error if TUR failed. For * removable media, UNIT_ATTENTION sets ->changed flag. **/ int @@ -2676,7 +2752,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send); struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, gfp_t gfpflags) { - struct scsi_event *evt = kzalloc(sizeof(struct scsi_event), gfpflags); + struct scsi_event *evt = kzalloc_obj(struct scsi_event, gfpflags); if (!evt) return NULL; @@ -2735,7 +2811,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple); * * Must be called with user context, may sleep. * - * Returns zero if unsuccessful or an error if not. + * Returns zero if successful or an error if not. */ int scsi_device_quiesce(struct scsi_device *sdev) @@ -3148,8 +3224,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, /* Offset starting from the beginning of first page in this sg-entry */ *offset = *offset - len_complete + sg->offset; - /* Assumption: contiguous pages can be accessed as "page + i" */ - page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT)); + page = sg_page(sg) + (*offset >> PAGE_SHIFT); *offset &= ~PAGE_MASK; /* Bytes in this sg-entry from *offset to the end of the page */ @@ -3387,6 +3462,52 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) EXPORT_SYMBOL(scsi_vpd_lun_id); /** + * scsi_vpd_lun_serial - return a unique device serial number + * @sdev: SCSI device + * @sn: buffer for the serial number + * @sn_size: size of the buffer + * + * Copies the device serial number into @sn based on the information in + * the VPD page 0x80 of the device. The string will be null terminated + * and have leading and trailing whitespace stripped. + * + * Returns the length of the serial number or error on failure. + */ +int scsi_vpd_lun_serial(struct scsi_device *sdev, char *sn, size_t sn_size) +{ + const struct scsi_vpd *vpd_pg80; + const unsigned char *d; + int len; + + guard(rcu)(); + vpd_pg80 = rcu_dereference(sdev->vpd_pg80); + if (!vpd_pg80) + return -ENXIO; + + len = vpd_pg80->len - 4; + d = vpd_pg80->data + 4; + + /* Skip leading spaces */ + while (len > 0 && isspace(*d)) { + len--; + d++; + } + + /* Skip trailing spaces */ + while (len > 0 && isspace(d[len - 1])) + len--; + + if (sn_size < len + 1) + return -EINVAL; + + memcpy(sn, d, len); + sn[len] = '\0'; + + return len; +} +EXPORT_SYMBOL(scsi_vpd_lun_serial); + +/** * scsi_vpd_tpg_id - return a target port group identifier * @sdev: SCSI device * @rel_id: pointer to return relative target port in if not %NULL diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index b02af340c2d3..3cd0d3074085 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -26,9 +26,9 @@ static void scsi_log_release_buffer(char *bufptr) kfree(bufptr); } -static inline const char *scmd_name(const struct scsi_cmnd *scmd) +static inline const char *scmd_name(struct scsi_cmnd *scmd) { - struct request *rq = scsi_cmd_to_rq((struct scsi_cmnd *)scmd); + const struct request *rq = scsi_cmd_to_rq(scmd); if (!rq->q || !rq->q->disk) return NULL; @@ -80,8 +80,8 @@ void sdev_prefix_printk(const char *level, const struct scsi_device *sdev, } EXPORT_SYMBOL(sdev_prefix_printk); -void scmd_printk(const char *level, const struct scsi_cmnd *scmd, - const char *fmt, ...) +void scmd_printk(const char *level, struct scsi_cmnd *scmd, const char *fmt, + ...) { va_list args; char *logbuf; @@ -94,7 +94,7 @@ void scmd_printk(const char *level, const struct scsi_cmnd *scmd, if (!logbuf) return; off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd), - scsi_cmd_to_rq((struct scsi_cmnd *)scmd)->tag); + scsi_cmd_to_rq(scmd)->tag); if (off < logbuf_len) { va_start(args, fmt); off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); @@ -371,16 +371,15 @@ void __scsi_print_sense(const struct scsi_device *sdev, const char *name, EXPORT_SYMBOL(__scsi_print_sense); /* Normalize and print sense buffer in SCSI command */ -void scsi_print_sense(const struct scsi_cmnd *cmd) +void scsi_print_sense(struct scsi_cmnd *cmd) { scsi_log_print_sense(cmd->device, scmd_name(cmd), - scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->tag, - cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); + scsi_cmd_to_rq(cmd)->tag, cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE); } EXPORT_SYMBOL(scsi_print_sense); -void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, - int disposition) +void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition) { char *logbuf; size_t off, logbuf_len; @@ -393,7 +392,7 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, return; off = sdev_format_header(logbuf, logbuf_len, scmd_name(cmd), - scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->tag); + scsi_cmd_to_rq(cmd)->tag); if (off >= logbuf_len) goto out_printk; diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index d581613d87c7..2652fecbfe47 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -205,7 +205,6 @@ static int scsi_runtime_idle(struct device *dev) /* Insert hooks here for targets, hosts, and transport classes */ if (scsi_is_sdev_device(dev)) { - pm_runtime_mark_last_busy(dev); pm_runtime_autosuspend(dev); return -EBUSY; } diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 9fc397a9ce7a..7a193cc04e5b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -79,8 +79,6 @@ extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, char *strflags, blist_flags_t flags, enum scsi_devinfo_key key); -extern int scsi_dev_info_list_del_keyed(char *vendor, char *model, - enum scsi_devinfo_key key); extern int scsi_dev_info_add_list(enum scsi_devinfo_key key, const char *name); extern int scsi_dev_info_remove_list(enum scsi_devinfo_key key); @@ -104,7 +102,8 @@ void scsi_eh_done(struct scsi_cmnd *scmd); /* scsi_lib.c */ extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd); -extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); +extern void scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern void scsi_requeue_run_queue(struct work_struct *work); @@ -137,6 +136,7 @@ extern int scsi_complete_async_scans(void); extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int, u64, enum scsi_scan_mode); extern void scsi_forget_host(struct Scsi_Host *); +struct scsi_device *scsi_get_pseudo_sdev(struct Scsi_Host *); /* scsi_sysctl.c */ #ifdef CONFIG_SYSCTL diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 41f23cd0bfb4..1799dcae775c 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -162,7 +162,7 @@ int scsi_proc_hostdir_add(const struct scsi_host_template *sht) mutex_lock(&global_host_template_mutex); e = __scsi_lookup_proc_entry(sht); if (!e) { - e = kzalloc(sizeof(*e), GFP_KERNEL); + e = kzalloc_obj(*e); if (!e) { ret = -ENOMEM; goto unlock; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 96d7e1a9a7c7..ef22a4228b85 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -151,8 +151,9 @@ int scsi_complete_async_scans(void) struct async_scan_data *data; do { - if (list_empty(&scanning_hosts)) - return 0; + scoped_guard(spinlock, &async_scan_lock) + if (list_empty(&scanning_hosts)) + return 0; /* If we can't get memory immediately, that's OK. Just * sleep a little. Even if we never get memory, the async * scans will finish eventually. @@ -346,6 +347,11 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, kref_get(&sdev->host->tagset_refcnt); sdev->request_queue = q; + scsi_sysfs_device_initialize(sdev); + + if (scsi_device_is_pseudo_dev(sdev)) + return sdev; + depth = sdev->host->cmd_per_lun ?: 1; /* @@ -354,16 +360,11 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, * default device queue depth to figure out sbitmap shift * since we use this queue depth most of times. */ - if (scsi_realloc_sdev_budget_map(sdev, depth)) { - put_device(&starget->dev); - kfree(sdev); - goto out; - } + if (scsi_realloc_sdev_budget_map(sdev, depth)) + goto out_device_destroy; scsi_change_queue_depth(sdev, depth); - scsi_sysfs_device_initialize(sdev); - if (shost->hostt->sdev_init) { ret = shost->hostt->sdev_init(sdev); if (ret) { @@ -908,7 +909,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->model = (char *) (sdev->inquiry + 16); sdev->rev = (char *) (sdev->inquiry + 32); - if (strncmp(sdev->vendor, "ATA ", 8) == 0) { + sdev->is_ata = strncmp(sdev->vendor, "ATA ", 8) == 0; + if (sdev->is_ata) { /* * sata emulation layer device. This is a hack to work around * the SATL power management specifications which state that @@ -1066,6 +1068,11 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, transport_configure_device(&sdev->sdev_gendev); + sdev->sdev_bflags = *bflags; + + if (scsi_device_is_pseudo_dev(sdev)) + return SCSI_SCAN_LUN_PRESENT; + /* * No need to freeze the queue as it isn't reachable to anyone else yet. */ @@ -1111,7 +1118,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->max_queue_depth = sdev->queue_depth; WARN_ON_ONCE(sdev->max_queue_depth > sdev->budget_map.depth); - sdev->sdev_bflags = *bflags; /* * Ok, the device is now all set up, we can @@ -1210,6 +1216,12 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (!sdev) goto out; + if (scsi_device_is_pseudo_dev(sdev)) { + if (bflagsp) + *bflagsp = BLIST_NOLUN; + return SCSI_SCAN_LUN_PRESENT; + } + result = kmalloc(result_len, GFP_KERNEL); if (!result) goto out_free_sdev; @@ -1898,7 +1910,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, return 0; } - +EXPORT_SYMBOL(scsi_scan_host_selected); static void scsi_sysfs_add_devices(struct Scsi_Host *shost) { struct scsi_device *sdev; @@ -1928,7 +1940,6 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost) static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) { struct async_scan_data *data = NULL; - unsigned long flags; if (strncmp(scsi_scan_type, "sync", 4) == 0) return NULL; @@ -1939,7 +1950,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) goto err; } - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); if (!data) goto err; data->shost = scsi_host_get(shost); @@ -1947,9 +1958,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) goto err; init_completion(&data->prev_finished); - spin_lock_irqsave(shost->host_lock, flags); - shost->async_scan = 1; - spin_unlock_irqrestore(shost->host_lock, flags); + shost->async_scan = true; mutex_unlock(&shost->scan_mutex); spin_lock(&async_scan_lock); @@ -1977,7 +1986,6 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) static void scsi_finish_async_scan(struct async_scan_data *data) { struct Scsi_Host *shost; - unsigned long flags; if (!data) return; @@ -1997,9 +2005,7 @@ static void scsi_finish_async_scan(struct async_scan_data *data) scsi_sysfs_add_devices(shost); - spin_lock_irqsave(shost->host_lock, flags); - shost->async_scan = 0; - spin_unlock_irqrestore(shost->host_lock, flags); + shost->async_scan = false; mutex_unlock(&shost->scan_mutex); @@ -2081,12 +2087,65 @@ void scsi_forget_host(struct Scsi_Host *shost) restart: spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->sdev_state == SDEV_DEL) + if (scsi_device_is_pseudo_dev(sdev) || + sdev->sdev_state == SDEV_DEL) continue; spin_unlock_irqrestore(shost->host_lock, flags); __scsi_remove_device(sdev); goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * Remove the pseudo device last since it may be needed during removal + * of other SCSI devices. + */ + if (shost->pseudo_sdev) + __scsi_remove_device(shost->pseudo_sdev); } +/** + * scsi_get_pseudo_sdev() - Attach a pseudo SCSI device to a SCSI host + * @shost: Host that needs a pseudo SCSI device + * + * Lock status: None assumed. + * + * Returns: The scsi_device or NULL + * + * Notes: + * Attach a single scsi_device to the Scsi_Host. The primary aim for this + * device is to serve as a container from which SCSI commands can be + * allocated. Each SCSI command will carry a command tag allocated by the + * block layer. These SCSI commands can be used by the LLDD to send + * internal or passthrough commands without having to manage tag allocation + * inside the LLDD. + */ +struct scsi_device *scsi_get_pseudo_sdev(struct Scsi_Host *shost) +{ + struct scsi_device *sdev = NULL; + struct scsi_target *starget; + + guard(mutex)(&shost->scan_mutex); + + if (!scsi_host_scan_allowed(shost)) + goto out; + + starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->max_id); + if (!starget) + goto out; + + sdev = scsi_alloc_sdev(starget, U64_MAX, NULL); + if (!sdev) { + scsi_target_reap(starget); + goto put_target; + } + + sdev->borken = 0; + +put_target: + /* See also the get_device(dev) call in scsi_alloc_target(). */ + put_device(&starget->dev); + +out: + return sdev; +} diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index be4aef0f4f99..055a03a83ad6 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -17,7 +17,9 @@ static const struct ctl_table scsi_table[] = { .data = &scsi_logging_level, .maxlen = sizeof(scsi_logging_level), .mode = 0644, - .proc_handler = proc_dointvec }, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_INT_MAX }, }; static struct ctl_table_header *scsi_table_header; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index d772258e29ad..dfc3559e7e04 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -265,7 +265,7 @@ show_shost_supported_mode(struct device *dev, struct device_attribute *attr, return show_shost_mode(supported_mode, buf); } -static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); +static DEVICE_ATTR(supported_mode, S_IRUGO, show_shost_supported_mode, NULL); static ssize_t show_shost_active_mode(struct device *dev, @@ -279,7 +279,7 @@ show_shost_active_mode(struct device *dev, return show_shost_mode(shost->active_mode, buf); } -static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); +static DEVICE_ATTR(active_mode, S_IRUGO, show_shost_active_mode, NULL); static int check_reset_type(const char *str) { @@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env return 0; } +static int scsi_bus_probe(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->probe) + return drv->probe(sdp); + else + return 0; +} + +static void scsi_bus_remove(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->remove) + drv->remove(sdp); +} + +static void scsi_bus_shutdown(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv; + + if (!dev->driver) + return; + + drv = to_scsi_driver(dev->driver); + + if (drv->shutdown) + drv->shutdown(sdp); +} + + const struct bus_type scsi_bus_type = { - .name = "scsi", - .match = scsi_bus_match, + .name = "scsi", + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif @@ -605,68 +643,6 @@ sdev_show_##field (struct device *dev, struct device_attribute *attr, \ sdev_show_function(field, format_string) \ static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL); - -/* - * sdev_rw_attr: create a function and attribute variable for a - * read/write field. - */ -#define sdev_rw_attr(field, format_string) \ - sdev_show_function(field, format_string) \ - \ -static ssize_t \ -sdev_store_##field (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct scsi_device *sdev; \ - sdev = to_scsi_device(dev); \ - sscanf (buf, format_string, &sdev->field); \ - return count; \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); - -/* Currently we don't export bit fields, but we might in future, - * so leave this code in */ -#if 0 -/* - * sdev_rd_attr: create a function and attribute variable for a - * read/write bit field. - */ -#define sdev_rw_attr_bit(field) \ - sdev_show_function(field, "%d\n") \ - \ -static ssize_t \ -sdev_store_##field (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int ret; \ - struct scsi_device *sdev; \ - ret = scsi_sdev_check_buf_bit(buf); \ - if (ret >= 0) { \ - sdev = to_scsi_device(dev); \ - sdev->field = ret; \ - ret = count; \ - } \ - return ret; \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); - -/* - * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1", - * else return -EINVAL. - */ -static int scsi_sdev_check_buf_bit(const char *buf) -{ - if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) { - if (buf[0] == '1') - return 1; - else if (buf[0] == '0') - return 0; - else - return -EINVAL; - } else - return -EINVAL; -} -#endif /* * Create the actual show/store functions and data structures. */ @@ -710,10 +686,14 @@ static ssize_t sdev_store_timeout (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct scsi_device *sdev; - int timeout; - sdev = to_scsi_device(dev); - sscanf (buf, "%d\n", &timeout); + struct scsi_device *sdev = to_scsi_device(dev); + int ret, timeout; + + ret = kstrtoint(buf, 0, &timeout); + if (ret) + return ret; + if (timeout <= 0) + return -EINVAL; blk_queue_rq_timeout(sdev->request_queue, timeout * HZ); return count; } @@ -917,7 +897,7 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \ static const struct bin_attribute dev_attr_vpd_##_page = { \ .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \ .size = 0, \ - .read_new = show_vpd_##_page, \ + .read = show_vpd_##_page, \ }; sdev_vpd_pg_attr(pg83); @@ -949,7 +929,7 @@ static const struct bin_attribute dev_attr_inquiry = { .mode = S_IRUGO, }, .size = 0, - .read_new = show_inquiry, + .read = show_inquiry, }; static ssize_t @@ -1071,6 +1051,21 @@ sdev_show_wwid(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL); +static ssize_t +sdev_show_serial(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + ssize_t ret; + + ret = scsi_vpd_lun_serial(sdev, buf, PAGE_SIZE - 1); + if (ret < 0) + return ret; + + buf[ret] = '\n'; + return ret + 1; +} +static DEVICE_ATTR(serial, S_IRUGO, sdev_show_serial, NULL); + #define BLIST_FLAG_NAME(name) \ [const_ilog2((__force __u64)BLIST_##name)] = #name static const char *const sdev_bflags_name[] = { @@ -1315,6 +1310,7 @@ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_device_busy.attr, &dev_attr_vendor.attr, &dev_attr_model.attr, + &dev_attr_serial.attr, &dev_attr_rev.attr, &dev_attr_rescan.attr, &dev_attr_delete.attr, @@ -1362,7 +1358,7 @@ static const struct bin_attribute *const scsi_sdev_bin_attrs[] = { }; static struct attribute_group scsi_sdev_attr_group = { .attrs = scsi_sdev_attrs, - .bin_attrs_new = scsi_sdev_bin_attrs, + .bin_attrs = scsi_sdev_bin_attrs, .is_visible = scsi_sdev_attr_is_visible, .is_bin_visible = scsi_sdev_bin_attr_is_visible, }; @@ -1406,6 +1402,9 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) int error; struct scsi_target *starget = sdev->sdev_target; + if (WARN_ON_ONCE(scsi_device_is_pseudo_dev(sdev))) + return -EINVAL; + error = scsi_target_add(starget); if (error) return error; @@ -1513,7 +1512,7 @@ void __scsi_remove_device(struct scsi_device *sdev) kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags); cancel_work_sync(&sdev->requeue_work); - if (sdev->host->hostt->sdev_destroy) + if (!scsi_device_is_pseudo_dev(sdev) && sdev->host->hostt->sdev_destroy) sdev->host->hostt->sdev_destroy(sdev); transport_destroy_device(dev); @@ -1609,11 +1608,44 @@ restart: } EXPORT_SYMBOL(scsi_remove_target); -int __scsi_register_driver(struct device_driver *drv, struct module *owner) +static int scsi_legacy_probe(struct scsi_device *sdp) { + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + return driver->probe(dev); +} + +static void scsi_legacy_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->remove(dev); +} + +static void scsi_legacy_shutdown(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->shutdown(dev); +} + +int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) +{ + struct device_driver *drv = &sdrv->gendrv; + drv->bus = &scsi_bus_type; drv->owner = owner; + if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; + if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; + if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; + return driver_register(drv); } EXPORT_SYMBOL(__scsi_register_driver); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 082f76e76721..dce95e361daf 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/hex.h> #include <linux/kernel.h> #include <linux/bsg-lib.h> #include <scsi/scsi_device.h> @@ -441,18 +442,12 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host->next_vport_number = 0; fc_host->npiv_vports_inuse = 0; - fc_host->work_q = alloc_workqueue("fc_wq_%d", 0, 0, shost->host_no); + fc_host->work_q = alloc_workqueue("fc_wq_%d", WQ_PERCPU, 0, + shost->host_no); if (!fc_host->work_q) return -ENOMEM; fc_host->dev_loss_tmo = fc_dev_loss_tmo; - fc_host->devloss_work_q = alloc_workqueue("fc_dl_%d", 0, 0, - shost->host_no); - if (!fc_host->devloss_work_q) { - destroy_workqueue(fc_host->work_q); - fc_host->work_q = NULL; - return -ENOMEM; - } fc_bsg_hostadd(shost, fc_host); /* ignore any bsg add error - we just can't do sgio */ @@ -1334,6 +1329,46 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); +#define fc_rport_encryption(name) \ +static ssize_t fc_rport_encinfo_##name(struct device *cd, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct fc_rport *rport = transport_class_to_rport(cd); \ + struct Scsi_Host *shost = rport_to_shost(rport); \ + struct fc_internal *i = to_fc_internal(shost->transportt); \ + struct fc_encryption_info *info; \ + ssize_t ret = -ENOENT; \ + u32 data; \ + \ + if (i->f->get_fc_rport_enc_info) { \ + info = (i->f->get_fc_rport_enc_info)(rport); \ + if (info) { \ + data = info->name; \ + if (!strcmp(#name, "status")) { \ + ret = scnprintf(buf, \ + FC_RPORT_ENCRYPTION_STATUS_MAX_LEN, \ + "%s\n", \ + data ? "Encrypted" : "Unencrypted"); \ + } \ + } \ + } \ + return ret; \ +} \ +static FC_DEVICE_ATTR(rport, encryption_##name, 0444, fc_rport_encinfo_##name, NULL) \ + +fc_rport_encryption(status); + +static struct attribute *fc_rport_encryption_attrs[] = { + &device_attr_rport_encryption_status.attr, + NULL +}; + +static struct attribute_group fc_rport_encryption_group = { + .name = "encryption", + .attrs = fc_rport_encryption_attrs, +}; + #define fc_rport_fpin_statistic(name) \ static ssize_t fc_rport_fpinstat_##name(struct device *cd, \ struct device_attribute *attr, \ @@ -2616,8 +2651,7 @@ struct scsi_transport_template * fc_attach_transport(struct fc_function_template *ft) { int count; - struct fc_internal *i = kzalloc(sizeof(struct fc_internal), - GFP_KERNEL); + struct fc_internal *i = kzalloc_obj(struct fc_internal); if (unlikely(!i)) return NULL; @@ -2639,6 +2673,8 @@ fc_attach_transport(struct fc_function_template *ft) i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; i->rport_attr_cont.ac.class = &fc_rport_class.class; i->rport_attr_cont.ac.match = fc_rport_match; + if (ft->get_fc_rport_enc_info) + i->rport_attr_cont.encryption = &fc_rport_encryption_group; i->rport_attr_cont.statistics = &fc_rport_statistics_group; transport_container_register(&i->rport_attr_cont); @@ -2814,6 +2850,7 @@ fc_flush_work(struct Scsi_Host *shost) /** * fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. + * @rport: rport associated with the devloss work * @work: Work to queue for execution. * @delay: jiffies to delay the work queuing * @@ -2821,10 +2858,10 @@ fc_flush_work(struct Scsi_Host *shost) * 1 on success / 0 already queued / < 0 for error */ static int -fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, - unsigned long delay) +fc_queue_devloss_work(struct Scsi_Host *shost, struct fc_rport *rport, + struct delayed_work *work, unsigned long delay) { - if (unlikely(!fc_host_devloss_work_q(shost))) { + if (unlikely(!rport->devloss_work_q)) { printk(KERN_ERR "ERROR: FC host '%s' attempted to queue work, " "when no workqueue created.\n", shost->hostt->name); @@ -2833,17 +2870,18 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, return -EINVAL; } - return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); + return queue_delayed_work(rport->devloss_work_q, work, delay); } /** * fc_flush_devloss - Flush a fc_host's devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. + * @rport: rport associated with the devloss work */ static void -fc_flush_devloss(struct Scsi_Host *shost) +fc_flush_devloss(struct Scsi_Host *shost, struct fc_rport *rport) { - if (!fc_host_devloss_work_q(shost)) { + if (unlikely(!rport->devloss_work_q)) { printk(KERN_ERR "ERROR: FC host '%s' attempted to flush work, " "when no workqueue created.\n", shost->hostt->name); @@ -2851,7 +2889,7 @@ fc_flush_devloss(struct Scsi_Host *shost) return; } - flush_workqueue(fc_host_devloss_work_q(shost)); + flush_workqueue(rport->devloss_work_q); } @@ -2913,13 +2951,6 @@ fc_remove_host(struct Scsi_Host *shost) fc_host->work_q = NULL; destroy_workqueue(work_q); } - - /* flush all devloss work items, then kill it */ - if (fc_host->devloss_work_q) { - work_q = fc_host->devloss_work_q; - fc_host->devloss_work_q = NULL; - destroy_workqueue(work_q); - } } EXPORT_SYMBOL(fc_remove_host); @@ -2967,6 +2998,7 @@ fc_rport_final_delete(struct work_struct *work) struct device *dev = &rport->dev; struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); + struct workqueue_struct *work_q; unsigned long flags; int do_callback = 0; @@ -2988,9 +3020,9 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { spin_unlock_irqrestore(shost->host_lock, flags); if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); cancel_work_sync(&rport->scan_work); spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; @@ -3021,6 +3053,12 @@ fc_rport_final_delete(struct work_struct *work) fc_bsg_remove(rport->rqst_q); + if (rport->devloss_work_q) { + work_q = rport->devloss_work_q; + rport->devloss_work_q = NULL; + destroy_workqueue(work_q); + } + transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); @@ -3093,6 +3131,22 @@ fc_remote_port_create(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + rport->devloss_work_q = alloc_workqueue("fc_dl_%d_%d", WQ_PERCPU, 0, + shost->host_no, rport->number); + if (!rport->devloss_work_q) { + printk(KERN_ERR "FC Remote Port alloc_workqueue failed\n"); +/* + * Note that we have not yet called device_initialize() / get_device() + * Cannot reclaim incremented rport->number because we released host_lock + */ + spin_lock_irqsave(shost->host_lock, flags); + list_del(&rport->peers); + scsi_host_put(shost); /* for fc_host->rport list */ + spin_unlock_irqrestore(shost->host_lock, flags); + kfree(rport); + return NULL; + } + dev = &rport->dev; device_initialize(dev); /* takes self reference */ dev->parent = get_device(&shost->shost_gendev); /* parent reference */ @@ -3255,9 +3309,9 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, * be checked and will NOOP the function. */ if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); spin_lock_irqsave(shost->host_lock, flags); @@ -3451,11 +3505,12 @@ fc_remote_port_delete(struct fc_rport *rport) /* see if we need to kill io faster than waiting for device loss */ if ((rport->fast_io_fail_tmo != -1) && (rport->fast_io_fail_tmo < timeout)) - fc_queue_devloss_work(shost, &rport->fail_io_work, - rport->fast_io_fail_tmo * HZ); + fc_queue_devloss_work(shost, rport, &rport->fail_io_work, + rport->fast_io_fail_tmo * HZ); /* cap the length the devices can be blocked until they are deleted */ - fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); + fc_queue_devloss_work(shost, rport, &rport->dev_loss_work, + timeout * HZ); } EXPORT_SYMBOL(fc_remote_port_delete); @@ -3509,14 +3564,14 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) * state as the LLDD would not have had an rport * reference to pass us. * - * Take no action on the del_timer failure as the state + * Take no action on the timer_delete() failure as the state * machine state change will validate the * transaction. */ if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9c347c64c315..8aa76f813bcd 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2143,6 +2143,8 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) return 0; iscsi_remove_conn(iscsi_dev_to_conn(dev)); + iscsi_put_conn(iscsi_dev_to_conn(dev)); + return 0; } @@ -3182,11 +3184,14 @@ iscsi_set_host_param(struct iscsi_transport *transport, } /* see similar check in iscsi_if_set_param() */ - if (strlen(data) > ev->u.set_host_param.len) - return -EINVAL; + if (strlen(data) > ev->u.set_host_param.len) { + err = -EINVAL; + goto out; + } err = transport->set_host_param(shost, ev->u.set_host_param.param, data, ev->u.set_host_param.len); +out: scsi_host_put(shost); return err; } @@ -3496,7 +3501,7 @@ static int iscsi_new_flashnode(struct iscsi_transport *transport, pr_err("%s could not find host no %u\n", __func__, ev->u.new_flashnode.host_no); err = -ENODEV; - goto put_host; + goto exit_new_fnode; } index = transport->new_flashnode(shost, data, len); @@ -3506,7 +3511,6 @@ static int iscsi_new_flashnode(struct iscsi_transport *transport, else err = -EIO; -put_host: scsi_host_put(shost); exit_new_fnode: @@ -3531,7 +3535,7 @@ static int iscsi_del_flashnode(struct iscsi_transport *transport, pr_err("%s could not find host no %u\n", __func__, ev->u.del_flashnode.host_no); err = -ENODEV; - goto put_host; + goto exit_del_fnode; } idx = ev->u.del_flashnode.flashnode_idx; @@ -3573,7 +3577,7 @@ static int iscsi_login_flashnode(struct iscsi_transport *transport, pr_err("%s could not find host no %u\n", __func__, ev->u.login_flashnode.host_no); err = -ENODEV; - goto put_host; + goto exit_login_fnode; } idx = ev->u.login_flashnode.flashnode_idx; @@ -3625,7 +3629,7 @@ static int iscsi_logout_flashnode(struct iscsi_transport *transport, pr_err("%s could not find host no %u\n", __func__, ev->u.logout_flashnode.host_no); err = -ENODEV; - goto put_host; + goto exit_logout_fnode; } idx = ev->u.logout_flashnode.flashnode_idx; @@ -3675,7 +3679,7 @@ static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport, pr_err("%s could not find host no %u\n", __func__, ev->u.logout_flashnode.host_no); err = -ENODEV; - goto put_host; + goto exit_logout_sid; } session = iscsi_session_lookup(ev->u.logout_flashnode_sid.sid); @@ -3957,7 +3961,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) list_del_init(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); - queue_work(system_unbound_wq, &session->destroy_work); + queue_work(system_dfl_wq, &session->destroy_work); } break; case ISCSI_UEVENT_UNBIND_SESSION: @@ -4844,7 +4848,7 @@ iscsi_register_transport(struct iscsi_transport *tt) if (priv) return NULL; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 351b028ef893..13412702188e 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -40,6 +40,8 @@ #include <scsi/scsi_transport_sas.h> #include "scsi_sas_internal.h" +#include "scsi_priv.h" + struct sas_host_attrs { struct list_head rphy_list; struct mutex lock; @@ -710,7 +712,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) struct Scsi_Host *shost = dev_to_shost(parent); struct sas_phy *phy; - phy = kzalloc(sizeof(*phy), GFP_KERNEL); + phy = kzalloc_obj(*phy); if (!phy) return NULL; @@ -905,7 +907,7 @@ struct sas_port *sas_port_alloc(struct device *parent, int port_id) struct Scsi_Host *shost = dev_to_shost(parent); struct sas_port *port; - port = kzalloc(sizeof(*port), GFP_KERNEL); + port = kzalloc_obj(*port); if (!port) return NULL; @@ -1465,7 +1467,7 @@ struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) struct Scsi_Host *shost = dev_to_shost(&parent->dev); struct sas_end_device *rdev; - rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + rdev = kzalloc_obj(*rdev); if (!rdev) { return NULL; } @@ -1509,7 +1511,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent, BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE && type != SAS_FANOUT_EXPANDER_DEVICE); - rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + rdev = kzalloc_obj(*rdev); if (!rdev) { return NULL; } @@ -1683,32 +1685,66 @@ int scsi_is_sas_rphy(const struct device *dev) } EXPORT_SYMBOL(scsi_is_sas_rphy); - -/* - * SCSI scan helper - */ - -static int sas_user_scan(struct Scsi_Host *shost, uint channel, - uint id, u64 lun) +static void scan_channel_zero(struct Scsi_Host *shost, uint id, u64 lun) { struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); struct sas_rphy *rphy; - mutex_lock(&sas_host->lock); list_for_each_entry(rphy, &sas_host->rphy_list, list) { if (rphy->identify.device_type != SAS_END_DEVICE || rphy->scsi_target_id == -1) continue; - if ((channel == SCAN_WILD_CARD || channel == 0) && - (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { + if (id == SCAN_WILD_CARD || id == rphy->scsi_target_id) { scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun, SCSI_SCAN_MANUAL); } } - mutex_unlock(&sas_host->lock); +} - return 0; +/* + * SCSI scan helper + */ + +static int sas_user_scan(struct Scsi_Host *shost, uint channel, + uint id, u64 lun) +{ + struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); + int res = 0; + int i; + + switch (channel) { + case 0: + mutex_lock(&sas_host->lock); + scan_channel_zero(shost, id, lun); + mutex_unlock(&sas_host->lock); + break; + + case SCAN_WILD_CARD: + mutex_lock(&sas_host->lock); + scan_channel_zero(shost, id, lun); + mutex_unlock(&sas_host->lock); + + for (i = 1; i <= shost->max_channel; i++) { + res = scsi_scan_host_selected(shost, i, id, lun, + SCSI_SCAN_MANUAL); + if (res) + goto exit_scan; + } + break; + + default: + if (channel <= shost->max_channel) { + res = scsi_scan_host_selected(shost, channel, id, lun, + SCSI_SCAN_MANUAL); + } else { + res = -EINVAL; + } + break; + } + +exit_scan: + return res; } @@ -1779,7 +1815,7 @@ sas_attach_transport(struct sas_function_template *ft) struct sas_internal *i; int count; - i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); + i = kzalloc_obj(struct sas_internal); if (!i) return NULL; diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index fe47850a8258..3e3da8c2ff26 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1096,7 +1096,7 @@ void spi_schedule_dv_device(struct scsi_device *sdev) { struct work_queue_wrapper *wqw = - kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); + kmalloc_obj(struct work_queue_wrapper, GFP_ATOMIC); if (unlikely(!wqw)) return; @@ -1570,8 +1570,7 @@ static int spi_target_configure(struct transport_container *tc, struct scsi_transport_template * spi_attach_transport(struct spi_function_template *ft) { - struct spi_internal *i = kzalloc(sizeof(struct spi_internal), - GFP_KERNEL); + struct spi_internal *i = kzalloc_obj(struct spi_internal); if (unlikely(!i)) return NULL; @@ -1622,7 +1621,7 @@ static __init int spi_transport_init(void) error = transport_class_register(&spi_transport_class); if (error) return error; - error = anon_transport_class_register(&spi_device_class); + anon_transport_class_register(&spi_device_class); return transport_class_register(&spi_host_class); } diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 64f6b22e8cc0..d71ab5fdb758 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -388,7 +388,7 @@ static void srp_reconnect_work(struct work_struct *work) "reconnect attempt %d failed (%d)\n", ++rport->failed_reconnects, res); delay = rport->reconnect_delay * - min(100, max(1, rport->failed_reconnects - 10)); + clamp(rport->failed_reconnects - 10, 1, 100); if (delay > 0) queue_delayed_work(system_long_wq, &rport->reconnect_work, delay * HZ); @@ -700,7 +700,7 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, struct srp_internal *i = to_srp_internal(shost->transportt); int id, ret; - rport = kzalloc(sizeof(*rport), GFP_KERNEL); + rport = kzalloc_obj(*rport); if (!rport) return ERR_PTR(-ENOMEM); @@ -814,7 +814,7 @@ srp_attach_transport(struct srp_function_template *ft) int count; struct srp_internal *i; - i = kzalloc(sizeof(*i), GFP_KERNEL); + i = kzalloc_obj(*i); if (!i) return NULL; diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 19e6c3852d50..887de505bcf9 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -30,9 +30,9 @@ * starting at offset %0x1be. * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error. */ -unsigned char *scsi_bios_ptable(struct block_device *dev) +unsigned char *scsi_bios_ptable(struct gendisk *dev) { - struct address_space *mapping = bdev_whole(dev)->bd_mapping; + struct address_space *mapping = dev->part0->bd_mapping; unsigned char *res = NULL; struct folio *folio; @@ -48,7 +48,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); /** * scsi_partsize - Parse cylinders/heads/sectors from PC partition table - * @bdev: block device to parse + * @disk: gendisk of the disk to parse * @capacity: size of the disk in sectors * @geom: output in form of [hds, cylinders, sectors] * @@ -57,7 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); * * Returns: %false on failure, %true on success. */ -bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]) +bool scsi_partsize(struct gendisk *disk, sector_t capacity, int geom[3]) { int cyl, ext_cyl, end_head, end_cyl, end_sector; unsigned int logical_end, physical_end, ext_physical_end; @@ -65,7 +65,7 @@ bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]) void *buf; int ret = false; - buf = scsi_bios_ptable(bdev); + buf = scsi_bios_ptable(disk); if (!buf) return false; @@ -205,7 +205,7 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds /** * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors. - * @bdev: which device + * @disk: which device * @capacity: size of the disk in sectors * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders * @@ -215,13 +215,13 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds * * Returns : -1 on failure, 0 on success. */ -int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) +int scsicam_bios_param(struct gendisk *disk, sector_t capacity, int *ip) { u64 capacity64 = capacity; /* Suppress gcc warning */ int ret = 0; /* try to infer mapping from partition table */ - if (scsi_partsize(bdev, capacity, ip)) + if (scsi_partsize(disk, capacity, ip)) return 0; if (capacity64 < (1ULL << 32)) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 950d8c9fb884..599e75f33334 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -102,18 +102,16 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); #define SD_MINORS 16 -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode); static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); -static int sd_revalidate_disk(struct gendisk *); -static void sd_unlock_native_capacity(struct gendisk *disk); -static void sd_shutdown(struct device *); -static void scsi_disk_release(struct device *cdev); +static void sd_revalidate_disk(struct gendisk *); static DEFINE_IDA(sd_index_ida); +static DEFINE_MUTEX(sd_mutex_lock); static mempool_t *sd_page_pool; +static mempool_t *sd_large_page_pool; +static atomic_t sd_large_page_pool_users = ATOMIC_INIT(0); static struct lock_class_key sd_bio_compl_lkclass; static const char *sd_cache_types[] = { @@ -121,6 +119,89 @@ static const char *sd_cache_types[] = { "write back, no read (daft)" }; +static int sd_large_pool_create(void) +{ + mutex_lock(&sd_mutex_lock); + if (!sd_large_page_pool) { + sd_large_page_pool = mempool_create_page_pool( + SD_MEMPOOL_SIZE, get_order(BLK_MAX_BLOCK_SIZE)); + if (!sd_large_page_pool) { + printk(KERN_ERR "sd: can't create large page mempool\n"); + mutex_unlock(&sd_mutex_lock); + return -ENOMEM; + } + } + atomic_inc(&sd_large_page_pool_users); + mutex_unlock(&sd_mutex_lock); + return 0; +} + +static void sd_large_pool_destroy(void) +{ + mutex_lock(&sd_mutex_lock); + if (atomic_dec_and_test(&sd_large_page_pool_users)) { + mempool_destroy(sd_large_page_pool); + sd_large_page_pool = NULL; + } + mutex_unlock(&sd_mutex_lock); +} + +static void sd_disable_discard(struct scsi_disk *sdkp) +{ + sdkp->provisioning_mode = SD_LBP_DISABLE; + blk_queue_disable_discard(sdkp->disk->queue); +} + +static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, + unsigned int mode) +{ + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int max_blocks = 0; + + lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; + lim->discard_granularity = max(sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + sdkp->provisioning_mode = mode; + + switch (mode) { + + case SD_LBP_FULL: + case SD_LBP_DISABLE: + break; + + case SD_LBP_UNMAP: + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS16: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS10: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); + break; + + case SD_LBP_ZERO: + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + break; + } + + lim->max_hw_discard_sectors = max_blocks * + (logical_block_size >> SECTOR_SHIFT); +} + static void sd_set_flush_flag(struct scsi_disk *sdkp, struct queue_limits *lim) { @@ -318,6 +399,35 @@ static ssize_t manage_shutdown_store(struct device *dev, } static DEVICE_ATTR_RW(manage_shutdown); +static ssize_t manage_restart_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + + return sysfs_emit(buf, "%u\n", sdp->manage_restart); +} + +static ssize_t manage_restart_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + bool v; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (kstrtobool(buf, &v)) + return -EINVAL; + + sdp->manage_restart = v; + + return count; +} +static DEVICE_ATTR_RW(manage_restart); + static ssize_t allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -654,6 +764,7 @@ static struct attribute *sd_disk_attrs[] = { &dev_attr_manage_system_start_stop.attr, &dev_attr_manage_runtime_start_stop.attr, &dev_attr_manage_shutdown.attr, + &dev_attr_manage_restart.attr, &dev_attr_protection_type.attr, &dev_attr_protection_mode.attr, &dev_attr_app_tag_own.attr, @@ -668,6 +779,17 @@ static struct attribute *sd_disk_attrs[] = { }; ATTRIBUTE_GROUPS(sd_disk); +static void scsi_disk_release(struct device *dev) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + ida_free(&sd_index_ida, sdkp->index); + put_device(&sdkp->device->sdev_gendev); + free_opal_dev(sdkp->opal_dev); + + kfree(sdkp); +} + static struct class sd_disk_class = { .name = "scsi_disk", .dev_release = scsi_disk_release, @@ -836,70 +958,24 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, return protect; } -static void sd_disable_discard(struct scsi_disk *sdkp) -{ - sdkp->provisioning_mode = SD_LBP_DISABLE; - blk_queue_disable_discard(sdkp->disk->queue); -} - -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode) -{ - unsigned int logical_block_size = sdkp->device->sector_size; - unsigned int max_blocks = 0; - - lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; - lim->discard_granularity = max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); - sdkp->provisioning_mode = mode; - - switch (mode) { - - case SD_LBP_FULL: - case SD_LBP_DISABLE: - break; - - case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, - (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS16: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS10: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); - break; - - case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, - (u32)SD_MAX_WS10_BLOCKS); - break; - } - - lim->max_hw_discard_sectors = max_blocks * - (logical_block_size >> SECTOR_SHIFT); -} - -static void *sd_set_special_bvec(struct request *rq, unsigned int data_len) +static void *sd_set_special_bvec(struct scsi_cmnd *cmd, unsigned int data_len) { struct page *page; + struct request *rq = scsi_cmd_to_rq(cmd); + struct scsi_device *sdp = cmd->device; + unsigned sector_size = sdp->sector_size; + unsigned int nr_pages = DIV_ROUND_UP(sector_size, PAGE_SIZE); + int n; - page = mempool_alloc(sd_page_pool, GFP_ATOMIC); + if (sector_size > PAGE_SIZE) + page = mempool_alloc(sd_large_page_pool, GFP_ATOMIC); + else + page = mempool_alloc(sd_page_pool, GFP_ATOMIC); if (!page) return NULL; - clear_highpage(page); + + for (n = 0; n < nr_pages; n++) + clear_highpage(page + n); bvec_set_page(&rq->special_vec, page, data_len, 0); rq->rq_flags |= RQF_SPECIAL_PAYLOAD; return bvec_virt(&rq->special_vec); @@ -915,7 +991,7 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd) unsigned int data_len = 24; char *buf; - buf = sd_set_special_bvec(rq, data_len); + buf = sd_set_special_bvec(cmd, data_len); if (!buf) return BLK_STS_RESOURCE; @@ -1004,7 +1080,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); u32 data_len = sdp->sector_size; - if (!sd_set_special_bvec(rq, data_len)) + if (!sd_set_special_bvec(cmd, data_len)) return BLK_STS_RESOURCE; cmd->cmd_len = 16; @@ -1031,7 +1107,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); u32 data_len = sdp->sector_size; - if (!sd_set_special_bvec(rq, data_len)) + if (!sd_set_special_bvec(cmd, data_len)) return BLK_STS_RESOURCE; cmd->cmd_len = 10; @@ -1141,6 +1217,11 @@ static void sd_config_write_same(struct scsi_disk *sdkp, out: lim->max_write_zeroes_sectors = sdkp->max_ws_blocks * (logical_block_size >> SECTOR_SHIFT); + + if (sdkp->zeroing_mode == SD_ZERO_WS16_UNMAP || + sdkp->zeroing_mode == SD_ZERO_WS10_UNMAP) + lim->max_hw_wzeroes_unmap_sectors = + lim->max_write_zeroes_sectors; } static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) @@ -1472,9 +1553,15 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) static void sd_uninit_command(struct scsi_cmnd *SCpnt) { struct request *rq = scsi_cmd_to_rq(SCpnt); + struct scsi_device *sdp = SCpnt->device; + unsigned sector_size = sdp->sector_size; - if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) - mempool_free(rq->special_vec.bv_page, sd_page_pool); + if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) { + if (sector_size > PAGE_SIZE) + mempool_free(rq->special_vec.bv_page, sd_large_page_pool); + else + mempool_free(rq->special_vec.bv_page, sd_page_pool); + } } static bool sd_need_revalidate(struct gendisk *disk, struct scsi_disk *sdkp) @@ -1594,9 +1681,9 @@ static void sd_release(struct gendisk *disk) scsi_device_put(sdev); } -static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int sd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; struct Scsi_Host *host = sdp->host; sector_t capacity = logical_to_sectors(sdp, sdkp->capacity); @@ -1609,9 +1696,9 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) /* override with calculated, extended default, or driver values */ if (host->hostt->bios_param) - host->hostt->bios_param(sdp, bdev, capacity, diskinfo); + host->hostt->bios_param(sdp, disk, capacity, diskinfo); else - scsicam_bios_param(bdev, capacity, diskinfo); + scsicam_bios_param(disk, capacity, diskinfo); geo->heads = diskinfo[0]; geo->sectors = diskinfo[1]; @@ -1641,9 +1728,10 @@ static int sd_ioctl(struct block_device *bdev, blk_mode_t mode, struct scsi_device *sdp = sdkp->device; void __user *p = (void __user *)arg; int error; - - SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " - "cmd=0x%x\n", disk->disk_name, cmd)); + + SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, + "sd_ioctl: disk=%s, cmd=0x%x\n", + disk->disk_name, cmd)); if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) return -ENOIOCTLCMD; @@ -1969,9 +2057,19 @@ static int sd_pr_read_keys(struct block_device *bdev, struct pr_keys *keys_info) { int result, i, data_offset, num_copy_keys; u32 num_keys = keys_info->num_keys; - int data_len = num_keys * 8 + 8; + int data_len; u8 *data; + /* + * Each reservation key takes 8 bytes and there is an 8-byte header + * before the reservation key list. The total size must fit into the + * 16-bit ALLOCATION LENGTH field. + */ + if (check_mul_overflow(num_keys, 8, &data_len) || + check_add_overflow(data_len, 8, &data_len) || + data_len > USHRT_MAX) + return -EINVAL; + data = kzalloc(data_len, GFP_KERNEL); if (!data) return -ENOMEM; @@ -2132,21 +2230,6 @@ static void scsi_disk_free_disk(struct gendisk *disk) put_device(&sdkp->disk_dev); } -static const struct block_device_operations sd_fops = { - .owner = THIS_MODULE, - .open = sd_open, - .release = sd_release, - .ioctl = sd_ioctl, - .getgeo = sd_getgeo, - .compat_ioctl = blkdev_compat_ptr_ioctl, - .check_events = sd_check_events, - .unlock_native_capacity = sd_unlock_native_capacity, - .report_zones = sd_zbc_report_zones, - .get_unique_id = sd_get_unique_id, - .free_disk = scsi_disk_free_disk, - .pr_ops = &sd_pr_ops, -}; - /** * sd_eh_reset - reset error handling callback * @scmd: sd-issued command that has failed @@ -2393,8 +2476,7 @@ sd_spinup_disk(struct scsi_disk *sdkp) { static const u8 cmd[10] = { TEST_UNIT_READY }; unsigned long spintime_expire = 0; - int spintime, sense_valid = 0; - unsigned int the_result; + int the_result, spintime, sense_valid = 0; struct scsi_sense_hdr sshdr; struct scsi_failure failure_defs[] = { /* Do not retry Medium Not Present */ @@ -2557,8 +2639,8 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ if (type > T10_PI_TYPE3_PROTECTION) { - sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ - " protection type %u. Disabling disk!\n", + sd_printk(KERN_ERR, sdkp, + "formatted with unsupported protection type %u. Disabling disk!\n", type); sdkp->protection_type = 0; return -ENODEV; @@ -2835,8 +2917,8 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, if ((sizeof(sdkp->capacity) > 4) && (sdkp->capacity > 0xffffffffULL)) { int old_sector_size = sector_size; - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); + sd_printk(KERN_NOTICE, sdkp, + "Very big device. Trying to use READ CAPACITY(16).\n"); sector_size = read_capacity_16(sdkp, sdp, lim, buffer); if (sector_size < 0) { sd_printk(KERN_NOTICE, sdkp, @@ -2862,23 +2944,20 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, */ if (sdp->fix_capacity || (sdp->guess_capacity && (sdkp->capacity & 0x01))) { - sd_printk(KERN_INFO, sdkp, "Adjusting the sector count " - "from its reported value: %llu\n", - (unsigned long long) sdkp->capacity); + sd_printk(KERN_INFO, sdkp, + "Adjusting the sector count from its reported value: %llu\n", + (unsigned long long) sdkp->capacity); --sdkp->capacity; } got_data: if (sector_size == 0) { sector_size = 512; - sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " - "assuming 512.\n"); + sd_printk(KERN_NOTICE, sdkp, + "Sector size 0 reported, assuming 512.\n"); } - if (sector_size != 512 && - sector_size != 1024 && - sector_size != 2048 && - sector_size != 4096) { + if (blk_validate_block_size(sector_size)) { sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n", sector_size); /* @@ -3077,8 +3156,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (len < 3) goto bad_sense; else if (len > SD_BUF_SIZE) { - sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " - "data from %d to %d bytes\n", len, SD_BUF_SIZE); + sd_first_printk(KERN_NOTICE, sdkp, + "Truncating mode parameter data from %d to %d bytes\n", + len, SD_BUF_SIZE); len = SD_BUF_SIZE; } if (modepage == 0x3F && sdp->use_192_bytes_for_3f) @@ -3101,8 +3181,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) */ if (len - offset <= 2) { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode parameter " - "data\n"); + "Incomplete mode parameter data\n"); goto defaults; } else { modepage = page_code; @@ -3117,8 +3196,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) offset += 2 + buffer[offset+1]; else { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode " - "parameter data\n"); + "Incomplete mode parameter data\n"); goto defaults; } } @@ -3215,7 +3293,7 @@ static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int stream_id) return false; if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status)) return false; - return buf.h.stream_status[0].perm; + return buf.s.perm; } static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) @@ -3384,7 +3462,7 @@ static void sd_read_block_limits_ext(struct scsi_disk *sdkp) rcu_read_lock(); vpd = rcu_dereference(sdkp->device->vpd_pgb7); - if (vpd && vpd->len >= 2) + if (vpd && vpd->len >= 6) sdkp->rscs = vpd->data[5] & 1; rcu_read_unlock(); } @@ -3459,19 +3537,14 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) } if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY, 0) < 0) { - struct scsi_vpd *vpd; - sdev->no_report_opcodes = 1; - /* Disable WRITE SAME if REPORT SUPPORTED OPERATION - * CODES is unsupported and the device has an ATA - * Information VPD page (SAT). + /* + * Disable WRITE SAME if REPORT SUPPORTED OPERATION CODES is + * unsupported and this is an ATA device. */ - rcu_read_lock(); - vpd = rcu_dereference(sdev->vpd_pg89); - if (vpd) + if (sdev->is_ata) sdev->no_write_same = 1; - rcu_read_unlock(); } if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16, 0) == 1) @@ -3586,8 +3659,7 @@ static bool sd_validate_min_xfer_size(struct scsi_disk *sdkp) if (min_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Preferred minimum I/O size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Preferred minimum I/O size %u bytes not a multiple of physical block size (%u bytes)\n", min_xfer_bytes, sdkp->physical_block_size); sdkp->min_xfer_blocks = 0; return false; @@ -3617,41 +3689,35 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp, if (sdkp->opt_xfer_blocks > dev_max) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> dev_max (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > dev_max (%u logical blocks)\n", sdkp->opt_xfer_blocks, dev_max); return false; } if (sdkp->opt_xfer_blocks > SD_DEF_XFER_BLOCKS) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> sd driver limit (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > sd driver limit (%u logical blocks)\n", sdkp->opt_xfer_blocks, SD_DEF_XFER_BLOCKS); return false; } if (opt_xfer_bytes < PAGE_SIZE) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes < " \ - "PAGE_SIZE (%u bytes)\n", + "Optimal transfer size %u bytes < PAGE_SIZE (%u bytes)\n", opt_xfer_bytes, (unsigned int)PAGE_SIZE); return false; } if (min_xfer_bytes && opt_xfer_bytes % min_xfer_bytes) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of preferred minimum block " \ - "size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of preferred minimum block size (%u bytes)\n", opt_xfer_bytes, min_xfer_bytes); return false; } if (opt_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of physical block size (%u bytes)\n", opt_xfer_bytes, sdkp->physical_block_size); return false; } @@ -3691,13 +3757,13 @@ static void sd_read_block_zero(struct scsi_disk *sdkp) * performs disk spin up, read_capacity, etc. * @disk: struct gendisk we care about **/ -static int sd_revalidate_disk(struct gendisk *disk) +static void sd_revalidate_disk(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; sector_t old_capacity = sdkp->capacity; - struct queue_limits lim; - unsigned char *buffer; + struct queue_limits *lim = NULL; + unsigned char *buffer = NULL; unsigned int dev_max; int err; @@ -3709,25 +3775,26 @@ static int sd_revalidate_disk(struct gendisk *disk) * of the other niceties. */ if (!scsi_device_online(sdp)) - goto out; + return; + + lim = kmalloc_obj(*lim); + if (!lim) + return; buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL); - if (!buffer) { - sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory " - "allocation failure.\n"); + if (!buffer) goto out; - } sd_spinup_disk(sdkp); - lim = queue_limits_start_update(sdkp->disk->queue); + *lim = queue_limits_start_update(sdkp->disk->queue); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { - sd_read_capacity(sdkp, &lim, buffer); + sd_read_capacity(sdkp, lim, buffer); /* * Some USB/UAS devices return generic values for mode pages * until the media has been accessed. Trigger a READ operation @@ -3741,17 +3808,17 @@ static int sd_revalidate_disk(struct gendisk *disk) * cause this to be updated correctly and any device which * doesn't support it should be treated as rotational. */ - lim.features |= (BLK_FEAT_ROTATIONAL | BLK_FEAT_ADD_RANDOM); + lim->features |= (BLK_FEAT_ROTATIONAL | BLK_FEAT_ADD_RANDOM); if (scsi_device_supports_vpd(sdp)) { sd_read_block_provisioning(sdkp); - sd_read_block_limits(sdkp, &lim); + sd_read_block_limits(sdkp, lim); sd_read_block_limits_ext(sdkp); - sd_read_block_characteristics(sdkp, &lim); - sd_zbc_read_zones(sdkp, &lim, buffer); + sd_read_block_characteristics(sdkp, lim); + sd_zbc_read_zones(sdkp, lim, buffer); } - sd_config_discard(sdkp, &lim, sd_discard_mode(sdkp)); + sd_config_discard(sdkp, lim, sd_discard_mode(sdkp)); sd_print_capacity(sdkp, old_capacity); @@ -3761,47 +3828,46 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); - sd_config_protection(sdkp, &lim); + sd_config_protection(sdkp, lim); } /* * We now have all cache related info, determine how we deal * with flush requests. */ - sd_set_flush_flag(sdkp, &lim); + sd_set_flush_flag(sdkp, lim); /* Initial block count limit based on CDB TRANSFER LENGTH field size. */ dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS; /* Some devices report a maximum block count for READ/WRITE requests. */ dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks); - lim.max_dev_sectors = logical_to_sectors(sdp, dev_max); + lim->max_dev_sectors = logical_to_sectors(sdp, dev_max); if (sd_validate_min_xfer_size(sdkp)) - lim.io_min = logical_to_bytes(sdp, sdkp->min_xfer_blocks); + lim->io_min = logical_to_bytes(sdp, sdkp->min_xfer_blocks); else - lim.io_min = 0; + lim->io_min = 0; /* * Limit default to SCSI host optimal sector limit if set. There may be * an impact on performance for when the size of a request exceeds this * host limit. */ - lim.io_opt = sdp->host->opt_sectors << SECTOR_SHIFT; + lim->io_opt = sdp->host->opt_sectors << SECTOR_SHIFT; if (sd_validate_opt_xfer_size(sdkp, dev_max)) { - lim.io_opt = min_not_zero(lim.io_opt, + lim->io_opt = min_not_zero(lim->io_opt, logical_to_bytes(sdp, sdkp->opt_xfer_blocks)); } sdkp->first_scan = 0; set_capacity_and_notify(disk, logical_to_sectors(sdp, sdkp->capacity)); - sd_config_write_same(sdkp, &lim); - kfree(buffer); + sd_config_write_same(sdkp, lim); - err = queue_limits_commit_update_frozen(sdkp->disk->queue, &lim); + err = queue_limits_commit_update_frozen(sdkp->disk->queue, lim); if (err) - return err; + goto out; /* * Query concurrent positioning ranges after @@ -3820,7 +3886,9 @@ static int sd_revalidate_disk(struct gendisk *disk) set_capacity_and_notify(disk, 0); out: - return 0; + kfree(buffer); + kfree(lim); + } /** @@ -3843,6 +3911,21 @@ static void sd_unlock_native_capacity(struct gendisk *disk) sdev->host->hostt->unlock_native_capacity(sdev); } +static const struct block_device_operations sd_fops = { + .owner = THIS_MODULE, + .open = sd_open, + .release = sd_release, + .ioctl = sd_ioctl, + .getgeo = sd_getgeo, + .compat_ioctl = blkdev_compat_ptr_ioctl, + .check_events = sd_check_events, + .unlock_native_capacity = sd_unlock_native_capacity, + .report_zones = sd_zbc_report_zones, + .get_unique_id = sd_get_unique_id, + .free_disk = scsi_disk_free_disk, + .pr_ops = &sd_pr_ops, +}; + /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks @@ -3893,7 +3976,7 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. - * @dev: pointer to device object + * @sdp: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error. @@ -3907,9 +3990,9 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * Assume sd_probe is not re-entrant (for time being) * Also think about sd_probe() and sd_remove() running coincidentally. **/ -static int sd_probe(struct device *dev) +static int sd_probe(struct scsi_device *sdp) { - struct scsi_device *sdp = to_scsi_device(dev); + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp; struct gendisk *gd; int index; @@ -3933,7 +4016,7 @@ static int sd_probe(struct device *dev) "sd_probe\n")); error = -ENOMEM; - sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); + sdkp = kzalloc_obj(*sdkp); if (!sdkp) goto out; @@ -3977,6 +4060,7 @@ static int sd_probe(struct device *dev) error = device_add(&sdkp->disk_dev); if (error) { put_device(&sdkp->disk_dev); + put_disk(gd); goto out; } @@ -4002,6 +4086,12 @@ static int sd_probe(struct device *dev) sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; sd_revalidate_disk(gd); + if (sdp->sector_size > PAGE_SIZE) { + if (sd_large_pool_create()) { + error = -ENOMEM; + goto out_free_index; + } + } if (sdp->removable) { gd->flags |= GENHD_FL_REMOVABLE; @@ -4019,6 +4109,8 @@ static int sd_probe(struct device *dev) if (error) { device_unregister(&sdkp->disk_dev); put_disk(gd); + if (sdp->sector_size > PAGE_SIZE) + sd_large_pool_destroy(); goto out; } @@ -4045,43 +4137,6 @@ static int sd_probe(struct device *dev) return error; } -/** - * sd_remove - called whenever a scsi disk (previously recognized by - * sd_probe) is detached from the system. It is called (potentially - * multiple times) during sd module unload. - * @dev: pointer to device object - * - * Note: this function is invoked from the scsi mid-level. - * This function potentially frees up a device name (e.g. /dev/sdc) - * that could be re-used by a subsequent sd_probe(). - * This function is not called when the built-in sd driver is "exit-ed". - **/ -static int sd_remove(struct device *dev) -{ - struct scsi_disk *sdkp = dev_get_drvdata(dev); - - scsi_autopm_get_device(sdkp->device); - - device_del(&sdkp->disk_dev); - del_gendisk(sdkp->disk); - if (!sdkp->suspended) - sd_shutdown(dev); - - put_disk(sdkp->disk); - return 0; -} - -static void scsi_disk_release(struct device *dev) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - ida_free(&sd_index_ida, sdkp->index); - put_device(&sdkp->device->sdev_gendev); - free_opal_dev(sdkp->opal_dev); - - kfree(sdkp); -} - static int sd_start_stop_device(struct scsi_disk *sdkp, int start) { unsigned char cmd[6] = { START_STOP }; /* START_VALID */ @@ -4155,8 +4210,9 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) * the normal SCSI command structure. Wait for the command to * complete. */ -static void sd_shutdown(struct device *dev) +static void sd_shutdown(struct scsi_device *sdp) { + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp = dev_get_drvdata(dev); if (!sdkp) @@ -4173,12 +4229,45 @@ static void sd_shutdown(struct device *dev) if ((system_state != SYSTEM_RESTART && sdkp->device->manage_system_start_stop) || (system_state == SYSTEM_POWER_OFF && - sdkp->device->manage_shutdown)) { + sdkp->device->manage_shutdown) || + (system_state == SYSTEM_RUNNING && + sdkp->device->manage_runtime_start_stop) || + (system_state == SYSTEM_RESTART && + sdkp->device->manage_restart)) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); sd_start_stop_device(sdkp, 0); } } +/** + * sd_remove - called whenever a scsi disk (previously recognized by + * sd_probe) is detached from the system. It is called (potentially + * multiple times) during sd module unload. + * @sdp: pointer to device object + * + * Note: this function is invoked from the scsi mid-level. + * This function potentially frees up a device name (e.g. /dev/sdc) + * that could be re-used by a subsequent sd_probe(). + * This function is not called when the built-in sd driver is "exit-ed". + **/ +static void sd_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + scsi_autopm_get_device(sdkp->device); + + device_del(&sdkp->disk_dev); + del_gendisk(sdkp->disk); + if (!sdkp->suspended) + sd_shutdown(sdp); + + put_disk(sdkp->disk); + + if (sdp->sector_size > PAGE_SIZE) + sd_large_pool_destroy(); +} + static inline bool sd_do_start_stop(struct scsi_device *sdev, bool runtime) { return (sdev->manage_system_start_stop && !runtime) || @@ -4322,12 +4411,12 @@ static const struct dev_pm_ops sd_pm_ops = { }; static struct scsi_driver sd_template = { + .probe = sd_probe, + .remove = sd_remove, + .shutdown = sd_shutdown, .gendrv = { .name = "sd", - .probe = sd_probe, .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .remove = sd_remove, - .shutdown = sd_shutdown, .pm = &sd_pm_ops, }, .rescan = sd_rescan, @@ -4371,7 +4460,7 @@ static int __init init_sd(void) goto err_out_class; } - err = scsi_register_driver(&sd_template.gendrv); + err = scsi_register_driver(&sd_template); if (err) goto err_out_driver; @@ -4398,8 +4487,10 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); - scsi_unregister_driver(&sd_template.gendrv); + scsi_unregister_driver(&sd_template); mempool_destroy(sd_page_pool); + if (sd_large_page_pool) + mempool_destroy(sd_large_page_pool); class_unregister(&sd_disk_class); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 36382eca941c..574af8243016 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -240,7 +240,7 @@ blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, struct scsi_sense_hdr *sshdr); int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, - unsigned int nr_zones, report_zones_cb cb, void *data); + unsigned int nr_zones, struct blk_report_zones_args *args); #else /* CONFIG_BLK_DEV_ZONED */ diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index ae6ce6f5d622..ff4217fef93b 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -52,7 +52,8 @@ void sd_dif_config_host(struct scsi_disk *sdkp, struct queue_limits *lim) if (type != T10_PI_TYPE3_PROTECTION) bi->flags |= BLK_INTEGRITY_REF_TAG; - bi->tuple_size = sizeof(struct t10_pi_tuple); + bi->metadata_size = sizeof(struct t10_pi_tuple); + bi->pi_tuple_size = bi->metadata_size; if (dif && type) { bi->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 7a447ff600d2..56e455fb5add 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -35,8 +35,7 @@ static bool sd_zbc_is_gap_zone(const u8 buf[64]) * @buf: SCSI zone descriptor. * @idx: Index of the zone relative to the first zone reported by the current * sd_zbc_report_zones() call. - * @cb: Callback function pointer. - * @data: Second argument passed to @cb. + * @args: report zones arguments (callback, etc) * * Return: Value returned by @cb. * @@ -44,12 +43,11 @@ static bool sd_zbc_is_gap_zone(const u8 buf[64]) * call @cb(blk_zone, @data). */ static int sd_zbc_parse_report(struct scsi_disk *sdkp, const u8 buf[64], - unsigned int idx, report_zones_cb cb, void *data) + unsigned int idx, struct blk_report_zones_args *args) { struct scsi_device *sdp = sdkp->device; struct blk_zone zone = { 0 }; sector_t start_lba, gran; - int ret; if (WARN_ON_ONCE(sd_zbc_is_gap_zone(buf))) return -EINVAL; @@ -87,11 +85,7 @@ static int sd_zbc_parse_report(struct scsi_disk *sdkp, const u8 buf[64], else zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); - ret = cb(&zone, idx, data); - if (ret) - return ret; - - return 0; + return disk_report_zone(sdkp->disk, &zone, idx, args); } /** @@ -169,6 +163,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, unsigned int nr_zones, size_t *buflen) { struct request_queue *q = sdkp->disk->queue; + unsigned int max_segments; size_t bufsize; void *buf; @@ -180,12 +175,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, * Furthermore, since the report zone command cannot be split, make * sure that the allocated buffer can always be mapped by limiting the * number of pages allocated to the HBA max segments limit. + * Since max segments can be larger than the max inline bio vectors, + * further limit the allocated buffer to BIO_MAX_INLINE_VECS. */ nr_zones = min(nr_zones, sdkp->zone_info.nr_zones); bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE); bufsize = min_t(size_t, bufsize, queue_max_hw_sectors(q) << SECTOR_SHIFT); - bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); + max_segments = min(BIO_MAX_INLINE_VECS, queue_max_segments(q)); + bufsize = min_t(size_t, bufsize, max_segments << PAGE_SHIFT); while (bufsize >= SECTOR_SIZE) { buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY); @@ -213,14 +211,14 @@ static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) * @disk: Disk to report zones for. * @sector: Start sector. * @nr_zones: Maximum number of zones to report. - * @cb: Callback function called to report zone information. - * @data: Second argument passed to @cb. + * @args: Callback arguments. * * Called by the block layer to iterate over zone information. See also the * disk->fops->report_zones() calls in block/blk-zoned.c. */ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, - unsigned int nr_zones, report_zones_cb cb, void *data) + unsigned int nr_zones, + struct blk_report_zones_args *args) { struct scsi_disk *sdkp = scsi_disk(disk); sector_t lba = sectors_to_logical(sdkp->device, sector); @@ -279,7 +277,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, } ret = sd_zbc_parse_report(sdkp, buf + offset, zone_idx, - cb, data); + args); if (ret) goto out; diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 2c61624cb4b0..4c348645b04e 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -42,9 +42,8 @@ static bool ses_page2_supported(struct enclosure_device *edev) return (ses_dev->page2 != NULL); } -static int ses_probe(struct device *dev) +static int ses_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); int err = -ENODEV; if (sdev->type != TYPE_ENCLOSURE) @@ -216,7 +215,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, unsigned char *type_ptr = ses_dev->page1_types; unsigned char *desc_ptr = ses_dev->page2 + 8; - if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0) + if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len)) return NULL; for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { @@ -529,9 +528,8 @@ struct efd { }; static int ses_enclosure_find_by_addr(struct enclosure_device *edev, - void *data) + struct efd *efd) { - struct efd *efd = data; int i; struct ses_component *scomp; @@ -684,7 +682,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, if (efd.addr) { efd.dev = &sdev->sdev_gendev; - enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); + ses_enclosure_find_by_addr(edev, &efd); } } @@ -716,7 +714,7 @@ static int ses_intf_add(struct device *cdev) if (sdev->type != TYPE_ENCLOSURE) sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); - ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); + ses_dev = kzalloc_obj(*ses_dev); hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); if (!hdr_buf || !ses_dev) goto err_init_free; @@ -800,7 +798,7 @@ static int ses_intf_add(struct device *cdev) } page2_not_supported: if (components > 0) { - scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); + scomp = kzalloc_objs(struct ses_component, components); if (!scomp) goto err_free; } @@ -847,11 +845,6 @@ page2_not_supported: return err; } -static int ses_remove(struct device *dev) -{ - return 0; -} - static void ses_intf_remove_component(struct scsi_device *sdev) { struct enclosure_device *edev, *prev = NULL; @@ -906,10 +899,9 @@ static struct class_interface ses_interface = { }; static struct scsi_driver ses_template = { + .probe = ses_probe, .gendrv = { .name = "ses", - .probe = ses_probe, - .remove = ses_remove, }, }; @@ -921,7 +913,7 @@ static int __init ses_init(void) if (err) return err; - err = scsi_register_driver(&ses_template.gendrv); + err = scsi_register_driver(&ses_template); if (err) goto out_unreg; @@ -934,7 +926,7 @@ static int __init ses_init(void) static void __exit ses_exit(void) { - scsi_unregister_driver(&ses_template.gendrv); + scsi_unregister_driver(&ses_template); scsi_unregister_interface(&ses_interface); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index effb7e768165..74cd4e8a61c2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -81,14 +81,14 @@ static int sg_proc_init(void); #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ) -static int sg_big_buff = SG_DEF_RESERVED_SIZE; /* N.B. This variable is readable and writeable via - /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer - of this size (or less if there is not enough memory) will be reserved - for use by this file descriptor. [Deprecated usage: this variable is also - readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into - the kernel (i.e. it is not a module).] */ -static int def_reserved_size = -1; /* picks up init parameter */ + * /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer + * of this size (or less if there is not enough memory) will be reserved + * for use by this file descriptor. + */ + +/* picks up init parameter */ +static int def_reserved_size = SG_DEF_RESERVED_SIZE; static int sg_allow_dio = SG_ALLOW_DIO_DEF; static int scatter_elem_sz = SG_SCATTER_SZ; @@ -177,7 +177,8 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ } Sg_device; /* tasklet or soft irq callback */ -static enum rq_end_io_ret sg_rq_end_io(struct request *rq, blk_status_t status); +static enum rq_end_io_ret sg_rq_end_io(struct request *rq, blk_status_t status, + const struct io_comp_batch *iob); static int sg_start_req(Sg_request *srp, unsigned char *cmd); static int sg_finish_rem_req(Sg_request * srp); static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); @@ -731,6 +732,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } + hp->duration = jiffies_to_msecs(jiffies); + if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; @@ -815,7 +818,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return -ENODEV; } - hp->duration = jiffies_to_msecs(jiffies); if (hp->interface_id != '\0' && /* v3 (or later) interface */ (SG_FLAG_Q_AT_TAIL & hp->flags)) at_head = 0; @@ -1235,8 +1237,7 @@ sg_vma_fault(struct vm_fault *vmf) len = vma->vm_end - sa; len = (len < length) ? len : length; if (offset < len) { - struct page *page = nth_page(rsv_schp->pages[k], - offset >> PAGE_SHIFT); + struct page *page = rsv_schp->pages[k] + (offset >> PAGE_SHIFT); get_page(page); /* increment page count */ vmf->page = page; return 0; /* success */ @@ -1309,7 +1310,8 @@ sg_rq_end_io_usercontext(struct work_struct *work) * level when a command is completed (or has failed). */ static enum rq_end_io_ret -sg_rq_end_io(struct request *rq, blk_status_t status) +sg_rq_end_io(struct request *rq, blk_status_t status, + const struct io_comp_batch *iob) { struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); struct sg_request *srp = rq->end_io_data; @@ -1339,9 +1341,6 @@ sg_rq_end_io(struct request *rq, blk_status_t status) "sg_cmd_done: pack_id=%d, res=0x%x\n", srp->header.pack_id, result)); srp->header.resid = resid; - ms = jiffies_to_msecs(jiffies); - srp->header.duration = (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; if (0 != result) { struct scsi_sense_hdr sshdr; @@ -1390,6 +1389,9 @@ sg_rq_end_io(struct request *rq, blk_status_t status) done = 0; } srp->done = done; + ms = jiffies_to_msecs(jiffies); + srp->header.duration = (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (likely(done)) { @@ -1434,7 +1436,7 @@ sg_alloc(struct scsi_device *scsidp) int error; u32 k; - sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); + sdp = kzalloc_obj(Sg_device); if (!sdp) { sdev_printk(KERN_WARNING, scsidp, "%s: kmalloc Sg_device " "failure\n", __func__); @@ -1621,10 +1623,35 @@ sg_remove_device(struct device *cl_dev) } module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); -module_param_named(def_reserved_size, def_reserved_size, int, - S_IRUGO | S_IWUSR); module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); +static int def_reserved_size_set(const char *val, const struct kernel_param *kp) +{ + int size, ret; + + if (!val) + return -EINVAL; + + ret = kstrtoint(val, 0, &size); + if (ret) + return ret; + + /* limit to 1 MB */ + if (size < 0 || size > 1048576) + return -ERANGE; + + def_reserved_size = size; + return 0; +} + +static const struct kernel_param_ops def_reserved_size_ops = { + .set = def_reserved_size_set, + .get = param_get_int, +}; + +module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, + S_IRUGO | S_IWUSR); + MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); MODULE_LICENSE("GPL"); @@ -1636,36 +1663,6 @@ MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); -#ifdef CONFIG_SYSCTL -#include <linux/sysctl.h> - -static const struct ctl_table sg_sysctls[] = { - { - .procname = "sg-big-buff", - .data = &sg_big_buff, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, -}; - -static struct ctl_table_header *hdr; -static void register_sg_sysctls(void) -{ - if (!hdr) - hdr = register_sysctl("kernel", sg_sysctls); -} - -static void unregister_sg_sysctls(void) -{ - if (hdr) - unregister_sysctl_table(hdr); -} -#else -#define register_sg_sysctls() do { } while (0) -#define unregister_sg_sysctls() do { } while (0) -#endif /* CONFIG_SYSCTL */ - static int __init init_sg(void) { @@ -1675,10 +1672,6 @@ init_sg(void) scatter_elem_sz = PAGE_SIZE; scatter_elem_sz_prev = scatter_elem_sz; } - if (def_reserved_size >= 0) - sg_big_buff = def_reserved_size; - else - def_reserved_size = sg_big_buff; rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); @@ -1696,7 +1689,6 @@ init_sg(void) return 0; } class_unregister(&sg_sysfs_class); - register_sg_sysctls(); err_out: unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); return rc; @@ -1705,7 +1697,6 @@ err_out: static void __exit exit_sg(void) { - unregister_sg_sysctls(); #ifdef CONFIG_SCSI_PROC_FS remove_proc_subtree("scsi/sg", NULL); #endif /* CONFIG_SCSI_PROC_FS */ @@ -1810,7 +1801,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) } res = blk_rq_map_user_io(rq, md, hp->dxferp, hp->dxfer_len, - GFP_ATOMIC, iov_count, iov_count, 1, rw); + GFP_KERNEL, iov_count, iov_count, 1, rw); if (!res) { srp->bio = rq->bio; @@ -2156,7 +2147,7 @@ sg_add_sfp(Sg_device * sdp) unsigned long iflags; int bufflen; - sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); + sfp = kzalloc_obj(*sfp, GFP_ATOMIC | __GFP_NOWARN); if (!sfp) return ERR_PTR(-ENOMEM); @@ -2181,10 +2172,8 @@ sg_add_sfp(Sg_device * sdp) write_unlock_irqrestore(&sdp->sfd_lock, iflags); SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_add_sfp: sfp=0x%p\n", sfp)); - if (unlikely(sg_big_buff != def_reserved_size)) - sg_big_buff = def_reserved_size; - bufflen = min_t(int, sg_big_buff, + bufflen = min_t(int, def_reserved_size, max_sectors_bytes(sdp->device->request_queue)); sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, @@ -2210,9 +2199,17 @@ sg_remove_sfp_usercontext(struct work_struct *work) write_lock_irqsave(&sfp->rq_list_lock, iflags); while (!list_empty(&sfp->rq_list)) { srp = list_first_entry(&sfp->rq_list, Sg_request, entry); - sg_finish_rem_req(srp); list_del(&srp->entry); + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + + sg_finish_rem_req(srp); + /* + * sg_rq_end_io() uses srp->parentfp. Hence, only clear + * srp->parentfp after blk_mq_free_request() has been called. + */ srp->parentfp = NULL; + + write_lock_irqsave(&sfp->rq_list_lock, iflags); } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); @@ -2404,7 +2401,7 @@ sg_proc_write_adio(struct file *filp, const char __user *buffer, static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) { - return single_open(file, sg_proc_seq_show_int, &sg_big_buff); + return single_open(file, sg_proc_seq_show_int, &def_reserved_size); } static ssize_t @@ -2421,7 +2418,7 @@ sg_proc_write_dressz(struct file *filp, const char __user *buffer, if (err) return err; if (k <= 1048576) { /* limit "big buff" to 1 MB */ - sg_big_buff = k; + def_reserved_size = k; return count; } return -ERANGE; @@ -2447,7 +2444,7 @@ struct sg_proc_deviter { static void * dev_seq_start(struct seq_file *s, loff_t *pos) { - struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL); + struct sg_proc_deviter * it = kmalloc_obj(*it); s->private = it; if (! it) @@ -2527,6 +2524,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) const sg_io_hdr_t *hp; const char * cp; unsigned int ms; + unsigned int duration; k = 0; list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { @@ -2564,13 +2562,17 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - seq_printf(s, " dur=%d", hp->duration); + seq_printf(s, " dur=%u", hp->duration); else { ms = jiffies_to_msecs(jiffies); - seq_printf(s, " t_o/elap=%d/%d", + duration = READ_ONCE(hp->duration); + if (duration) + duration = (ms > duration ? + ms - duration : 0); + seq_printf(s, " t_o/elap=%u/%u", (new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout)), - (ms > hp->duration ? ms - hp->duration : 0)); + duration); } seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); @@ -2589,7 +2591,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) if (it && (0 == it->index)) seq_printf(s, "max_active_device=%d def_reserved_size=%d\n", - (int)it->max, sg_big_buff); + (int)it->max, def_reserved_size); read_lock_irqsave(&sg_index_lock, iflags); sdp = it ? sg_lookup_dev(it->index) : NULL; diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index e519df68d603..408f37003748 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -87,7 +87,7 @@ static int sim710_probe_common(struct device *dev, unsigned long base_addr, { struct Scsi_Host * host = NULL; struct NCR_700_Host_Parameters *hostdata = - kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + kzalloc_obj(struct NCR_700_Host_Parameters); printk(KERN_NOTICE "sim710: %s\n", dev_name(dev)); printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", @@ -133,6 +133,7 @@ static int sim710_probe_common(struct device *dev, unsigned long base_addr, out_put_host: scsi_host_put(host); out_release: + ioport_unmap(hostdata->base); release_region(base_addr, 64); out_free: kfree(hostdata); @@ -148,6 +149,7 @@ static int sim710_device_remove(struct device *dev) scsi_remove_host(host); NCR_700_release(host); + ioport_unmap(hostdata->base); kfree(hostdata); free_irq(host->irq, host); release_region(host->base, 64); diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 0da7be40c925..2026ac645d6a 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -19,6 +19,8 @@ #include <linux/bcd.h> #include <linux/reboot.h> #include <linux/cciss_ioctl.h> +#include <linux/crash_dump.h> +#include <linux/string.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -32,11 +34,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "2.1.30-031" +#define DRIVER_VERSION "2.1.36-026" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 1 -#define DRIVER_RELEASE 30 -#define DRIVER_REVISION 31 +#define DRIVER_RELEASE 36 +#define DRIVER_REVISION 26 #define DRIVER_NAME "Microchip SmartPQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -67,6 +69,7 @@ static struct pqi_cmd_priv *pqi_cmd_priv(struct scsi_cmnd *cmd) static void pqi_verify_structures(void); static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason); +static void pqi_take_ctrl_devices_offline(struct pqi_ctrl_info *ctrl_info); static void pqi_ctrl_offline_worker(struct work_struct *work); static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info); static void pqi_scan_start(struct Scsi_Host *shost); @@ -885,7 +888,7 @@ static int pqi_get_advanced_raid_bypass_config(struct pqi_ctrl_info *ctrl_info) struct pqi_raid_path_request request; struct bmic_sense_feature_buffer *buffer; - buffer = kmalloc(sizeof(*buffer), GFP_KERNEL); + buffer = kmalloc_obj(*buffer); if (!buffer) return -ENOMEM; @@ -950,7 +953,7 @@ static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info, int rc; struct bmic_flush_cache *flush_cache; - flush_cache = kzalloc(sizeof(*flush_cache), GFP_KERNEL); + flush_cache = kzalloc_obj(*flush_cache); if (!flush_cache) return -ENOMEM; @@ -979,7 +982,7 @@ static int pqi_set_diag_rescan(struct pqi_ctrl_info *ctrl_info) int rc; struct bmic_diag_options *diag; - diag = kzalloc(sizeof(*diag), GFP_KERNEL); + diag = kzalloc_obj(*diag); if (!diag) return -ENOMEM; @@ -1161,7 +1164,7 @@ static int pqi_report_phys_logical_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd, void *lun_data = NULL; struct report_lun_header *report_lun_header; - report_lun_header = kmalloc(sizeof(*report_lun_header), GFP_KERNEL); + report_lun_header = kmalloc_obj(*report_lun_header); if (!report_lun_header) { rc = -ENOMEM; goto out; @@ -1238,7 +1241,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b dev_err(&ctrl_info->pci_dev->dev, "RPL returned unsupported data format %u\n", rpl_response_format); - return -EINVAL; + rc = -EINVAL; + goto out_free_rpl_list; } else { dev_warn(&ctrl_info->pci_dev->dev, "RPL returned extended format 2 instead of 4\n"); @@ -1248,10 +1252,12 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b rpl_8byte_wwid_list = rpl_list; num_physicals = get_unaligned_be32(&rpl_8byte_wwid_list->header.list_length) / sizeof(rpl_8byte_wwid_list->lun_entries[0]); - rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, - num_physicals), GFP_KERNEL); - if (!rpl_16byte_wwid_list) - return -ENOMEM; + rpl_16byte_wwid_list = kmalloc_flex(*rpl_16byte_wwid_list, lun_entries, + num_physicals); + if (!rpl_16byte_wwid_list) { + rc = -ENOMEM; + goto out_free_rpl_list; + } put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), &rpl_16byte_wwid_list->header.list_length); @@ -1272,6 +1278,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b *buffer = rpl_16byte_wwid_list; return 0; + +out_free_rpl_list: + kfree(rpl_list); + return rc; } static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) @@ -1468,7 +1478,7 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info, u32 raid_map_size; struct raid_map *raid_map; - raid_map = kmalloc(sizeof(*raid_map), GFP_KERNEL); + raid_map = kmalloc_obj(*raid_map); if (!raid_map) return -ENOMEM; @@ -1606,7 +1616,7 @@ static void pqi_get_volume_status(struct pqi_ctrl_info *ctrl_info, u32 volume_flags; struct ciss_vpd_logical_volume_status *vpd; - vpd = kmalloc(sizeof(*vpd), GFP_KERNEL); + vpd = kmalloc_obj(*vpd); if (!vpd) goto no_buffer; @@ -2010,18 +2020,31 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info, PQI_DEV_INFO_BUFFER_LENGTH - count, "-:-"); - if (pqi_is_logical_device(device)) + if (pqi_is_logical_device(device)) { count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %08x%08x", *((u32 *)&device->scsi3addr), *((u32 *)&device->scsi3addr[4])); - else + } else if (ctrl_info->rpl_extended_format_4_5_supported) { + if (device->device_type == SA_DEVICE_TYPE_NVME) + count += scnprintf(buffer + count, + PQI_DEV_INFO_BUFFER_LENGTH - count, + " %016llx%016llx", + get_unaligned_be64(&device->wwid[0]), + get_unaligned_be64(&device->wwid[8])); + else + count += scnprintf(buffer + count, + PQI_DEV_INFO_BUFFER_LENGTH - count, + " %016llx", + get_unaligned_be64(&device->wwid[0])); + } else { count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, - " %016llx%016llx", - get_unaligned_be64(&device->wwid[0]), - get_unaligned_be64(&device->wwid[8])); + " %016llx", + get_unaligned_be64(&device->wwid[0])); + } + count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %s %.8s %.16s ", @@ -2424,7 +2447,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) * pqi_get_physical_disk_info() because it's a fairly large * buffer. */ - id_phys = kmalloc(sizeof(*id_phys), GFP_KERNEL); + id_phys = kmalloc_obj(*id_phys); if (!id_phys) { dev_warn(&ctrl_info->pci_dev->dev, "%s\n", out_of_memory_msg); @@ -2449,9 +2472,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) num_new_devices = num_physicals + num_logicals; - new_device_list = kmalloc_array(num_new_devices, - sizeof(*new_device_list), - GFP_KERNEL); + new_device_list = kmalloc_objs(*new_device_list, num_new_devices); if (!new_device_list) { dev_warn(&ctrl_info->pci_dev->dev, "%s\n", out_of_memory_msg); rc = -ENOMEM; @@ -2459,7 +2480,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) } for (i = 0; i < num_new_devices; i++) { - device = kzalloc(sizeof(*device), GFP_KERNEL); + device = kzalloc_obj(*device); if (!device) { dev_warn(&ctrl_info->pci_dev->dev, "%s\n", out_of_memory_msg); @@ -3810,7 +3831,8 @@ static void pqi_heartbeat_timer_handler(struct timer_list *t) { int num_interrupts; u32 heartbeat_count; - struct pqi_ctrl_info *ctrl_info = from_timer(ctrl_info, t, heartbeat_timer); + struct pqi_ctrl_info *ctrl_info = timer_container_of(ctrl_info, t, + heartbeat_timer); pqi_check_ctrl_health(ctrl_info); if (pqi_ctrl_offline(ctrl_info)) @@ -3853,7 +3875,7 @@ static void pqi_start_heartbeat_timer(struct pqi_ctrl_info *ctrl_info) static inline void pqi_stop_heartbeat_timer(struct pqi_ctrl_info *ctrl_info) { - del_timer_sync(&ctrl_info->heartbeat_timer); + timer_delete_sync(&ctrl_info->heartbeat_timer); } static void pqi_ofa_capture_event_payload(struct pqi_ctrl_info *ctrl_info, @@ -4727,7 +4749,7 @@ static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info) struct pqi_device_capability *capability; struct pqi_iu_layer_descriptor *sop_iu_layer_descriptor; - capability = kmalloc(sizeof(*capability), GFP_KERNEL); + capability = kmalloc_obj(*capability); if (!capability) return -ENOMEM; @@ -5183,8 +5205,8 @@ static int pqi_alloc_io_resources(struct pqi_ctrl_info *ctrl_info) struct device *dev; struct pqi_io_request *io_request; - ctrl_info->io_request_pool = kcalloc(ctrl_info->max_io_slots, - sizeof(ctrl_info->io_request_pool[0]), GFP_KERNEL); + ctrl_info->io_request_pool = kzalloc_objs(ctrl_info->io_request_pool[0], + ctrl_info->max_io_slots); if (!ctrl_info->io_request_pool) { dev_err(&ctrl_info->pci_dev->dev, @@ -5246,7 +5268,7 @@ static void pqi_calculate_io_resources(struct pqi_ctrl_info *ctrl_info) ctrl_info->error_buffer_length = ctrl_info->max_io_slots * PQI_ERROR_BUFFER_ELEMENT_LENGTH; - if (reset_devices) + if (is_kdump_kernel()) max_transfer_size = min(ctrl_info->max_transfer_size, PQI_MAX_TRANSFER_SIZE_KDUMP); else @@ -5275,18 +5297,17 @@ static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info) u16 num_elements_per_iq; u16 num_elements_per_oq; - if (reset_devices) { + if (is_kdump_kernel()) { num_queue_groups = 1; } else { - int num_cpus; int max_queue_groups; max_queue_groups = min(ctrl_info->max_inbound_queues / 2, ctrl_info->max_outbound_queues - 1); max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS); - num_cpus = num_online_cpus(); - num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors); + num_queue_groups = + blk_mq_num_online_queues(ctrl_info->max_msix_vectors); num_queue_groups = min(num_queue_groups, max_queue_groups); } @@ -5539,14 +5560,25 @@ static void pqi_raid_io_complete(struct pqi_io_request *io_request, pqi_scsi_done(scmd); } +/* + * Adjust the timeout value for physical devices sent to the firmware + * by subtracting 3 seconds for timeouts greater than or equal to 8 seconds. + * + * This provides the firmware with additional time to attempt early recovery + * before the OS-level timeout occurs. + */ +#define ADJUST_SECS_TIMEOUT_VALUE(tv) (((tv) >= 8) ? ((tv) - 3) : (tv)) + static int pqi_raid_submit_io(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, struct scsi_cmnd *scmd, struct pqi_queue_group *queue_group, bool io_high_prio) { int rc; + u32 timeout; size_t cdb_length; struct pqi_io_request *io_request; struct pqi_raid_path_request *request; + struct request *rq; io_request = pqi_alloc_io_request(ctrl_info, scmd); if (!io_request) @@ -5618,6 +5650,12 @@ static int pqi_raid_submit_io(struct pqi_ctrl_info *ctrl_info, return SCSI_MLQUEUE_HOST_BUSY; } + if (device->is_physical_device) { + rq = scsi_cmd_to_rq(scmd); + timeout = rq->timeout / HZ; + put_unaligned_le32(ADJUST_SECS_TIMEOUT_VALUE(timeout), &request->timeout); + } + pqi_start_io(ctrl_info, queue_group, RAID_PATH, io_request); return 0; @@ -5989,7 +6027,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, pqi_stream_data->next_lba = rmd.first_block + rmd.block_cnt; pqi_stream_data->last_accessed = jiffies; - per_cpu_ptr(device->raid_io_stats, smp_processor_id())->write_stream_cnt++; + per_cpu_ptr(device->raid_io_stats, raw_smp_processor_id())->write_stream_cnt++; return true; } @@ -6014,7 +6052,8 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, return false; } -static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status pqi_scsi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { int rc; struct pqi_ctrl_info *ctrl_info; @@ -6068,7 +6107,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) { raid_bypassed = true; - per_cpu_ptr(device->raid_io_stats, smp_processor_id())->raid_bypass_cnt++; + per_cpu_ptr(device->raid_io_stats, raw_smp_processor_id())->raid_bypass_cnt++; } } if (!raid_bypassed) @@ -6394,10 +6433,22 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev static int pqi_device_reset_handler(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, u8 lun, struct scsi_cmnd *scmd, u8 scsi_opcode) { + unsigned long flags; int rc; mutex_lock(&ctrl_info->lun_reset_mutex); + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + if (pqi_find_scsi_dev(ctrl_info, device->bus, device->target, device->lun) == NULL) { + dev_warn(&ctrl_info->pci_dev->dev, + "skipping reset of scsi %d:%d:%d:%u, device has been removed\n", + ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + mutex_unlock(&ctrl_info->lun_reset_mutex); + return 0; + } + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + dev_err(&ctrl_info->pci_dev->dev, "resetting scsi %d:%d:%d:%u SCSI cmd at %p due to cmd opcode 0x%02x\n", ctrl_info->scsi_host->host_no, device->bus, device->target, lun, scmd, scsi_opcode); @@ -6578,7 +6629,9 @@ static void pqi_sdev_destroy(struct scsi_device *sdev) { struct pqi_ctrl_info *ctrl_info; struct pqi_scsi_dev *device; + struct pqi_tmf_work *tmf_work; int mutex_acquired; + unsigned int lun; unsigned long flags; ctrl_info = shost_to_hba(sdev->host); @@ -6605,8 +6658,13 @@ static void pqi_sdev_destroy(struct scsi_device *sdev) mutex_unlock(&ctrl_info->scan_mutex); + for (lun = 0, tmf_work = device->tmf_work; lun < PQI_MAX_LUNS_PER_DEVICE; lun++, tmf_work++) + cancel_work_sync(&tmf_work->work_struct); + + mutex_lock(&ctrl_info->lun_reset_mutex); pqi_dev_info(ctrl_info, "removed", device); pqi_free_device(device); + mutex_unlock(&ctrl_info->lun_reset_mutex); } static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) @@ -6759,17 +6817,15 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) } if (iocommand.buf_size > 0) { - kernel_buffer = kmalloc(iocommand.buf_size, GFP_KERNEL); - if (!kernel_buffer) - return -ENOMEM; if (iocommand.Request.Type.Direction & XFER_WRITE) { - if (copy_from_user(kernel_buffer, iocommand.buf, - iocommand.buf_size)) { - rc = -EFAULT; - goto out; - } + kernel_buffer = memdup_user(iocommand.buf, + iocommand.buf_size); + if (IS_ERR(kernel_buffer)) + return PTR_ERR(kernel_buffer); } else { - memset(kernel_buffer, 0, iocommand.buf_size); + kernel_buffer = kzalloc(iocommand.buf_size, GFP_KERNEL); + if (!kernel_buffer) + return -ENOMEM; } } @@ -7688,7 +7744,7 @@ static int pqi_get_ctrl_serial_number(struct pqi_ctrl_info *ctrl_info) int rc; struct bmic_sense_subsystem_info *sense_info; - sense_info = kzalloc(sizeof(*sense_info), GFP_KERNEL); + sense_info = kzalloc_obj(*sense_info); if (!sense_info) return -ENOMEM; @@ -7711,7 +7767,7 @@ static int pqi_get_ctrl_product_details(struct pqi_ctrl_info *ctrl_info) int rc; struct bmic_identify_controller *identify; - identify = kmalloc(sizeof(*identify), GFP_KERNEL); + identify = kmalloc_obj(*identify); if (!identify) return -ENOMEM; @@ -8288,12 +8344,12 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) u32 product_id; if (reset_devices) { - if (pqi_is_fw_triage_supported(ctrl_info)) { + if (is_kdump_kernel() && pqi_is_fw_triage_supported(ctrl_info)) { rc = sis_wait_for_fw_triage_completion(ctrl_info); if (rc) return rc; } - if (sis_is_ctrl_logging_supported(ctrl_info)) { + if (is_kdump_kernel() && sis_is_ctrl_logging_supported(ctrl_info)) { sis_notify_kdump(ctrl_info); rc = sis_wait_for_ctrl_logging_completion(ctrl_info); if (rc) @@ -8344,7 +8400,7 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) ctrl_info->product_id = (u8)product_id; ctrl_info->product_revision = (u8)(product_id >> 8); - if (reset_devices) { + if (is_kdump_kernel()) { if (ctrl_info->max_outstanding_requests > PQI_MAX_OUTSTANDING_REQUESTS_KDUMP) ctrl_info->max_outstanding_requests = @@ -8480,7 +8536,7 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) if (rc) return rc; - if (ctrl_info->ctrl_logging_supported && !reset_devices) { + if (ctrl_info->ctrl_logging_supported && !is_kdump_kernel()) { pqi_host_setup_buffer(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_CTRL_LOG_TOTAL_SIZE, PQI_CTRL_LOG_MIN_SIZE); pqi_host_memory_update(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE); } @@ -8922,7 +8978,8 @@ static int pqi_host_alloc_mem(struct pqi_ctrl_info *ctrl_info, if (sg_count == 0 || sg_count > PQI_HOST_MAX_SG_DESCRIPTORS) goto out; - host_memory_descriptor->host_chunk_virt_address = kmalloc(sg_count * sizeof(void *), GFP_KERNEL); + host_memory_descriptor->host_chunk_virt_address = + kmalloc_array(sg_count, sizeof(void *), GFP_KERNEL); if (!host_memory_descriptor->host_chunk_virt_address) goto out; @@ -9128,6 +9185,7 @@ static void pqi_take_ctrl_offline_deferred(struct pqi_ctrl_info *ctrl_info) pqi_ctrl_wait_until_quiesced(ctrl_info); pqi_fail_all_outstanding_requests(ctrl_info); pqi_ctrl_unblock_requests(ctrl_info); + pqi_take_ctrl_devices_offline(ctrl_info); } static void pqi_ctrl_offline_worker(struct work_struct *work) @@ -9202,6 +9260,27 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, schedule_work(&ctrl_info->ctrl_offline_work); } +static void pqi_take_ctrl_devices_offline(struct pqi_ctrl_info *ctrl_info) +{ + int rc; + unsigned long flags; + struct pqi_scsi_dev *device; + + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + list_for_each_entry(device, &ctrl_info->scsi_device_list, scsi_device_list_entry) { + rc = list_is_last(&device->scsi_device_list_entry, &ctrl_info->scsi_device_list); + if (rc) + continue; + + /* + * Is the sdev pointer NULL? + */ + if (device->sdev) + scsi_device_set_state(device->sdev, SDEV_OFFLINE); + } + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); +} + static void pqi_print_ctrl_info(struct pci_dev *pci_dev, const struct pci_device_id *id) { @@ -9348,6 +9427,7 @@ static void pqi_shutdown(struct pci_dev *pci_dev) pqi_crash_if_pending_command(ctrl_info); pqi_reset(ctrl_info); + pqi_ctrl_unblock_device_reset(ctrl_info); } static void pqi_process_lockup_action_param(void) @@ -9710,6 +9790,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x00a3) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1ff9, 0x00a1) }, { @@ -10046,6 +10130,34 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4044) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4054) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4084) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4094) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4140) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4240) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4840) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADVANTECH, 0x8312) }, { @@ -10262,6 +10374,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1018, 0x8238) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1f3f, 0x0610) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_LENOVO, 0x0220) }, { @@ -10270,10 +10390,30 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0222) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0223) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0224) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0225) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_LENOVO, 0x0520) }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0521) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_LENOVO, 0x0522) }, { @@ -10294,6 +10434,26 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0624) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0625) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0626) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0627) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0628) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1014, 0x0718) }, { @@ -10322,6 +10482,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ded, 0x3301) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1ff9, 0x0045) }, { @@ -10470,6 +10634,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1f51, 0x100b) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1f51, 0x100e) }, { diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index 93e96705754e..b9c56a3816e0 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -22,7 +22,7 @@ static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port) struct pqi_sas_phy *pqi_sas_phy; struct sas_phy *phy; - pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL); + pqi_sas_phy = kzalloc_obj(*pqi_sas_phy); if (!pqi_sas_phy) return NULL; @@ -131,7 +131,7 @@ static struct pqi_sas_port *pqi_alloc_sas_port( struct pqi_sas_port *pqi_sas_port; struct sas_port *port; - pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL); + pqi_sas_port = kzalloc_obj(*pqi_sas_port); if (!pqi_sas_port) return NULL; @@ -180,7 +180,7 @@ static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev) { struct pqi_sas_node *pqi_sas_node; - pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL); + pqi_sas_node = kzalloc_obj(*pqi_sas_node); if (pqi_sas_node) { pqi_sas_node->parent_dev = parent_dev; INIT_LIST_HEAD(&pqi_sas_node->port_list_head); @@ -463,7 +463,7 @@ pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy, u32 req_size; u32 resp_size; - smp_buf = kzalloc(sizeof(*smp_buf), GFP_KERNEL); + smp_buf = kzalloc_obj(*smp_buf); if (!smp_buf) return NULL; diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index d1d2556c8fc4..b504a2cc5041 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -64,7 +64,7 @@ static int snirm710_probe(struct platform_device *dev) return -ENODEV; base = res->start; - hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); + hostdata = kzalloc_obj(*hostdata); if (!hostdata) return -ENOMEM; diff --git a/drivers/scsi/snic/snic.h b/drivers/scsi/snic/snic.h index 32f5a34b6987..ebaf6d63a59b 100644 --- a/drivers/scsi/snic/snic.h +++ b/drivers/scsi/snic/snic.h @@ -362,7 +362,8 @@ void snic_glob_cleanup(void); extern struct workqueue_struct *snic_event_queue; extern const struct attribute_group *snic_host_groups[]; -int snic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int snic_abort_cmd(struct scsi_cmnd *); int snic_device_reset(struct scsi_cmnd *); int snic_host_reset(struct scsi_cmnd *); diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c index 9dd975b36b5b..edf3e5ef28a6 100644 --- a/drivers/scsi/snic/snic_debugfs.c +++ b/drivers/scsi/snic/snic_debugfs.c @@ -282,8 +282,8 @@ snic_stats_show(struct seq_file *sfp, void *data) jiffies_to_timespec64(stats->misc.last_ack_time, &last_ack_tms); seq_printf(sfp, - "Last ISR Time : %llu (%8llu.%09lu)\n" - "Last Ack Time : %llu (%8llu.%09lu)\n" + "Last ISR Time : %llu (%ptSp)\n" + "Last Ack Time : %llu (%ptSp)\n" "Ack ISRs : %llu\n" "IO Cmpl ISRs : %llu\n" "Err Notify ISRs : %llu\n" @@ -298,10 +298,8 @@ snic_stats_show(struct seq_file *sfp, void *data) "Queue Ramp Down : %lld\n" "Queue Last Queue Depth : %lld\n" "Target Not Ready : %lld\n", - (u64) stats->misc.last_isr_time, - last_isr_tms.tv_sec, last_isr_tms.tv_nsec, - (u64)stats->misc.last_ack_time, - last_ack_tms.tv_sec, last_ack_tms.tv_nsec, + (u64) stats->misc.last_isr_time, &last_isr_tms, + (u64) stats->misc.last_ack_time, &last_ack_tms, (u64) atomic64_read(&stats->misc.ack_isr_cnt), (u64) atomic64_read(&stats->misc.cmpl_isr_cnt), (u64) atomic64_read(&stats->misc.errnotify_isr_cnt), diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index 4db3ba62fcd3..71d34a702f2a 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -244,7 +244,7 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) return tgt; } - tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); + tgt = kzalloc_obj(*tgt); if (!tgt) { SNIC_HOST_ERR(snic->shost, "Failure to allocate snic_tgt.\n"); ret = -ENOMEM; diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index 1c24517e4e65..82953e6a0915 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -818,7 +818,7 @@ snic_global_data_init(void) struct kmem_cache *cachep; ssize_t len = 0; - snic_glob = kzalloc(sizeof(*snic_glob), GFP_KERNEL); + snic_glob = kzalloc_obj(*snic_glob); if (!snic_glob) { SNIC_ERR("Failed to allocate Global Context.\n"); diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 84973f0f771e..c6af3b8d2523 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -315,8 +315,8 @@ issue_sc_end: * Routine to send a scsi cdb to LLD * Called with host_lock held and interrupts disabled */ -int -snic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct snic_tgt *tgt = NULL; struct snic *snic = shost_priv(shost); diff --git a/drivers/scsi/snic/snic_trc.c b/drivers/scsi/snic/snic_trc.c index c2e5ab7e976c..6bad1ea9a6a7 100644 --- a/drivers/scsi/snic/snic_trc.c +++ b/drivers/scsi/snic/snic_trc.c @@ -56,9 +56,8 @@ snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz) jiffies_to_timespec64(td->ts, &tmspec); len += snprintf(buf, buf_sz, - "%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", - tmspec.tv_sec, - tmspec.tv_nsec, + "%ptSp %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", + &tmspec, td->fn, td->hno, td->tag, diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index 760f3f22095c..ed7771e62854 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c @@ -42,8 +42,6 @@ struct vnic_dev { struct vnic_devcmd_notify *notify; struct vnic_devcmd_notify notify_copy; dma_addr_t notify_pa; - u32 *linkstatus; - dma_addr_t linkstatus_pa; struct vnic_stats *stats; dma_addr_t stats_pa; struct vnic_devcmd_fw_info *fw_info; @@ -352,7 +350,7 @@ static int svnic_dev_init_devcmd2(struct vnic_dev *vdev) if (!p) return -ENODEV; - dc2c = kzalloc(sizeof(*dc2c), GFP_ATOMIC); + dc2c = kzalloc_obj(*dc2c, GFP_ATOMIC); if (!dc2c) return -ENOMEM; @@ -650,8 +648,6 @@ int svnic_dev_init(struct vnic_dev *vdev, int arg) int svnic_dev_link_status(struct vnic_dev *vdev) { - if (vdev->linkstatus) - return *vdev->linkstatus; if (!vnic_dev_notify_ready(vdev)) return 0; @@ -686,11 +682,6 @@ void svnic_dev_unregister(struct vnic_dev *vdev) sizeof(struct vnic_devcmd_notify), vdev->notify, vdev->notify_pa); - if (vdev->linkstatus) - dma_free_coherent(&vdev->pdev->dev, - sizeof(u32), - vdev->linkstatus, - vdev->linkstatus_pa); if (vdev->stats) dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_stats), @@ -712,7 +703,7 @@ struct vnic_dev *svnic_dev_alloc_discover(struct vnic_dev *vdev, unsigned int num_bars) { if (!vdev) { - vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); + vdev = kzalloc_obj(struct vnic_dev, GFP_ATOMIC); if (!vdev) return NULL; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b17796d5ee66..c36c54ecd354 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -82,8 +82,8 @@ 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 int sr_probe(struct device *); -static int sr_remove(struct device *); +static int sr_probe(struct scsi_device *); +static void sr_remove(struct scsi_device *); static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); static int sr_done(struct scsi_cmnd *); static int sr_runtime_suspend(struct device *dev); @@ -93,10 +93,10 @@ static const struct dev_pm_ops sr_pm_ops = { }; static struct scsi_driver sr_template = { + .probe = sr_probe, + .remove = sr_remove, .gendrv = { .name = "sr", - .probe = sr_probe, - .remove = sr_remove, .pm = &sr_pm_ops, }, .init_command = sr_init_command, @@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) switch (req_op(rq)) { case REQ_OP_WRITE: - if (!cd->writeable) + if (get_disk_ro(cd->disk)) goto out; SCpnt->cmnd[0] = WRITE_10; cd->cdi.media_written = 1; @@ -475,13 +475,21 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) static int sr_revalidate_disk(struct scsi_cd *cd) { + struct request_queue *q = cd->device->request_queue; struct scsi_sense_hdr sshdr; + struct queue_limits lim; + int sector_size; /* if the unit is not ready, nothing more to do */ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) return 0; sr_cd_check(&cd->cdi); - return get_sectorsize(cd); + sector_size = get_sectorsize(cd); + + lim = queue_limits_start_update(q); + lim.logical_block_size = sector_size; + lim.features |= BLK_FEAT_ROTATIONAL; + return queue_limits_commit_update_frozen(q, &lim); } static int sr_block_open(struct gendisk *disk, blk_mode_t mode) @@ -608,9 +616,9 @@ static void sr_release(struct cdrom_device_info *cdi) { } -static int sr_probe(struct device *dev) +static int sr_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); + struct device *dev = &sdev->sdev_gendev; struct gendisk *disk; struct scsi_cd *cd; int minor, error; @@ -621,7 +629,7 @@ static int sr_probe(struct device *dev) goto fail; error = -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); + cd = kzalloc_obj(*cd); if (!cd) goto fail; @@ -673,6 +681,7 @@ static int sr_probe(struct device *dev) error = -ENOMEM; if (get_capabilities(cd)) goto fail_minor; + cdrom_probe_write_features(&cd->cdi); sr_vendor_init(cd); set_capacity(disk, cd->capacity); @@ -721,10 +730,8 @@ fail: static int get_sectorsize(struct scsi_cd *cd) { - struct request_queue *q = cd->device->request_queue; static const u8 cmd[10] = { READ_CAPACITY }; unsigned char buffer[8] = { }; - struct queue_limits lim; int err; int sector_size; struct scsi_failure failure_defs[] = { @@ -795,9 +802,7 @@ static int get_sectorsize(struct scsi_cd *cd) set_capacity(cd->disk, cd->capacity); } - lim = queue_limits_start_update(q); - lim.logical_block_size = sector_size; - return queue_limits_commit_update_frozen(q, &lim); + return sector_size; } static int get_capabilities(struct scsi_cd *cd) @@ -895,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) /*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ - /* - * if DVD-RAM, MRW-W or CD-RW, we are randomly writable - */ - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != - (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { - cd->writeable = 1; - } - kfree(buffer); return 0; } @@ -978,16 +975,15 @@ out_put_request: return ret; } -static int sr_remove(struct device *dev) +static void sr_remove(struct scsi_device *sdev) { + struct device *dev = &sdev->sdev_gendev; struct scsi_cd *cd = dev_get_drvdata(dev); scsi_autopm_get_device(cd->device); del_gendisk(cd->disk); put_disk(cd->disk); - - return 0; } static int __init init_sr(void) @@ -997,7 +993,7 @@ static int __init init_sr(void) rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); if (rc) return rc; - rc = scsi_register_driver(&sr_template.gendrv); + rc = scsi_register_driver(&sr_template); if (rc) unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); @@ -1006,7 +1002,7 @@ static int __init init_sr(void) static void __exit exit_sr(void) { - scsi_unregister_driver(&sr_template.gendrv); + scsi_unregister_driver(&sr_template); unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); } diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index dc899277b3a4..2d92f9cb6fec 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -35,7 +35,6 @@ typedef struct scsi_cd { struct scsi_device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index ebbd50ec0cda..f1c3c4946637 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -163,9 +163,11 @@ static const char *st_formats[] = { static int debugging = DEBUG; +/* Setting these non-zero may risk recognizing resets */ #define MAX_RETRIES 0 #define MAX_WRITE_RETRIES 0 #define MAX_READY_RETRIES 0 + #define NO_TAPE NOT_READY #define ST_TIMEOUT (900 * HZ) @@ -200,14 +202,14 @@ static int sgl_map_user_pages(struct st_buffer *, const unsigned int, unsigned long, size_t, int); static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); -static int st_probe(struct device *); -static int st_remove(struct device *); +static int st_probe(struct scsi_device *); +static void st_remove(struct scsi_device *); static struct scsi_driver st_template = { + .probe = st_probe, + .remove = st_remove, .gendrv = { .name = "st", - .probe = st_probe, - .remove = st_remove, .groups = st_drv_groups, }, }; @@ -357,10 +359,18 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) { int result = SRpnt->result; u8 scode; + unsigned int ctr; DEB(const char *stp;) char *name = STp->name; struct st_cmdstatus *cmdstatp; + ctr = scsi_get_ua_por_ctr(STp->device); + if (ctr != STp->por_ctr) { + STp->por_ctr = ctr; + STp->pos_unknown = 1; /* ASC => power on / reset */ + st_printk(KERN_WARNING, STp, "Power on/reset recognized."); + } + if (!result) return 0; @@ -413,10 +423,11 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) if (cmdstatp->have_sense && cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17) STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */ - if (cmdstatp->have_sense && scode == UNIT_ATTENTION && cmdstatp->sense_hdr.asc == 0x29) + if (cmdstatp->have_sense && scode == UNIT_ATTENTION && + cmdstatp->sense_hdr.asc == 0x29 && !STp->pos_unknown) { STp->pos_unknown = 1; /* ASC => power on / reset */ - - STp->pos_unknown |= STp->device->was_reset; + st_printk(KERN_WARNING, STp, "Power on/reset recognized."); + } if (cmdstatp->have_sense && scode == RECOVERED_ERROR @@ -451,7 +462,7 @@ static struct st_request *st_allocate_request(struct scsi_tape *stp) { struct st_request *streq; - streq = kzalloc(sizeof(*streq), GFP_KERNEL); + streq = kzalloc_obj(*streq); if (streq) streq->stp = stp; else { @@ -514,7 +525,8 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req) } static enum rq_end_io_ret st_scsi_execute_end(struct request *req, - blk_status_t status) + blk_status_t status, + const struct io_comp_batch *iob) { struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); struct st_request *SRpnt = req->end_io_data; @@ -952,7 +964,6 @@ static void reset_state(struct scsi_tape *STp) STp->partition = find_partition(STp); if (STp->partition < 0) STp->partition = 0; - STp->new_partition = STp->partition; } } @@ -969,6 +980,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait) { int attentions, waits, max_wait, scode; int retval = CHKRES_READY, new_session = 0; + unsigned int ctr; unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt = NULL; struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; @@ -1025,6 +1037,13 @@ static int test_ready(struct scsi_tape *STp, int do_wait) } } + ctr = scsi_get_ua_new_media_ctr(STp->device); + if (ctr != STp->new_media_ctr) { + STp->new_media_ctr = ctr; + new_session = 1; + DEBC_printk(STp, "New tape session."); + } + retval = (STp->buffer)->syscall_result; if (!retval) retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; @@ -2897,7 +2916,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon timeout = STp->long_timeout * 8; DEBC_printk(STp, "Erasing tape.\n"); - fileno = blkno = at_sm = 0; break; case MTSETBLK: /* Set block length */ case MTSETDENSITY: /* Set tape density */ @@ -2930,14 +2948,17 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon if (cmd_in == MTSETDENSITY) { (STp->buffer)->b_data[4] = arg; STp->density_changed = 1; /* At least we tried ;-) */ + STp->changed_density = arg; } else if (cmd_in == SET_DENS_AND_BLK) (STp->buffer)->b_data[4] = arg >> 24; else (STp->buffer)->b_data[4] = STp->density; if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { ltmp = arg & MT_ST_BLKSIZE_MASK; - if (cmd_in == MTSETBLK) + if (cmd_in == MTSETBLK) { STp->blksize_changed = 1; /* At least we tried ;-) */ + STp->changed_blksize = arg; + } } else ltmp = STp->block_size; (STp->buffer)->b_data[9] = (ltmp >> 16); @@ -3084,7 +3105,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon cmd_in == MTSETDRVBUFFER || cmd_in == SET_DENS_AND_BLK) { if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && - !(STp->use_pf & PF_TESTED)) { + cmdstatp->sense_hdr.asc == 0x24 && + (STp->device)->scsi_level <= SCSI_2 && + !(STp->use_pf & PF_TESTED)) { /* Try the other possible state of Page Format if not already tried */ STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; @@ -3504,8 +3527,64 @@ static int partition_tape(struct scsi_tape *STp, int size) out: return result; } - +/* + * Handles any extra state needed for ioctls which are not st-specific. + * Called with the scsi_tape lock held, released before return + */ +static long st_common_ioctl(struct scsi_tape *STp, struct st_modedef *STm, + struct file *file, unsigned int cmd_in, + unsigned long arg) +{ + int i, retval = 0; + + if (!STm->defined) { + retval = -ENXIO; + goto out; + } + + switch (cmd_in) { + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_GET_PCI: + break; + case SG_IO: + case SCSI_IOCTL_SEND_COMMAND: + case CDROM_SEND_PACKET: + if (!capable(CAP_SYS_RAWIO)) { + retval = -EPERM; + goto out; + } + fallthrough; + default: + if ((i = flush_buffer(STp, 0)) < 0) { + retval = i; + goto out; + } else { /* flush_buffer succeeds */ + if (STp->can_partitions) { + i = switch_partition(STp); + if (i < 0) { + retval = i; + goto out; + } + } + } + } + mutex_unlock(&STp->lock); + + retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, + cmd_in, (void __user *)arg); + if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { + /* unload */ + STp->rew_at_close = 0; + STp->ready = ST_NO_TAPE; + } + + return retval; +out: + mutex_unlock(&STp->lock); + return retval; +} /* The ioctl command */ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) @@ -3543,6 +3622,15 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) if (retval) goto out; + switch (cmd_in) { + case MTIOCPOS: + case MTIOCGET: + case MTIOCTOP: + break; + default: + return st_common_ioctl(STp, STm, file, cmd_in, arg); + } + cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); @@ -3636,9 +3724,23 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) retval = (-EIO); goto out; } - reset_state(STp); - /* remove this when the midlevel properly clears was_reset */ - STp->device->was_reset = 0; + reset_state(STp); /* Clears pos_unknown */ + + /* Fix the device settings after reset, ignore errors */ + if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK || + mtc.mt_op == MTEOM) { + if (STp->can_partitions) { + /* STp->new_partition contains the + * latest partition set + */ + STp->partition = 0; + switch_partition(STp); + } + if (STp->density_changed) + st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); + if (STp->blksize_changed) + st_int_ioctl(STp, MTSETBLK, STp->changed_blksize); + } } if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && @@ -3840,29 +3942,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) } mt_pos.mt_blkno = blk; retval = put_user_mtpos(p, &mt_pos); - goto out; - } - mutex_unlock(&STp->lock); - - switch (cmd_in) { - case SG_IO: - case SCSI_IOCTL_SEND_COMMAND: - case CDROM_SEND_PACKET: - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - break; - default: - break; } - - retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, cmd_in, p); - if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { - /* unload */ - STp->rew_at_close = 0; - STp->ready = ST_NO_TAPE; - } - return retval; - out: mutex_unlock(&STp->lock); return retval; @@ -3893,7 +3973,7 @@ static struct st_buffer *new_tape_buffer(int max_sg) { struct st_buffer *tb; - tb = kzalloc(sizeof(struct st_buffer), GFP_KERNEL); + tb = kzalloc_obj(struct st_buffer); if (!tb) { printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); return NULL; @@ -3902,8 +3982,7 @@ static struct st_buffer *new_tape_buffer(int max_sg) tb->use_sg = max_sg; tb->buffer_size = 0; - tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *), - GFP_KERNEL); + tb->reserved_pages = kzalloc_objs(struct page *, max_sg); if (!tb->reserved_pages) { kfree(tb); return NULL; @@ -4122,7 +4201,7 @@ static void validate_options(void) */ static int __init st_setup(char *str) { - int i, len, ints[5]; + int i, len, ints[ARRAY_SIZE(parms) + 1]; char *stp; stp = get_options(str, ARRAY_SIZE(ints), ints); @@ -4263,9 +4342,9 @@ static void remove_cdevs(struct scsi_tape *tape) } } -static int st_probe(struct device *dev) +static int st_probe(struct scsi_device *SDp) { - struct scsi_device *SDp = to_scsi_device(dev); + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = NULL; struct st_modedef *STm; struct st_partstat *STps; @@ -4294,7 +4373,7 @@ static int st_probe(struct device *dev) goto out; } - tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL); + tpnt = kzalloc_obj(struct scsi_tape); if (tpnt == NULL) { sdev_printk(KERN_ERR, SDp, "st: Can't allocate device descriptor.\n"); @@ -4377,13 +4456,16 @@ static int st_probe(struct device *dev) } tpnt->index = error; sprintf(tpnt->name, "st%d", tpnt->index); - tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL); + tpnt->stats = kzalloc_obj(struct scsi_tape_stats); if (tpnt->stats == NULL) { sdev_printk(KERN_ERR, SDp, "st: Can't allocate statistics.\n"); goto out_idr_remove; } + tpnt->new_media_ctr = scsi_get_ua_new_media_ctr(SDp); + tpnt->por_ctr = scsi_get_ua_por_ctr(SDp); + dev_set_drvdata(dev, tpnt); @@ -4417,12 +4499,13 @@ out: }; -static int st_remove(struct device *dev) +static void st_remove(struct scsi_device *SDp) { + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = dev_get_drvdata(dev); int index = tpnt->index; - scsi_autopm_get_device(to_scsi_device(dev)); + scsi_autopm_get_device(SDp); remove_cdevs(tpnt); mutex_lock(&st_ref_mutex); @@ -4431,7 +4514,6 @@ static int st_remove(struct device *dev) spin_lock(&st_index_lock); idr_remove(&st_index_idr, index); spin_unlock(&st_index_lock); - return 0; } /** @@ -4494,7 +4576,7 @@ static int __init init_st(void) goto err_class; } - err = scsi_register_driver(&st_template.gendrv); + err = scsi_register_driver(&st_template); if (err) goto err_chrdev; @@ -4510,7 +4592,7 @@ err_class: static void __exit exit_st(void) { - scsi_unregister_driver(&st_template.gendrv); + scsi_unregister_driver(&st_template); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); class_unregister(&st_sysfs_class); @@ -4665,6 +4747,24 @@ options_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(options); +/** + * position_lost_in_reset_show - Value 1 indicates that reads, writes, etc. + * are blocked because a device reset has occurred and no operation positioning + * the tape has been issued. + * @dev: struct device + * @attr: attribute structure + * @buf: buffer to return formatted data in + */ +static ssize_t position_lost_in_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct st_modedef *STm = dev_get_drvdata(dev); + struct scsi_tape *STp = STm->tape; + + return sprintf(buf, "%d", STp->pos_unknown); +} +static DEVICE_ATTR_RO(position_lost_in_reset); + /* Support for tape stats */ /** @@ -4849,6 +4949,7 @@ static struct attribute *st_dev_attrs[] = { &dev_attr_default_density.attr, &dev_attr_default_compression.attr, &dev_attr_options.attr, + &dev_attr_position_lost_in_reset.attr, NULL, }; @@ -4905,7 +5006,7 @@ static int sgl_map_user_pages(struct st_buffer *STbp, if (count == 0) return 0; - pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL); + pages = kmalloc_objs(*pages, max_pages); if (pages == NULL) return -ENOMEM; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 1aaaf5369a40..0d7c4b8c2c8a 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -165,6 +165,7 @@ struct scsi_tape { unsigned char compression_changed; unsigned char drv_buffer; unsigned char density; + unsigned char changed_density; unsigned char door_locked; unsigned char autorew_dev; /* auto-rewind device */ unsigned char rew_at_close; /* rewind necessary at close */ @@ -172,11 +173,16 @@ struct scsi_tape { unsigned char cleaning_req; /* cleaning requested? */ unsigned char first_tur; /* first TEST UNIT READY */ int block_size; + int changed_blksize; int min_block; int max_block; int recover_count; /* From tape opening */ int recover_reg; /* From last status call */ + /* The saved values of midlevel counters */ + unsigned int new_media_ctr; + unsigned int por_ctr; + #if DEBUG unsigned char write_pending; int nbr_finished; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 63ed7f9aaa93..6aeeb338633d 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -593,7 +593,7 @@ stex_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) return 0; } -static int stex_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status stex_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct st_hba *hba; @@ -1457,7 +1457,7 @@ static void stex_reset_work(struct work_struct *work) } static int stex_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int geom[]) + struct gendisk *unused, sector_t capacity, int geom[]) { int heads = 255, sectors = 63; @@ -1757,7 +1757,7 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } - hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL); + hba->ccb = kzalloc_objs(struct st_ccb, ci->rq_count); if (!hba->ccb) { err = -ENOMEM; printk(KERN_ERR DRV_NAME "(%s): ccb alloc failed\n", @@ -1844,6 +1844,7 @@ out_release_regions: out_scsi_host_put: scsi_host_put(host); out_disable: + unregister_reboot_notifier(&stex_notifier); pci_disable_device(pdev); return err; @@ -1965,6 +1966,7 @@ static int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state) case PM_EVENT_SUSPEND: return ST_S3; case PM_EVENT_HIBERNATE: + case PM_EVENT_POWEROFF: hba->msi_lock = 0; return ST_S4; default: diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index a8614e54544e..6977ca8a0658 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -362,7 +362,7 @@ MODULE_PARM_DESC(ring_avail_percent_lowater, /* * Timeout in seconds for all devices managed by this driver. */ -static int storvsc_timeout = 180; +static const int storvsc_timeout = 180; #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) static struct scsi_transport_template *fc_transport_template; @@ -768,7 +768,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) return; } - t = wait_for_completion_timeout(&request->wait_event, 10*HZ); + t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); if (t == 0) { dev_err(dev, "Failed to create sub-channel: timed out\n"); return; @@ -776,7 +776,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || vstor_packet->status != 0) { - dev_err(dev, "Failed to create sub-channel: op=%d, sts=%d\n", + dev_err(dev, "Failed to create sub-channel: op=%d, host=0x%x\n", vstor_packet->operation, vstor_packet->status); return; } @@ -833,7 +833,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device, if (ret != 0) return ret; - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); if (t == 0) return -ETIMEDOUT; @@ -1063,7 +1063,7 @@ do_work: /* * We need to schedule work to process this error; schedule it. */ - wrk = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC); + wrk = kmalloc_obj(struct storvsc_scan_work, GFP_ATOMIC); if (!wrk) { set_host_byte(scmnd, DID_BAD_TARGET); return; @@ -1131,6 +1131,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, kfree(payload); } +/* + * The current SCSI handling on the host side does not correctly handle: + * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, + * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. + */ +static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) +{ + switch (opcode) { + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + return true; + case MAINTENANCE_IN: + case PERSISTENT_RESERVE_IN: + return hv_dev_is_fc(device); + default: + return false; + } +} + static void storvsc_on_io_completion(struct storvsc_device *stor_device, struct vstor_packet *vstor_packet, struct storvsc_cmd_request *request) @@ -1141,21 +1161,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, stor_pkt = &request->vstor_packet; /* - * The current SCSI handling on the host side does - * not correctly handle: - * INQUIRY command with page code parameter set to 0x80 - * MODE_SENSE command with cmd[2] == 0x1c - * MAINTENANCE_IN is not supported by HyperV FC passthrough - * * Setup srb and scsi status so this won't be fatal. * We do this so we can distinguish truly fatal failues * (srb status == 0x4) and off-line the device in that case. */ - if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || - (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && - hv_dev_is_fc(device))) { + if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { vstor_packet->vm_srb.scsi_status = 0; vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; } @@ -1183,7 +1194,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, STORVSC_LOGGING_WARN : STORVSC_LOGGING_ERROR; storvsc_log_ratelimited(device, loglevel, - "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n", + "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x host 0x%x\n", scsi_cmd_to_rq(request->cmd)->tag, stor_pkt->vm_srb.cdb[0], vstor_packet->vm_srb.scsi_status, @@ -1350,6 +1361,8 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size, return ret; ret = storvsc_channel_init(device, is_fc); + if (ret) + vmbus_close(device->channel); return ret; } @@ -1404,14 +1417,19 @@ static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device, } /* - * Our channel array is sparsley populated and we + * Our channel array could be sparsley populated and we * initiated I/O on a processor/hw-q that does not * currently have a designated channel. Fix this. * The strategy is simple: - * I. Ensure NUMA locality - * II. Distribute evenly (best effort) + * I. Prefer the channel associated with the current CPU + * II. Ensure NUMA locality + * III. Distribute evenly (best effort) */ + /* Prefer the channel on the I/O issuing processor/hw-q */ + if (cpumask_test_cpu(q_num, &stor_device->alloced_cpus)) + return stor_device->stor_chns[q_num]; + node_mask = cpumask_of_node(cpu_to_node(q_num)); num_channels = 0; @@ -1467,59 +1485,48 @@ static int storvsc_do_io(struct hv_device *device, /* See storvsc_change_target_cpu(). */ outgoing_channel = READ_ONCE(stor_device->stor_chns[q_num]); if (outgoing_channel != NULL) { - if (outgoing_channel->target_cpu == q_num) { - /* - * Ideally, we want to pick a different channel if - * available on the same NUMA node. - */ - node_mask = cpumask_of_node(cpu_to_node(q_num)); - for_each_cpu_wrap(tgt_cpu, - &stor_device->alloced_cpus, q_num + 1) { - if (!cpumask_test_cpu(tgt_cpu, node_mask)) - continue; - if (tgt_cpu == q_num) - continue; - channel = READ_ONCE( - stor_device->stor_chns[tgt_cpu]); - if (channel == NULL) - continue; - if (hv_get_avail_to_write_percent( - &channel->outbound) - > ring_avail_percent_lowater) { - outgoing_channel = channel; - goto found_channel; - } - } + if (hv_get_avail_to_write_percent(&outgoing_channel->outbound) + > ring_avail_percent_lowater) + goto found_channel; - /* - * All the other channels on the same NUMA node are - * busy. Try to use the channel on the current CPU - */ - if (hv_get_avail_to_write_percent( - &outgoing_channel->outbound) - > ring_avail_percent_lowater) + /* + * Channel is busy, try to find a channel on the same NUMA node + */ + node_mask = cpumask_of_node(cpu_to_node(q_num)); + for_each_cpu_wrap(tgt_cpu, &stor_device->alloced_cpus, + q_num + 1) { + if (!cpumask_test_cpu(tgt_cpu, node_mask)) + continue; + channel = READ_ONCE(stor_device->stor_chns[tgt_cpu]); + if (!channel) + continue; + if (hv_get_avail_to_write_percent(&channel->outbound) + > ring_avail_percent_lowater) { + outgoing_channel = channel; goto found_channel; + } + } - /* - * If we reach here, all the channels on the current - * NUMA node are busy. Try to find a channel in - * other NUMA nodes - */ - for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) { - if (cpumask_test_cpu(tgt_cpu, node_mask)) - continue; - channel = READ_ONCE( - stor_device->stor_chns[tgt_cpu]); - if (channel == NULL) - continue; - if (hv_get_avail_to_write_percent( - &channel->outbound) - > ring_avail_percent_lowater) { - outgoing_channel = channel; - goto found_channel; - } + /* + * If we reach here, all the channels on the current + * NUMA node are busy. Try to find a channel in + * all NUMA nodes + */ + for_each_cpu_wrap(tgt_cpu, &stor_device->alloced_cpus, + q_num + 1) { + channel = READ_ONCE(stor_device->stor_chns[tgt_cpu]); + if (!channel) + continue; + if (hv_get_avail_to_write_percent(&channel->outbound) + > ring_avail_percent_lowater) { + outgoing_channel = channel; + goto found_channel; } } + /* + * If we reach here, all the channels are busy. Use the + * original channel found. + */ } else { spin_lock_irqsave(&stor_device->lock, flags); outgoing_channel = stor_device->stor_chns[q_num]; @@ -1613,7 +1620,7 @@ static int storvsc_sdev_configure(struct scsi_device *sdevice, return 0; } -static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, +static int storvsc_get_chs(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int *info) { sector_t nsect = capacity; @@ -1668,7 +1675,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) if (ret != 0) return FAILED; - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); if (t == 0) return TIMEOUT_ERROR; @@ -1718,7 +1725,8 @@ static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) return allowed; } -static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) +static enum scsi_qc_status storvsc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *scmnd) { int ret; struct hv_host_device *host_dev = shost_priv(host); @@ -1819,6 +1827,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) return SCSI_MLQUEUE_DEVICE_BUSY; } + payload->rangecount = 1; payload->range.len = length; payload->range.offset = offset_in_hvpg; @@ -1857,8 +1866,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) cmd_request->payload_sz = payload_sz; /* Invokes the vsc to start an IO */ - ret = storvsc_do_io(dev, cmd_request, get_cpu()); - put_cpu(); + migrate_disable(); + ret = storvsc_do_io(dev, cmd_request, smp_processor_id()); + migrate_enable(); if (ret) scsi_dma_unmap(scmnd); @@ -1938,8 +1948,8 @@ static int storvsc_probe(struct hv_device *device, int num_present_cpus = num_present_cpus(); struct Scsi_Host *host; struct hv_host_device *host_dev; - bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); - bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false); + bool dev_is_ide = dev_id->driver_data == IDE_GUID; + bool is_fc = dev_id->driver_data == SFC_GUID; int target = 0; struct storvsc_device *stor_device; int max_sub_channels = 0; @@ -1971,7 +1981,7 @@ static int storvsc_probe(struct hv_device *device, host_dev->host = host; - stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); + stor_device = kzalloc_obj(struct storvsc_device); if (!stor_device) { ret = -ENOMEM; goto err_out0; diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 212d89d0d23e..27e22acaf1a7 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -485,7 +485,7 @@ void sym_log_bus_error(struct Scsi_Host *shost) * queuecommand method. Entered with the host adapter lock held and * interrupts disabled. */ -static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct sym_hcb *np = SYM_SOFTC_PTR(cmd); struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); @@ -545,7 +545,7 @@ static irqreturn_t sym53c8xx_intr(int irq, void *dev_id) */ static void sym53c8xx_timer(struct timer_list *t) { - struct sym_hcb *np = from_timer(np, t, s.timer); + struct sym_hcb *np = timer_container_of(np, t, s.timer); unsigned long flags; spin_lock_irqsave(np->s.host->host_lock, flags); @@ -1657,7 +1657,7 @@ static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev) struct sym_hcb *np = sym_get_hcb(shost); printk("%s: detaching ...\n", sym_name(np)); - del_timer_sync(&np->s.timer); + timer_delete_sync(&np->s.timer); /* * Reset NCR chip. diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index f0db17e34ea0..c554e4158094 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -4990,8 +4990,8 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) * Allocate the table of pointers for LUN(s) > 0, if needed. */ if (ln && !tp->lunmp) { - tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), - GFP_ATOMIC); + tp->lunmp = kzalloc_objs(struct sym_lcb *, SYM_CONF_MAX_LUN, + GFP_ATOMIC); if (!tp->lunmp) goto fail; } @@ -5655,7 +5655,7 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram /* * Allocate the array of lists of CCBs hashed by DSA. */ - np->ccbh = kcalloc(CCB_HASH_SIZE, sizeof(*np->ccbh), GFP_KERNEL); + np->ccbh = kzalloc_objs(*np->ccbh, CCB_HASH_SIZE); if (!np->ccbh) goto attach_failed; diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 21ce3e940192..5fdaa71f0652 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -29,6 +29,7 @@ #include <scsi/scsi_tcq.h> #include <scsi/scsi_devinfo.h> #include <linux/seqlock.h> +#include <linux/dma-mapping.h> #include "sd.h" @@ -61,7 +62,7 @@ struct virtio_scsi_cmd { struct virtio_scsi_event_node { struct virtio_scsi *vscsi; - struct virtio_scsi_event event; + struct virtio_scsi_event *event; struct work_struct work; }; @@ -89,6 +90,11 @@ struct virtio_scsi { struct virtio_scsi_vq ctrl_vq; struct virtio_scsi_vq event_vq; + + __dma_from_device_group_begin(); + struct virtio_scsi_event events[VIRTIO_SCSI_EVENT_LEN]; + __dma_from_device_group_end(); + struct virtio_scsi_vq req_vqs[]; }; @@ -227,7 +233,6 @@ static void virtscsi_ctrl_done(struct virtqueue *vq) virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free); }; -static void virtscsi_handle_event(struct work_struct *work); static int virtscsi_kick_event(struct virtio_scsi *vscsi, struct virtio_scsi_event_node *event_node) @@ -236,13 +241,12 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi, struct scatterlist sg; unsigned long flags; - INIT_WORK(&event_node->work, virtscsi_handle_event); - sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); + sg_init_one(&sg, event_node->event, sizeof(struct virtio_scsi_event)); spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); - err = virtqueue_add_inbuf(vscsi->event_vq.vq, &sg, 1, event_node, - GFP_ATOMIC); + err = virtqueue_add_inbuf_cache_clean(vscsi->event_vq.vq, &sg, 1, event_node, + GFP_ATOMIC); if (!err) virtqueue_kick(vscsi->event_vq.vq); @@ -257,6 +261,7 @@ static int virtscsi_kick_event_all(struct virtio_scsi *vscsi) for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) { vscsi->event_list[i].vscsi = vscsi; + vscsi->event_list[i].event = &vscsi->events[i]; virtscsi_kick_event(vscsi, &vscsi->event_list[i]); } @@ -380,7 +385,7 @@ static void virtscsi_handle_event(struct work_struct *work) struct virtio_scsi_event_node *event_node = container_of(work, struct virtio_scsi_event_node, work); struct virtio_scsi *vscsi = event_node->vscsi; - struct virtio_scsi_event *event = &event_node->event; + struct virtio_scsi_event *event = event_node->event; if (event->event & cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) { @@ -561,8 +566,8 @@ static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi, return &vscsi->req_vqs[hwq]; } -static int virtscsi_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status virtscsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(shost); struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); @@ -846,8 +851,8 @@ static int virtscsi_init(struct virtio_device *vdev, num_req_vqs = vscsi->num_queues; num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE; - vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL); - vqs_info = kcalloc(num_vqs, sizeof(*vqs_info), GFP_KERNEL); + vqs = kmalloc_objs(struct virtqueue *, num_vqs); + vqs_info = kzalloc_objs(*vqs_info, num_vqs); if (!vqs || !vqs_info) { err = -ENOMEM; @@ -919,6 +924,7 @@ static int virtscsi_probe(struct virtio_device *vdev) /* We need to know how many queues before we allocate. */ num_queues = virtscsi_config_get(vdev, num_queues) ? : 1; num_queues = min_t(unsigned int, nr_cpu_ids, num_queues); + num_queues = blk_mq_num_possible_queues(num_queues); num_targets = virtscsi_config_get(vdev, max_target) + 1; @@ -976,8 +982,10 @@ static int virtscsi_probe(struct virtio_device *vdev) virtio_device_ready(vdev); - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) - virtscsi_kick_event_all(vscsi); + for (int i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) + INIT_WORK(&vscsi->event_list[i].work, virtscsi_handle_event); + + virtscsi_kick_event_all(vscsi); scsi_scan_host(shost); return 0; @@ -994,8 +1002,7 @@ static void virtscsi_remove(struct virtio_device *vdev) struct Scsi_Host *shost = virtio_scsi_host(vdev); struct virtio_scsi *vscsi = shost_priv(shost); - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) - virtscsi_cancel_event_work(vscsi); + virtscsi_cancel_event_work(vscsi); scsi_remove_host(shost); virtscsi_remove_vqs(vdev); @@ -1021,8 +1028,7 @@ static int virtscsi_restore(struct virtio_device *vdev) virtio_device_ready(vdev); - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) - virtscsi_kick_event_all(vscsi); + virtscsi_kick_event_all(vscsi); return err; } diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 32242d86cf5b..151cac9f9c2a 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -771,7 +771,7 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, return 0; } -static int pvscsi_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status pvscsi_queue_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct pvscsi_adapter *adapter = shost_priv(host); @@ -1478,8 +1478,7 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) */ pvscsi_setup_all_rings(adapter); - adapter->cmd_map = kcalloc(adapter->req_depth, - sizeof(struct pvscsi_ctx), GFP_KERNEL); + adapter->cmd_map = kzalloc_objs(struct pvscsi_ctx, adapter->req_depth); if (!adapter->cmd_map) { printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n"); error = -ENOMEM; diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index dd1fef9226f2..1e49d0402f0b 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -302,7 +302,7 @@ calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, msg[1] = offset; } -static int wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); struct WD33C93_hostdata *hostdata; diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index e5e4254b1477..e1e98280aad1 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -332,7 +332,8 @@ static inline struct scsi_pointer *WD33C93_scsi_pointer(struct scsi_cmnd *cmd) void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs, dma_setup_t setup, dma_stop_t stop, int clock_freq); int wd33c93_abort (struct scsi_cmnd *cmd); -int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd); +enum scsi_qc_status wd33c93_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); void wd33c93_intr (struct Scsi_Host *instance); int wd33c93_show_info(struct seq_file *, struct Scsi_Host *); int wd33c93_write_info(struct Scsi_Host *, char *, int); diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 5a380eecfc75..830d40f57f6a 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -204,7 +204,8 @@ static void wd719x_finish_cmd(struct wd719x_scb *scb, int result) } /* Build a SCB and send it to the card */ -static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status wd719x_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { int i, count_sg; unsigned long flags; @@ -544,7 +545,7 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED; } -static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int wd719x_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { if (capacity >= 0x200000) { diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 924025305753..989bcaee42ca 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -494,8 +494,8 @@ static int map_data_for_request(struct vscsifrnt_info *info, return -E2BIG; } seg_grants = vscsiif_grants_sg(data_grants); - shadow->sg = kcalloc(data_grants, - sizeof(struct scsiif_request_segment), GFP_ATOMIC); + shadow->sg = kzalloc_objs(struct scsiif_request_segment, + data_grants, GFP_ATOMIC); if (!shadow->sg) return -ENOMEM; } @@ -603,8 +603,8 @@ static void scsifront_return(struct vscsifrnt_info *info) wake_up(&info->wq_pause); } -static int scsifront_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status scsifront_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct vscsifrnt_info *info = shost_priv(shost); struct vscsifrnt_shadow *shadow = scsi_cmd_priv(sc); @@ -669,7 +669,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) if (info->host_active == STATE_ERROR) return FAILED; - shadow = kzalloc(sizeof(*shadow), GFP_NOIO); + shadow = kzalloc_obj(*shadow, GFP_NOIO); if (!shadow) return FAILED; @@ -1175,7 +1175,7 @@ static void scsifront_backend_changed(struct xenbus_device *dev, return; } - if (xenbus_read_driver_state(dev->nodename) == + if (xenbus_read_driver_state(dev, dev->nodename) == XenbusStateInitialised) scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c index 7acf9193a9e8..6aca9897b231 100644 --- a/drivers/scsi/zorro7xx.c +++ b/drivers/scsi/zorro7xx.c @@ -95,7 +95,7 @@ static int zorro7xx_init_one(struct zorro_dev *z, return -EBUSY; } - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + hostdata = kzalloc_obj(struct NCR_700_Host_Parameters); if (!hostdata) { printk(KERN_ERR "zorro7xx: Failed to allocate host data\n"); goto out_release; diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index 56cae22a4242..1622285c9aec 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -726,7 +726,7 @@ static int zorro_esp_probe(struct zorro_dev *z, pr_info("%s found at address 0x%lx.\n", zdd->name, board); - zep = kzalloc(sizeof(*zep), GFP_KERNEL); + zep = kzalloc_obj(*zep); if (!zep) { pr_err("Can't allocate device private data!\n"); return -ENOMEM; |
