From 548f0e65a38f36976260a63ff4acfa9f3b17307d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 14 Mar 2016 15:29:43 +0100 Subject: aacraid: add missing curly braces gcc-6 warns about obviously wrong indentation for newly added code in aac_slave_configure(): drivers/scsi/aacraid/linit.c: In function 'aac_slave_configure': drivers/scsi/aacraid/linit.c:458:3: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation] sdev->tagged_supported = 1; ^~~~ drivers/scsi/aacraid/linit.c:455:4: note: ...this 'else' clause, but it is not gcc is correct, and evidently this was meant to be within the curly braces that should have been there to start with. This patch adds them, which avoids the warning and makes it clear what was intended here. Nothing changes in behavior because in the 'if' block, the sdev->tagged_supported flag is known to be set already. Signed-off-by: Arnd Bergmann Fixes: 6bf3b630d0a7 ("aacraid: SCSI blk tag support") Reviewed-by: Raghava Aditya Renukunta Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 21a67ed..ff6caab 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -452,10 +452,11 @@ static int aac_slave_configure(struct scsi_device *sdev) else if (depth < 2) depth = 2; scsi_change_queue_depth(sdev, depth); - } else + } else { scsi_change_queue_depth(sdev, 1); sdev->tagged_supported = 1; + } return 0; } -- cgit v0.10.2 From 5ec8a1753bc29efa7e4b1391d691c9c719b30257 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Fri, 18 Mar 2016 12:45:42 -0700 Subject: mpt3sas: Don't overreach ioc->reply_post[] during initialization In _base_make_ioc_operational(), we walk ioc->reply_queue_list and pull a pointer out of successive elements of ioc->reply_post[] for each entry in that list if RDPQ is enabled. Since the code pulls the pointer for the next iteration at the bottom of the loop, it triggers the a KASAN dump on the final iteration: BUG: KASAN: slab-out-of-bounds in _base_make_ioc_operational+0x47b7/0x47e0 [mpt3sas] at addr ffff880754816ab0 Read of size 8 by task modprobe/305 Call Trace: [] dump_stack+0x4d/0x6c [] print_trailer+0xf9/0x150 [] object_err+0x34/0x40 [] kasan_report_error+0x221/0x530 [] __asan_report_load8_noabort+0x43/0x50 [] _base_make_ioc_operational+0x47b7/0x47e0 [mpt3sas] [] mpt3sas_base_attach+0x1991/0x2120 [mpt3sas] [] _scsih_probe+0xeb3/0x16b0 [mpt3sas] [] local_pci_probe+0xc7/0x170 [] pci_device_probe+0x20f/0x290 [] really_probe+0x17d/0x600 [] __driver_attach+0x153/0x190 [] bus_for_each_dev+0x11c/0x1a0 [] driver_attach+0x3d/0x50 [] bus_add_driver+0x44a/0x5f0 [] driver_register+0x18c/0x3b0 [] __pci_register_driver+0x156/0x200 [] _mpt3sas_init+0x135/0x1000 [mpt3sas] [] do_one_initcall+0x113/0x2b0 [] do_init_module+0x1d0/0x4d8 [] load_module+0x6729/0x8dc0 [] SYSC_init_module+0x183/0x1a0 [] SyS_init_module+0xe/0x10 [] entry_SYSCALL_64_fastpath+0x12/0x6a Fix this by pulling the value at the beginning of the loop. Signed-off-by: Calvin Owens Reviewed-by: Johannes Thumshirn Reviewed-by: Jens Axboe Acked-by: Chaitra Basappa Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index e4db5fb..8c44b9c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5030,7 +5030,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, static int _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) { - int r, i; + int r, i, index; unsigned long flags; u32 reply_address; u16 smid; @@ -5039,8 +5039,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next; u8 hide_flag; struct adapter_reply_queue *reply_q; - long reply_post_free; - u32 reply_post_free_sz, index = 0; + Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig; dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); @@ -5124,27 +5123,27 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) _base_assign_reply_queues(ioc); /* initialize Reply Post Free Queue */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - reply_post_free = (long)ioc->reply_post[index].reply_post_free; + index = 0; + reply_post_free_contig = ioc->reply_post[0].reply_post_free; list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { + /* + * If RDPQ is enabled, switch to the next allocation. + * Otherwise advance within the contiguous region. + */ + if (ioc->rdpq_array_enable) { + reply_q->reply_post_free = + ioc->reply_post[index++].reply_post_free; + } else { + reply_q->reply_post_free = reply_post_free_contig; + reply_post_free_contig += ioc->reply_post_queue_depth; + } + reply_q->reply_post_host_index = 0; - reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) - reply_post_free; for (i = 0; i < ioc->reply_post_queue_depth; i++) reply_q->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX); if (!_base_is_controller_msix_enabled(ioc)) goto skip_init_reply_post_free_queue; - /* - * If RDPQ is enabled, switch to the next allocation. - * Otherwise advance within the contiguous region. - */ - if (ioc->rdpq_array_enable) - reply_post_free = (long) - ioc->reply_post[++index].reply_post_free; - else - reply_post_free += reply_post_free_sz; } skip_init_reply_post_free_queue: -- cgit v0.10.2 From 9526f36026f778e82b5175249443854c03b2e660 Mon Sep 17 00:00:00 2001 From: "Manoj N. Kumar" Date: Fri, 25 Mar 2016 14:26:34 -0500 Subject: cxlflash: Fix regression issue with re-ordering patch While running 'sg_reset -H' back to back the following exception was seen: [ 735.115695] Faulting instruction address: 0xd0000000098c0864 cpu 0x0: Vector: 300 (Data Access) at [c000000ffffafa80] pc: d0000000098c0864: cxlflash_async_err_irq+0x84/0x5c0 [cxlflash] lr: c00000000013aed0: handle_irq_event_percpu+0xa0/0x310 sp: c000000ffffafd00 msr: 9000000000009033 dar: 2010000 dsisr: 40000000 current = 0xc000000001510880 paca = 0xc00000000fb80000 softe: 0 irq_happened: 0x01 pid = 0, comm = swapper/0 Linux version 4.5.0-491-26f710d+ enter ? for help [c000000ffffafe10] c00000000013aed0 handle_irq_event_percpu+0xa0/0x310 [c000000ffffafed0] c00000000013b1a8 handle_irq_event+0x68/0xc0 [c000000ffffaff00] c0000000001404ec handle_fasteoi_irq+0xec/0x2a0 [c000000ffffaff30] c00000000013a084 generic_handle_irq+0x54/0x80 [c000000ffffaff60] c000000000011130 __do_irq+0x80/0x1d0 [c000000ffffaff90] c000000000024d40 call_do_irq+0x14/0x24 [c000000001573a20] c000000000011318 do_IRQ+0x98/0x140 [c000000001573a70] c000000000002594 hardware_interrupt_common+0x114/0x180 This exception is being hit because the async_err interrupt path performs an MMIO to read the interrupt status register. The MMIO region in this case is not available. Commit 6ded8b3cbd9a ("cxlflash: Unmap problem state area before detaching master context") re-ordered the sequence in which term_mc() and stop_afu() are called. This introduces a window for interrupts to come in with the problem space area unmapped, that did not exist previously. The fix is to separate the disabling of all AFU interrupts to a distinct function, term_intr() so that it is the first thing that is done in the tear down process. To keep the initialization process symmetric, separate the AFU interrupt setup also to a distinct function: init_intr(). Fixes: 6ded8b3cbd9a ("cxlflash: Unmap problem state area before detaching master context") Signed-off-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Reviewed-by: Johannes Thumshirn Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3879b46..1d41807 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -683,28 +683,23 @@ static void stop_afu(struct cxlflash_cfg *cfg) } /** - * term_mc() - terminates the master context + * term_intr() - disables all AFU interrupts * @cfg: Internal structure associated with the host. * @level: Depth of allocation, where to begin waterfall tear down. * * Safe to call with AFU/MC in partially allocated/initialized state. */ -static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) +static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level) { - int rc = 0; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; if (!afu || !cfg->mcctx) { - dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n", - __func__); + dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); return; } switch (level) { - case UNDO_START: - rc = cxl_stop_context(cfg->mcctx); - BUG_ON(rc); case UNMAP_THREE: cxl_unmap_afu_irq(cfg->mcctx, 3, afu); case UNMAP_TWO: @@ -713,9 +708,34 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) cxl_unmap_afu_irq(cfg->mcctx, 1, afu); case FREE_IRQ: cxl_free_afu_irqs(cfg->mcctx); - case RELEASE_CONTEXT: - cfg->mcctx = NULL; + /* fall through */ + case UNDO_NOOP: + /* No action required */ + break; + } +} + +/** + * term_mc() - terminates the master context + * @cfg: Internal structure associated with the host. + * @level: Depth of allocation, where to begin waterfall tear down. + * + * Safe to call with AFU/MC in partially allocated/initialized state. + */ +static void term_mc(struct cxlflash_cfg *cfg) +{ + int rc = 0; + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + + if (!afu || !cfg->mcctx) { + dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); + return; } + + rc = cxl_stop_context(cfg->mcctx); + WARN_ON(rc); + cfg->mcctx = NULL; } /** @@ -726,10 +746,20 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) */ static void term_afu(struct cxlflash_cfg *cfg) { + /* + * Tear down is carefully orchestrated to ensure + * no interrupts can come in when the problem state + * area is unmapped. + * + * 1) Disable all AFU interrupts + * 2) Unmap the problem state area + * 3) Stop the master context + */ + term_intr(cfg, UNMAP_THREE); if (cfg->afu) stop_afu(cfg); - term_mc(cfg, UNDO_START); + term_mc(cfg); pr_debug("%s: returning\n", __func__); } @@ -1597,41 +1627,24 @@ static int start_afu(struct cxlflash_cfg *cfg) } /** - * init_mc() - create and register as the master context + * init_intr() - setup interrupt handlers for the master context * @cfg: Internal structure associated with the host. * * Return: 0 on success, -errno on failure */ -static int init_mc(struct cxlflash_cfg *cfg) +static enum undo_level init_intr(struct cxlflash_cfg *cfg, + struct cxl_context *ctx) { - struct cxl_context *ctx; - struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int rc = 0; - enum undo_level level; - - ctx = cxl_get_context(cfg->dev); - if (unlikely(!ctx)) - return -ENOMEM; - cfg->mcctx = ctx; - - /* Set it up as a master with the CXL */ - cxl_set_master(ctx); - - /* During initialization reset the AFU to start from a clean slate */ - rc = cxl_afu_reset(cfg->mcctx); - if (unlikely(rc)) { - dev_err(dev, "%s: initial AFU reset failed rc=%d\n", - __func__, rc); - level = RELEASE_CONTEXT; - goto out; - } + enum undo_level level = UNDO_NOOP; rc = cxl_allocate_afu_irqs(ctx, 3); if (unlikely(rc)) { dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n", __func__, rc); - level = RELEASE_CONTEXT; + level = UNDO_NOOP; goto out; } @@ -1661,8 +1674,47 @@ static int init_mc(struct cxlflash_cfg *cfg) level = UNMAP_TWO; goto out; } +out: + return level; +} - rc = 0; +/** + * init_mc() - create and register as the master context + * @cfg: Internal structure associated with the host. + * + * Return: 0 on success, -errno on failure + */ +static int init_mc(struct cxlflash_cfg *cfg) +{ + struct cxl_context *ctx; + struct device *dev = &cfg->dev->dev; + int rc = 0; + enum undo_level level; + + ctx = cxl_get_context(cfg->dev); + if (unlikely(!ctx)) { + rc = -ENOMEM; + goto ret; + } + cfg->mcctx = ctx; + + /* Set it up as a master with the CXL */ + cxl_set_master(ctx); + + /* During initialization reset the AFU to start from a clean slate */ + rc = cxl_afu_reset(cfg->mcctx); + if (unlikely(rc)) { + dev_err(dev, "%s: initial AFU reset failed rc=%d\n", + __func__, rc); + goto ret; + } + + level = init_intr(cfg, ctx); + if (unlikely(level)) { + dev_err(dev, "%s: setting up interrupts failed rc=%d\n", + __func__, rc); + goto out; + } /* This performs the equivalent of the CXL_IOCTL_START_WORK. * The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process @@ -1678,7 +1730,7 @@ ret: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; out: - term_mc(cfg, level); + term_intr(cfg, level); goto ret; } @@ -1751,7 +1803,8 @@ out: err2: kref_put(&afu->mapcount, afu_unmap); err1: - term_mc(cfg, UNDO_START); + term_intr(cfg, UNMAP_THREE); + term_mc(cfg); goto out; } @@ -2502,8 +2555,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, if (unlikely(rc)) dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", __func__, rc); - stop_afu(cfg); - term_mc(cfg, UNDO_START); + term_afu(cfg); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: cfg->state = STATE_FAILTERM; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 0faed42..eb9d8f7 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -79,12 +79,11 @@ #define WWPN_BUF_LEN (WWPN_LEN + 1) enum undo_level { - RELEASE_CONTEXT = 0, + UNDO_NOOP = 0, FREE_IRQ, UNMAP_ONE, UNMAP_TWO, - UNMAP_THREE, - UNDO_START + UNMAP_THREE }; struct dev_dependent_vals { -- cgit v0.10.2 From ea76543127da32dec28af0a13ea1b06625fc085e Mon Sep 17 00:00:00 2001 From: "Manoj N. Kumar" Date: Fri, 25 Mar 2016 14:26:49 -0500 Subject: cxlflash: Move to exponential back-off when cmd_room is not available While profiling the cxlflash_queuecommand() path under a heavy load it was found that number of retries to find cmd_room was fairly high. There are two problems with the current back-off: a) It starts with a udelay of 0 b) It backs-off linearly Tried several approaches (a higher multiple 10*n, 100*n, as well as n^2, 2^n) and found that the exponential back-off(2^n) approach had the least overall cost. Cost as being defined as overall time spent waiting. The fix is to change the linear back-off to an exponential back-off. This solution also takes care of the problem with the initial delay (starts with 1 usec). Signed-off-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Reviewed-by: Johannes Thumshirn Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 1d41807..724b771 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -289,7 +289,7 @@ static void context_reset(struct afu_cmd *cmd) atomic64_set(&afu->room, room); if (room) goto write_rrin; - udelay(nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); pr_err("%s: no cmd_room to send reset\n", __func__); @@ -303,7 +303,7 @@ write_rrin: if (rrin != 0x1) break; /* Double delay each time */ - udelay(2 << nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); } @@ -338,7 +338,7 @@ retry: atomic64_set(&afu->room, room); if (room) goto write_ioarrin; - udelay(nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); dev_err(dev, "%s: no cmd_room to send 0x%X\n", @@ -352,7 +352,7 @@ retry: * afu->room. */ if (nretry++ < MC_ROOM_RETRY_CNT) { - udelay(nretry); + udelay(1 << nretry); goto retry; } -- cgit v0.10.2 From d78540dae77fd18e2eba57e5dc7021953f9506f4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 28 Mar 2016 11:13:16 -0700 Subject: scsi: Declare local symbols static Avoid that building with W=1 causes gcc to report warnings about symbols that have not been declared. Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinicke Reviewed-by: Christoph Hellwig Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 92ffd24..2b642b1 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -81,6 +81,7 @@ const char *scsi_host_state_name(enum scsi_host_state state) return name; } +#ifdef CONFIG_SCSI_DH static const struct { unsigned char value; char *name; @@ -94,7 +95,7 @@ static const struct { { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" }, }; -const char *scsi_access_state_name(unsigned char state) +static const char *scsi_access_state_name(unsigned char state) { int i; char *name = NULL; @@ -107,6 +108,7 @@ const char *scsi_access_state_name(unsigned char state) } return name; } +#endif static int check_set(unsigned long long *val, char *src) { @@ -226,7 +228,7 @@ show_shost_state(struct device *dev, struct device_attribute *attr, char *buf) } /* DEVICE_ATTR(state) clashes with dev_attr_state for sdev */ -struct device_attribute dev_attr_hstate = +static struct device_attribute dev_attr_hstate = __ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); static ssize_t @@ -401,7 +403,7 @@ static struct attribute *scsi_sysfs_shost_attrs[] = { NULL }; -struct attribute_group scsi_shost_attr_group = { +static struct attribute_group scsi_shost_attr_group = { .attrs = scsi_sysfs_shost_attrs, }; -- cgit v0.10.2 From 38c315992338a6c26050477b50700e0f8e08ff96 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 28 Mar 2016 11:14:04 -0700 Subject: scsi_dh_alua: Fix a recently introduced deadlock While retesting the SRP initiator I ran the command "rmmod mlx4_ib" while I/O was in progress. That command triggers SCSI device removal indirectly. Avoid that this action triggers the following deadlock: ================================= [ INFO: inconsistent lock state ] 4.6.0-rc0-dbg+ #2 Tainted: G O --------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. multipathd/484 [HC0[0]:SC0[0]:HE1:SE1] takes: (&(&pg->lock)->rlock){+.?...}, at: [] alua_bus_detach+0x52/0xa0 [scsi_dh_alua] {IN-SOFTIRQ-W} state was registered at: [] __lock_acquire+0x7e9/0x1ad0 [] lock_acquire+0x60/0x80 [] _raw_spin_lock_irqsave+0x3e/0x60 [] alua_rtpg_queue+0x41/0x1d0 [scsi_dh_alua] [] alua_check+0xe1/0x220 [scsi_dh_alua] [] alua_check_sense+0x99/0xb0 [scsi_dh_alua] [] scsi_check_sense+0x71/0x3f0 [] scsi_decide_disposition+0x18b/0x1d0 [] scsi_softirq_done+0x52/0x140 [] blk_done_softirq+0x52/0x90 [] __do_softirq+0x10f/0x230 [] irq_exit+0xa8/0xb0 [] do_IRQ+0x65/0x110 [] ret_from_intr+0x0/0x19 [] kmem_cache_alloc+0x151/0x190 [] create_object+0x34/0x2d0 [] kmemleak_alloc_percpu+0x56/0xd0 [] pcpu_alloc+0x38d/0x660 [] __alloc_percpu_gfp+0xd/0x10 [] __percpu_counter_init+0x55/0xb0 [] blkg_alloc+0x79/0x230 [] blkcg_init_queue+0x26/0x1d0 [] blk_alloc_queue_node+0x27d/0x2e0 [] dm_create+0x20c/0x570 [dm_mod] [] dev_create+0x56/0x2c0 [dm_mod] [] ctl_ioctl+0x26e/0x520 [dm_mod] [] dm_ctl_ioctl+0xe/0x20 [dm_mod] [] do_vfs_ioctl+0x8e/0x660 [] SyS_ioctl+0x3c/0x70 [] entry_SYSCALL_64_fastpath+0x1c/0xac irq event stamp: 4290931 hardirqs last enabled at (4290931): [ 1662.892772] [] _raw_spin_unlock_irqrestore+0x31/0x50 hardirqs last disabled at (4290930): [] _raw_spin_lock_irqsave+0x17/0x60 softirqs last enabled at (4290774): [] __do_softirq+0x1cb/0x230 softirqs last disabled at (4289831): [] irq_exit+0xa8/0xb0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&pg->lock)->rlock); lock(&(&pg->lock)->rlock); *** DEADLOCK *** 2 locks held by multipathd/484: #0: (&bdev->bd_mutex){+.+.+.}, at: [] __blkdev_put+0x33/0x360 #1: (sd_ref_mutex){+.+...}, at: [] scsi_disk_put+0x1c/0x40 stack backtrace: CPU: 6 PID: 484 Comm: multipathd Tainted: G O 4.6.0-rc0-dbg+ #2 Call Trace: [] dump_stack+0x67/0x92 [] print_usage_bug+0x215/0x240 [] mark_lock+0x54a/0x610 [] __lock_acquire+0x845/0x1ad0 [] lock_acquire+0x60/0x80 [] _raw_spin_lock+0x33/0x50 [] alua_bus_detach+0x52/0xa0 [scsi_dh_alua] [] scsi_dh_release_device+0x17/0x50 [] scsi_device_dev_release_usercontext+0x2a/0x120 [] execute_in_process_context+0x80/0x90 [] scsi_device_dev_release+0x17/0x20 [] device_release+0x2d/0x90 [] kobject_release+0x7a/0x190 [] kobject_put+0x26/0x50 [] put_device+0x12/0x20 [] scsi_device_put+0x26/0x30 [] scsi_disk_put+0x2d/0x40 [] sd_release+0x48/0xb0 [] __blkdev_put+0x29e/0x360 [] blkdev_put+0x49/0x170 [] blkdev_close+0x20/0x30 [] __fput+0xe8/0x1f0 [] ____fput+0x9/0x10 [] task_work_run+0x6e/0xa0 [] exit_to_usermode_loop+0xa9/0xb0 [] syscall_return_slowpath+0xb0/0xc0 [] entry_SYSCALL_64_fastpath+0xaa/0xac Fixes: cb0a168cb6b8 (scsi_dh_alua: update 'access_state' field) Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Reviewed-by: Laurence Oberman Reviewed-by: Hannes Reinicke Reviewed-by: Christoph Hellwig Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index a404a41..8eaed05 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -1112,9 +1112,9 @@ static void alua_bus_detach(struct scsi_device *sdev) h->sdev = NULL; spin_unlock(&h->pg_lock); if (pg) { - spin_lock(&pg->lock); + spin_lock_irq(&pg->lock); list_del_rcu(&h->node); - spin_unlock(&pg->lock); + spin_unlock_irq(&pg->lock); kref_put(&pg->kref, release_port_group); } sdev->handler_data = NULL; -- cgit v0.10.2 From f08bb1e0dbdd0297258d0b8cd4dbfcc057e57b2a Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 28 Mar 2016 21:18:56 -0400 Subject: sd: Fix excessive capacity printing on devices with blocks bigger than 512 bytes During revalidate we check whether device capacity has changed before we decide whether to output disk information or not. The check for old capacity failed to take into account that we scaled sdkp->capacity based on the reported logical block size. And therefore the capacity test would always fail for devices with sectors bigger than 512 bytes and we would print several copies of the same discovery information. Avoid scaling sdkp->capacity and instead adjust the value on the fly when setting the block device capacity and generating fake C/H/S geometry. Signed-off-by: Martin K. Petersen Cc: Reported-by: Hannes Reinecke Reviewed-by: Hannes Reinicke Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5a5457a..8401697 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1275,18 +1275,19 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); struct scsi_device *sdp = sdkp->device; struct Scsi_Host *host = sdp->host; + sector_t capacity = logical_to_sectors(sdp, sdkp->capacity); int diskinfo[4]; /* default to most commonly used values */ - diskinfo[0] = 0x40; /* 1 << 6 */ - diskinfo[1] = 0x20; /* 1 << 5 */ - diskinfo[2] = sdkp->capacity >> 11; - + diskinfo[0] = 0x40; /* 1 << 6 */ + diskinfo[1] = 0x20; /* 1 << 5 */ + diskinfo[2] = capacity >> 11; + /* override with calculated, extended default, or driver values */ if (host->hostt->bios_param) - host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo); + host->hostt->bios_param(sdp, bdev, capacity, diskinfo); else - scsicam_bios_param(bdev, sdkp->capacity, diskinfo); + scsicam_bios_param(bdev, capacity, diskinfo); geo->heads = diskinfo[0]; geo->sectors = diskinfo[1]; @@ -2337,14 +2338,6 @@ got_data: if (sdkp->capacity > 0xffffffff) sdp->use_16_for_rw = 1; - /* Rescale capacity to 512-byte units */ - if (sector_size == 4096) - sdkp->capacity <<= 3; - else if (sector_size == 2048) - sdkp->capacity <<= 2; - else if (sector_size == 1024) - sdkp->capacity <<= 1; - blk_queue_physical_block_size(sdp->request_queue, sdkp->physical_block_size); sdkp->device->sector_size = sector_size; @@ -2812,11 +2805,6 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp) return 0; } -static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks) -{ - return blocks << (ilog2(sdev->sector_size) - 9); -} - /** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. @@ -2900,7 +2888,7 @@ static int sd_revalidate_disk(struct gendisk *disk) /* Combine with controller limits */ q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q)); - set_capacity(disk, sdkp->capacity); + set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity)); sd_config_write_same(sdkp); kfree(buffer); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 5f2a84a..654630b 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -65,7 +65,7 @@ struct scsi_disk { struct device dev; struct gendisk *disk; atomic_t openers; - sector_t capacity; /* size in 512-byte sectors */ + sector_t capacity; /* size in logical blocks */ u32 max_xfer_blocks; u32 opt_xfer_blocks; u32 max_ws_blocks; @@ -146,6 +146,11 @@ static inline int scsi_medium_access_command(struct scsi_cmnd *scmd) return 0; } +static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blocks) +{ + return blocks << (ilog2(sdev->sector_size) - 9); +} + /* * A DIF-capable target device can be formatted with different * protection schemes. Currently 0 through 3 are defined: -- cgit v0.10.2 From 5ddfe0858ea7848c5d4efe3f4319e7543522e0ee Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 1 Apr 2016 08:57:36 +0200 Subject: scsi: Do not attach VPD to devices that don't support it The patch "scsi: rescan VPD attributes" introduced a regression in which devices that don't support VPD were being scanned for VPD attributes anyway. This could cause issues for some devices and should be avoided so the check for scsi_level has been moved out of scsi_add_lun and into scsi_attach_vpd so that all callers will not scan VPD for devices that don't support it. [mkp: Merge fix] Fixes: 09e2b0b14690 ("scsi: rescan VPD attributes") Cc: #v4.5+ Suggested-by: Alexander Duyck Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b1bf42b..1deb6ad 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -784,8 +784,9 @@ void scsi_attach_vpd(struct scsi_device *sdev) int pg83_supported = 0; unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL; - if (sdev->skip_vpd_pages) + if (!scsi_device_supports_vpd(sdev)) return; + retry_pg0: vpd_buf = kmalloc(vpd_len, GFP_KERNEL); if (!vpd_buf) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8401697..974ca5b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2788,23 +2788,6 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->ws10 = 1; } -static int sd_try_extended_inquiry(struct scsi_device *sdp) -{ - /* Attempt VPD inquiry if the device blacklist explicitly calls - * for it. - */ - if (sdp->try_vpd_pages) - return 1; - /* - * Although VPD inquiries can go to SCSI-2 type devices, - * some USB ones crash on receiving them, and the pages - * we currently ask for are for SPC-3 and beyond - */ - if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages) - return 1; - return 0; -} - /** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. @@ -2844,7 +2827,7 @@ static int sd_revalidate_disk(struct gendisk *disk) if (sdkp->media_present) { sd_read_capacity(sdkp, buffer); - if (sd_try_extended_inquiry(sdp)) { + if (scsi_device_supports_vpd(sdp)) { sd_read_block_provisioning(sdkp); sd_read_block_limits(sdkp); sd_read_block_characteristics(sdkp); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c067019..74d79bd 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -516,6 +516,31 @@ static inline int scsi_device_tpgs(struct scsi_device *sdev) return sdev->inquiry ? (sdev->inquiry[5] >> 4) & 0x3 : 0; } +/** + * scsi_device_supports_vpd - test if a device supports VPD pages + * @sdev: the &struct scsi_device to test + * + * If the 'try_vpd_pages' flag is set it takes precedence. + * Otherwise we will assume VPD pages are supported if the + * SCSI level is at least SPC-3 and 'skip_vpd_pages' is not set. + */ +static inline int scsi_device_supports_vpd(struct scsi_device *sdev) +{ + /* Attempt VPD inquiry if the device blacklist explicitly calls + * for it. + */ + if (sdev->try_vpd_pages) + return 1; + /* + * Although VPD inquiries can go to SCSI-2 type devices, + * some USB ones crash on receiving them, and the pages + * we currently ask for are for SPC-3 and beyond + */ + if (sdev->scsi_level > SCSI_SPC_2 && !sdev->skip_vpd_pages) + return 1; + return 0; +} + #define MODULE_ALIAS_SCSI_DEVICE(type) \ MODULE_ALIAS("scsi:t-" __stringify(type) "*") #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x" -- cgit v0.10.2