Re: [PATCH 0/2] mpt3sas: Reference counting fixes from in-flight mpt2sas
Hi Sreekanth, On Thu, 2015-08-27 at 10:37 +0530, Sreekanth Reddy wrote: > HI Nicholas & Calvin, > > Thanks for the patchset. Sure We will review and we do some unit > testing on this patch series. Currently my bandwidth is occupied with > some internal activity, so by end of next week I will acknowledge this > series if all the thing are fine with this patch series. > Thanks for the quick response. So Calvin's mpt2sas series has been merged into scsi.git/for-next. Since this series is AFAICT functionally identical to Calvin's changes, I assume JEJB will be merging it up for v4.3-rc1 soon too. Also, we're probably not the only ones hitting this class of OOPsen, so it will certainly need to be picked up for stable at some point, and any further regressions will need to be addressed. Please keep the list posted of your testing progress. For reference, here are prerequisites need to apply atop v3.14.y: 4dc06fd mpt3sas: delay scsi_add_host call to work with scsi-mq 35b6236 mpt3sas: combine fw_event_work and its event_data 62c4da4 mpt3sas: correct scsi_{target,device} hostdata allocation --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] aic94xx: Skip reading user settings if flash is not found
On Mon, Jul 06, 2015 at 01:07:58PM +0200, Hannes Reinecke wrote: > If no user settings are found it's pointless trying to > read them from flash. So skip that step. > This also fixes a compilation warning about uninitialized variables in > aic94xx. This looks okay to me. Reviewed-by: Christoph Hellwig -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH V6 08/10] [SCSI] aacraid: Send commit-config to controller firmware
Hi Christoph, Hi Tomas, After discussed internally, this driver patch is required only if "auto commit" support is not available in the controller firmware. We have fix in the released controller firmware, so this driver patch is not needed. I'm removing this patch in V7. Hi James, As you suggested, will keep the review-tags going V6->V7 and add reviewers in CC list. Thanks, Mahesh -Original Message- From: Christoph Hellwig [mailto:h...@infradead.org] Sent: Tuesday, August 25, 2015 8:41 PM To: Tomas Henzl Cc: Mahesh Rajashekhara; jbottom...@parallels.com; linux-scsi@vger.kernel.org; aacr...@pmc-sierra.com; Harry Yang; Rich Bono Subject: Re: [PATCH V6 08/10] [SCSI] aacraid: Send commit-config to controller firmware On Tue, Aug 25, 2015 at 04:57:26PM +0200, Tomas Henzl wrote: > On 11.8.2015 07:58, Mahesh Rajashekhara wrote: > > +#if defined(__powerpc__) || defined(__PPC__) || defined(__ppc__) > > + aac_get_config_status(aac, 1); > > +#else > > aac_get_config_status(aac, 0); > > +#endif > > If we use instead > + aac_get_config_status(aac, 1); > on all archs will it make problems ? Yes, that should be our first choice. If that doesn't work it should be a #ifndef CONFIG_X86 with a comment explaining it. -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 0/9] [SCSI] aacraid: Patchset for aacraid driver version 41010
This patchset includes the following changes (bug fixes and new feature support) specific to aacraid driver. V7: Removed patch 08 of V6. Keep the review-tags going V6->V7. V6: Applied driver update change at the end. Merged 10 and 11 of V5 into 9 of V6. AAC_MAX_MSIX definition change. aac_msi option description and subject change. Removed 'reviewed-by' tag. V5: Splited patch 10 from V4 into 2 Added one more patch to request minimum 2 MSIx. V4: Updated code with pci_enable_msix_range instead of exact. V3: Increased msleep() time from 1 to 20. Created new patch for pci_enable_msix() replacement. Changed subject/description of patch 03. Mahesh Rajashekhara (9): [SCSI] aacraid: Fix for logical device name and UID not exposed to the OS [SCSI] aacraid: Add Power Management support [SCSI] aacraid: Change interrupt mode to MSI for series-6 controller [SCSI] aacraid: Enable 64-bit write to controller register [SCSI] aacraid: Tune response path if IsFastPath bit set [SCSI] aacraid: Reset irq affinity hints before releasing irq [SCSI] aacraid: Unblock IOCTLs to controller once system resumed from suspend [SCSI] aacraid: Replace pci_enable_msix() with pci_enable_msix_range() [SCSI] aacraid: Update driver version drivers/scsi/aacraid/aachba.c | 265 +--- drivers/scsi/aacraid/aacraid.h | 20 ++- drivers/scsi/aacraid/comminit.c | 147 +++--- drivers/scsi/aacraid/commsup.c | 113 - drivers/scsi/aacraid/linit.c| 152 +++ drivers/scsi/aacraid/rx.c | 1 + drivers/scsi/aacraid/sa.c | 1 + drivers/scsi/aacraid/src.c | 64 +++--- 8 files changed, 480 insertions(+), 283 deletions(-) -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 1/9] [SCSI] aacraid: Fix for logical device name and UID not exposed to the OS
Description: Driver sends the right size of the response buffer. Changes from V2: None Reviewed By: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aachba.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 9b3dd6e..fe59b00 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -570,7 +570,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_name), + sizeof(struct aac_get_name_resp), FsaNormal, 0, 1, (fib_callback)get_container_name_callback, @@ -1052,7 +1052,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_serial), + sizeof(struct aac_get_serial_resp), FsaNormal, 0, 1, (fib_callback) get_container_serial_callback, -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 4/9] [SCSI] aacraid: Enable 64-bit write to controller register
Description: If writeq() not supported, then do atomic two 32bit write Changes from V2: None Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aacraid.h | 9 + drivers/scsi/aacraid/comminit.c | 1 + drivers/scsi/aacraid/src.c | 12 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 62b0999..e54f597 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -844,6 +844,10 @@ struct src_registers { &((AEP)->regs.src.bar0->CSR)) #define src_writel(AEP, CSR, value)writel(value, \ &((AEP)->regs.src.bar0->CSR)) +#if defined(writeq) +#definesrc_writeq(AEP, CSR, value) writeq(value, \ + &((AEP)->regs.src.bar0->CSR)) +#endif #define SRC_ODR_SHIFT 12 #define SRC_IDR_SHIFT 9 @@ -1163,6 +1167,11 @@ struct aac_dev struct fsa_dev_info *fsa_dev; struct task_struct *thread; int cardtype; + /* +*This lock will protect the two 32-bit +*writes to the Inbound Queue +*/ + spinlock_t iq_lock; /* * The following is the device specific extension. diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 45a0a04..b4b6088 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -424,6 +424,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) dev->management_fib_count = 0; spin_lock_init(&dev->manage_lock); spin_lock_init(&dev->sync_lock); + spin_lock_init(&dev->iq_lock); dev->max_fib_size = sizeof(struct hw_fib); dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index eb07b3d..1409a0b 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -447,6 +447,10 @@ static int aac_src_deliver_message(struct fib *fib) u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; +#if !defined(writeq) + unsigned long flags; +#endif + u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size); atomic_inc(&q->numpending); @@ -511,10 +515,14 @@ static int aac_src_deliver_message(struct fib *fib) return -EINVAL; address |= fibsize; } - +#if defined(writeq) + src_writeq(dev, MUnit.IQ_L, (u64)address); +#else + spin_lock_irqsave(&fib->dev->iq_lock, flags); src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0x); src_writel(dev, MUnit.IQ_L, address & 0x); - + spin_unlock_irqrestore(&fib->dev->iq_lock, flags); +#endif return 0; } -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 7/9] [SCSI] aacraid: Unblock IOCTLs to controller once system resumed from suspend
Description: Driver blocks ioctls once it received shutdown/suspend request during suspend/hybernation. This patch unblocks ioctls on resume path. Changes from V2: None Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/linit.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 37375cf..3b6e5c6 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1448,6 +1448,11 @@ static int aac_resume(struct pci_dev *pdev) pci_set_master(pdev); if (aac_acquire_resources(aac)) goto fail_device; + /* + * reset this flag to unblock ioctl() as it was set at + * aac_send_shutdown() to block ioctls from upperlayer + */ + aac->adapter_shutdown = 0; scsi_unblock_requests(shost); return 0; -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 8/9] [SCSI] aacraid: Replace pci_enable_msix() with pci_enable_msix_range()
Description: As pci_enable_msix() deprecated, replaced with pci_enable_msix_range() Changes from V5: Merged 10 and 11 of V5 into this patch. AAC_MAX_MSIX definition change. Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aacraid.h | 2 +- drivers/scsi/aacraid/comminit.c | 20 ++-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 7b95227..2de5ebc 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@ * D E F I N E S **/ -#define AAC_MAX_MSIX 8 /* vectors */ +#define AAC_MAX_MSIX 32 /* vectors */ #define AAC_PCI_MSI_ENABLE 0x8000 enum { diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index b4b6088..0e954e3 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -338,7 +338,7 @@ static int aac_comm_init(struct aac_dev * dev) void aac_define_int_mode(struct aac_dev *dev) { - int i, msi_count; + int i, msi_count, min_msix; msi_count = i = 0; /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ @@ -366,22 +366,14 @@ void aac_define_int_mode(struct aac_dev *dev) if (msi_count > 1 && pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { - i = pci_enable_msix(dev->pdev, + min_msix = 2; + i = pci_enable_msix_range(dev->pdev, dev->msixentry, + min_msix, msi_count); -/* Check how many MSIX vectors are allocated */ - if (i >= 0) { + if (i > 0) { dev->msi_enabled = 1; - if (i) { - msi_count = i; - if (pci_enable_msix(dev->pdev, - dev->msixentry, - msi_count)) { - dev->msi_enabled = 0; - printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", - dev->name, dev->id, i); - } - } + msi_count = i; } else { dev->msi_enabled = 0; printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 9/9] [SCSI] aacraid: Update driver version
Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aacraid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 2de5ebc..074878b 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -62,7 +62,7 @@ enum { #definePMC_GLOBAL_INT_BIT0 0x0001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 40709 +# define AAC_DRIVER_BUILD 41010 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 5/9] [SCSI] aacraid: Tune response path if IsFastPath bit set
Description: If 'IsFastPath' bit is set, then response path assumes no error and skips error check. Changes from V2: None Reviewed-by: Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aachba.c | 259 ++ 1 file changed, 137 insertions(+), 122 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 05f2a02..e4c2437 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -2977,11 +2977,16 @@ static void aac_srb_callback(void *context, struct fib * fibptr) return; BUG_ON(fibptr == NULL); - dev = fibptr->dev; - srbreply = (struct aac_srb_reply *) fib_data(fibptr); + scsi_dma_unmap(scsicmd); + /* expose physical device if expose_physicald flag is on */ + if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) + && expose_physicals > 0) + aac_expose_phy_device(scsicmd); + + srbreply = (struct aac_srb_reply *) fib_data(fibptr); scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { @@ -2994,147 +2999,157 @@ static void aac_srb_callback(void *context, struct fib * fibptr) */ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) - le32_to_cpu(srbreply->data_xfer_length)); - } - - scsi_dma_unmap(scsicmd); - - /* expose physical device if expose_physicald flag is on */ - if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) - && expose_physicals > 0) - aac_expose_phy_device(scsicmd); + /* +* First check the fib status +*/ - /* -* First check the fib status -*/ + if (le32_to_cpu(srbreply->status) != ST_OK) { + int len; - if (le32_to_cpu(srbreply->status) != ST_OK){ - int len; - printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } + printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8 + | SAM_STAT_CHECK_CONDITION; + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } - /* -* Next check the srb status -*/ - switch( (le32_to_cpu(srbreply->srb_status))&0x3f){ - case SRB_STATUS_ERROR_RECOVERY: - case SRB_STATUS_PENDING: - case SRB_STATUS_SUCCESS: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_DATA_OVERRUN: - switch(scsicmd->cmnd[0]){ - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) { - printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); - } else { - printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); + /* +* Next check the srb status +*/ + switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { + case SRB_STATUS_ERROR_RECOVERY: + case SRB_STATUS_PENDING: + case SRB_STATUS_SUCCESS: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case SRB_STATUS_DATA_OVERRUN: + switch (scsicmd->cmnd[0]) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + case READ_16: + case WRITE_16: + if (le32_to_cpu(srbreply->data_xfer_length) +
[PATCH V7 3/9] [SCSI] aacraid: Change interrupt mode to MSI for series-6 controller
Description: This change always sets MSI interrupt mode for series-6 controller. Changes from V2: aac_msi option description and subject change. Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aachba.c | 2 +- drivers/scsi/aacraid/src.c| 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index fe59b00..05f2a02 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -259,7 +259,7 @@ MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" " 0=off, 1=on"); module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(msi, "IRQ handling." - " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)"); + " 0=PIC(default), 1=MSI, 2=MSI-X)"); module_param(startup_timeout, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" " adapter to have it's kernel up and\n" diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index b147341..eb07b3d 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -742,7 +742,7 @@ int aac_src_init(struct aac_dev *dev) if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) goto error_iounmap; - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); + dev->msi = !pci_enable_msi(dev->pdev); dev->aac_msix[0].vector_no = 0; dev->aac_msix[0].dev = dev; -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH V7 6/9] [SCSI] aacraid: Reset irq affinity hints before releasing irq
Description: Reset irq affinity hints before releasing IRQ Removed duplicate code of IRQ acquire/release Changes from V2: None Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aacraid.h | 2 + drivers/scsi/aacraid/commsup.c | 113 ++--- drivers/scsi/aacraid/src.c | 48 ++--- 3 files changed, 88 insertions(+), 75 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index e54f597..7b95227 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -2110,6 +2110,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) #define AAC_OWNER_ERROR_HANDLER0x103 #define AAC_OWNER_FIRMWARE 0x106 +int aac_acquire_irq(struct aac_dev *dev); +void aac_free_irq(struct aac_dev *dev); const char *aac_driverinfo(struct Scsi_Host *); struct fib *aac_fib_alloc(struct aac_dev *dev); int aac_fib_setup(struct aac_dev *dev); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 4da5749..a1f90fe 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1270,13 +1270,12 @@ retry_next: static int _aac_reset_adapter(struct aac_dev *aac, int forced) { int index, quirks; - int retval, i; + int retval; struct Scsi_Host *host; struct scsi_device *dev; struct scsi_cmnd *command; struct scsi_cmnd *command_list; int jafo = 0; - int cpu; /* * Assumptions: @@ -1339,35 +1338,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) aac->comm_phys = 0; kfree(aac->queues); aac->queues = NULL; - cpu = cpumask_first(cpu_online_mask); - if (aac->pdev->device == PMC_DEVICE_S6 || - aac->pdev->device == PMC_DEVICE_S7 || - aac->pdev->device == PMC_DEVICE_S8 || - aac->pdev->device == PMC_DEVICE_S9) { - if (aac->max_msix > 1) { - for (i = 0; i < aac->max_msix; i++) { - if (irq_set_affinity_hint( - aac->msixentry[i].vector, - NULL)) { - printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n", - aac->name, - aac->id, - cpu); - } - cpu = cpumask_next(cpu, - cpu_online_mask); - free_irq(aac->msixentry[i].vector, -&(aac->aac_msix[i])); - } - pci_disable_msix(aac->pdev); - } else { - free_irq(aac->pdev->irq, &(aac->aac_msix[0])); - } - } else { - free_irq(aac->pdev->irq, aac); - } - if (aac->msi) - pci_disable_msi(aac->pdev); + aac_free_irq(aac); kfree(aac->fsa_dev); aac->fsa_dev = NULL; quirks = aac_get_driver_ident(index)->quirks; @@ -1978,3 +1949,83 @@ int aac_command_thread(void *data) dev->aif_thread = 0; return 0; } + +int aac_acquire_irq(struct aac_dev *dev) +{ + int i; + int j; + int ret = 0; + int cpu; + + cpu = cpumask_first(cpu_online_mask); + if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + dev->aac_msix[i].vector_no = i; + dev->aac_msix[i].dev = dev; + if (request_irq(dev->msixentry[i].vector, + dev->a_ops.adapter_intr, + 0, "aacraid", &(dev->aac_msix[i]))) { + printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", + dev->name, dev->id, i); + for (j = 0 ; j < i ; j++) + free_irq(dev->msixentry[j].vector, +&(dev->aac_msix[j])); + pci_disable_msix(dev->pdev); + ret = -1; + } + if (irq_set_affinity_hint(dev->msixentry[i].vector, + get_cpu_mask(cpu))) { + printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n", + dev->name, dev->id, cpu); + } + cpu = cpumask_next(cpu, cpu_online_mask); +
[PATCH V7 2/9] [SCSI] aacraid: Add Power Management support
Description: * .suspend() and .resume() routines implemented in the driver * aac_release_resources() initiates firmware shutdown * aac_acquire_resources re-initializes the host interface Changes from V2: Increased msleep(1) to msleep(20) Reverted pci_enable_msix_exact() to pci_enable_msix() as this change has moved into a separate patch Reviewed-by: Tomas Henzl , Murthy Bhat , Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- drivers/scsi/aacraid/aacraid.h | 5 ++ drivers/scsi/aacraid/comminit.c | 154 drivers/scsi/aacraid/linit.c| 147 ++ drivers/scsi/aacraid/rx.c | 1 + drivers/scsi/aacraid/sa.c | 1 + drivers/scsi/aacraid/src.c | 2 + 6 files changed, 232 insertions(+), 78 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 40fe65c..62b0999 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -547,6 +547,7 @@ struct adapter_ops int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); int (*adapter_restart)(struct aac_dev *dev, int bled); + void (*adapter_start)(struct aac_dev *dev); /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); irq_handler_t adapter_intr; @@ -1247,6 +1248,9 @@ struct aac_dev #define aac_adapter_restart(dev,bled) \ (dev)->a_ops.adapter_restart(dev,bled) +#define aac_adapter_start(dev) \ + ((dev)->a_ops.adapter_start(dev)) + #define aac_adapter_ioremap(dev, size) \ (dev)->a_ops.adapter_ioremap(dev, size) @@ -2127,6 +2131,7 @@ int aac_sa_init(struct aac_dev *dev); int aac_src_init(struct aac_dev *dev); int aac_srcv_init(struct aac_dev *dev); int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); +void aac_define_int_mode(struct aac_dev *dev); unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 45db84a..45a0a04 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -43,8 +43,6 @@ #include "aacraid.h" -static void aac_define_int_mode(struct aac_dev *dev); - struct aac_common aac_config = { .irq_mod = 1 }; @@ -338,6 +336,82 @@ static int aac_comm_init(struct aac_dev * dev) return 0; } +void aac_define_int_mode(struct aac_dev *dev) +{ + int i, msi_count; + + msi_count = i = 0; + /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ + if (dev->max_msix == 0 || + dev->pdev->device == PMC_DEVICE_S6 || + dev->sync_mode) { + dev->max_msix = 1; + dev->vector_cap = + dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB; + return; + } + + /* Don't bother allocating more MSI-X vectors than cpus */ + msi_count = min(dev->max_msix, + (unsigned int)num_online_cpus()); + + dev->max_msix = msi_count; + + if (msi_count > AAC_MAX_MSIX) + msi_count = AAC_MAX_MSIX; + + for (i = 0; i < msi_count; i++) + dev->msixentry[i].entry = i; + + if (msi_count > 1 && + pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { + i = pci_enable_msix(dev->pdev, + dev->msixentry, + msi_count); +/* Check how many MSIX vectors are allocated */ + if (i >= 0) { + dev->msi_enabled = 1; + if (i) { + msi_count = i; + if (pci_enable_msix(dev->pdev, + dev->msixentry, + msi_count)) { + dev->msi_enabled = 0; + printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", + dev->name, dev->id, i); + } + } + } else { + dev->msi_enabled = 0; + printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", + dev->name, dev->id, i); + } + } + + if (!dev->msi_enabled) { + msi_count = 1; + i = pci_enable_msi(dev->pdev); + + if (!i) { + dev->msi_ena
Re: [PATCH v1 14/15] scsi: ufs: commit descriptors before setting the doorbell
> On Tue, Aug 25, 2015 at 7:36 AM, wrote: >>> On Aug 21, 2015 3:10 PM, "Yaniv Gardi" wrote: Add a write memory barrier to make sure descriptors prepared are actually written to memory before ringing the doorbell. We have also added the write memory barrier after ringing the doorbell register so that controller sees the new request immediately. Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index fef0660..876148b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -833,6 +833,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + /* Make sure that doorbell is committed immediately */ + wmb(); >>> >>> Is this really necessary? Is there a measurable difference? >> >> I'm not sure if there is a measurable difference, but as the Door-Bell >> register is the one that actually responsible for the HW execution of >> the >> requests, anyhow, it's recommended to its value will be written >> instantly to the memory. > > A barrier doesn't guarantee speed, only ordering. Unless you can > measure the difference, you should not have it. Rob, let me have an example: context#1 updates outstanding_reqs variable and write(DOOR_BELL) context#2 upon interrupt of a request completion the following happens: report completion on each one of the bits in: outstanding_reqs ^ read(DOOR_BELL); 0. let's assume the DOOR_BELL = 0x1 (which means 1 active request in slot 0) 1. context#1: update the DOOR_BELL to be 0x3; (2 active requests: in slot 0 and 1) 2. the new value 0x3 is still not written to the DR so DORR_BELL is still 0x1, but outstanding_reqs is already updated = 0x3 3. the request in slot 0 just completed, and interrupt happens, so DORR_BELL is now 0 (request in slot 0 completed) 4. context#2: outstanding_reqs ^ read(DOOR_BELL) = 0x3 ^ 0x0 = 0x3 => wrong conclusion since the request in slot 1 never completed, and actually never started. > >> Also, as the Interrupt context reads this register, and compare it to >> the >> SW mirroring value (hba->outstanding_reqs) in order to realize what >> requests are already completed, it's important to get the correct value >> by reading this register, otherwise we might realize a request >> completion >> while it was never even submitted. > > If a register read can pass a register write out of order, then your > h/w is broken. Plus what if the interrupt occurs before the barrier. > > Rob > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/10] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate()
When calling scsi_dh_activate() we should be returning SCSI_DH_NOTCONN if the device handler couldn't be attached. Reviewed-by: Bart van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_dh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 954ca5e..2d93bc9 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -325,6 +325,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (!sdev->handler) goto out_fn; + err = SCSI_DH_NOTCONN; if (sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) goto out_fn; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/10] scsi_dh: don't allow to detach device handlers at runtime
From: Christoph Hellwig The I/O submission and completion pathes call into the device handler without any synchronization agains detachment. So disallow detaching device handlers at runtime. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/scsi_dh.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 489083c..954ca5e 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -180,8 +180,10 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Detach from a device handler */ - scsi_dh_handler_detach(sdev); - err = 0; + sdev_printk(KERN_WARNING, sdev, + "can't detach handler %s.\n", + sdev->handler->name); + err = -EINVAL; } else if (!strncmp(buf, "activate", 8)) { /* * Activate a device handler -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/10] scsi_dh: add a common helper to get a scsi_device from a request_queue
From: Christoph Hellwig And cleanup the various messy opencoded versions of this. Note that this moves the sdev_state checks outside the queue_lock coverage, but as we don't hold the lock over the activation they are only advisory anyway. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/scsi_dh.c | 99 +++--- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index f752a45..489083c 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -282,6 +282,20 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) } EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); +static struct scsi_device *get_sdev_from_queue(struct request_queue *q) +{ + struct scsi_device *sdev; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = q->queuedata; + if (!sdev || !get_device(&sdev->sdev_gendev)) + sdev = NULL; + spin_unlock_irqrestore(q->queue_lock, flags); + + return sdev; +} + /* * scsi_dh_activate - activate the path associated with the scsi_device * corresponding to the given request queue. @@ -297,41 +311,37 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); */ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) { - int err = 0; - unsigned long flags; struct scsi_device *sdev; - struct device *dev = NULL; + int err = SCSI_DH_NOSYS; - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; + sdev = get_sdev_from_queue(q); if (!sdev) { - spin_unlock_irqrestore(q->queue_lock, flags); - err = SCSI_DH_NOSYS; if (fn) fn(data, err); return err; } - dev = get_device(&sdev->sdev_gendev); - if (!sdev->handler || !dev || - sdev->sdev_state == SDEV_CANCEL || + if (!sdev->handler) + goto out_fn; + if (sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) - err = SCSI_DH_NOSYS; - if (sdev->sdev_state == SDEV_OFFLINE) - err = SCSI_DH_DEV_OFFLINED; - spin_unlock_irqrestore(q->queue_lock, flags); + goto out_fn; - if (err) { - if (fn) - fn(data, err); - goto out; - } + err = SCSI_DH_DEV_OFFLINED; + if (sdev->sdev_state == SDEV_OFFLINE) + goto out_fn; if (sdev->handler->activate) err = sdev->handler->activate(sdev, fn, data); -out: - put_device(dev); + +out_put_device: + put_device(&sdev->sdev_gendev); return err; + +out_fn: + if (fn) + fn(data, err); + goto out_put_device; } EXPORT_SYMBOL_GPL(scsi_dh_activate); @@ -347,21 +357,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_activate); */ int scsi_dh_set_params(struct request_queue *q, const char *params) { - int err = -SCSI_DH_NOSYS; - unsigned long flags; struct scsi_device *sdev; + int err = -SCSI_DH_NOSYS; - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (sdev->handler && - sdev->handler->set_params && - get_device(&sdev->sdev_gendev)) - err = 0; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (err) + sdev = get_sdev_from_queue(q); + if (!sdev) return err; - err = sdev->handler->set_params(sdev, params); + + if (sdev->handler && sdev->handler->set_params) + err = sdev->handler->set_params(sdev, params); put_device(&sdev->sdev_gendev); return err; } @@ -375,23 +379,19 @@ EXPORT_SYMBOL_GPL(scsi_dh_set_params); */ int scsi_dh_attach(struct request_queue *q, const char *name) { - unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh; int err = 0; - scsi_dh = scsi_dh_lookup(name); - if (!scsi_dh) - return -EINVAL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - err = -ENODEV; - spin_unlock_irqrestore(q->queue_lock, flags); + sdev = get_sdev_from_queue(q); + if (!sdev) + return -ENODEV; - if (err) - return err; + scsi_dh = scsi_dh_lookup(name); + if (!scsi_dh) { + err = -EINVAL; + goto out_put_device; + } if (sdev->handler) { if (sdev->handler != scsi_dh) @@ -418,22 +418,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach); */ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) { - unsigned long flags;
[PATCH 05/10] scsi_dh: move device matching to the core code
From: Christoph Hellwig Add a single list of devices that need non-ALUA device handlers to the core scsi_dh code so that we can autoload the modules for them at probe time. While this is a little ugly in terms of architecture it actually significantly simplifies the code in addition to the new autoloading functionality. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer --- drivers/scsi/device_handler/scsi_dh_alua.c | 6 --- drivers/scsi/device_handler/scsi_dh_emc.c | 29 -- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 30 --- drivers/scsi/device_handler/scsi_dh_rdac.c | 50 - drivers/scsi/scsi_dh.c | 84 ++--- include/scsi/scsi_device.h | 1 - 6 files changed, 66 insertions(+), 134 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 854b568..ace2457 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -819,11 +819,6 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) } -static bool alua_match(struct scsi_device *sdev) -{ - return (scsi_device_tpgs(sdev) != 0); -} - /* * alua_bus_attach - Attach device handler * @sdev: device to be attached to @@ -877,7 +872,6 @@ static struct scsi_device_handler alua_dh = { .check_sense = alua_check_sense, .activate = alua_activate, .set_params = alua_set_params, - .match = alua_match, }; static int __init alua_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 6ed1caa..fd31e67 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -622,34 +622,6 @@ done: return result; } -static const struct { - char *vendor; - char *model; -} clariion_dev_list[] = { - {"DGC", "RAID"}, - {"DGC", "DISK"}, - {"DGC", "VRAID"}, - {NULL, NULL}, -}; - -static bool clariion_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; clariion_dev_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, - strlen(clariion_dev_list[i].vendor)) && - !strncmp(sdev->model, clariion_dev_list[i].model, - strlen(clariion_dev_list[i].model))) { - return true; - } - } - return false; -} - static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev) { struct clariion_dh_data *h; @@ -698,7 +670,6 @@ static struct scsi_device_handler clariion_dh = { .activate = clariion_activate, .prep_fn= clariion_prep_fn, .set_params = clariion_set_params, - .match = clariion_match, }; static int __init clariion_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 485d995..1bf10d3 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -311,35 +311,6 @@ static int hp_sw_activate(struct scsi_device *sdev, return 0; } -static const struct { - char *vendor; - char *model; -} hp_sw_dh_data_list[] = { - {"COMPAQ", "MSA1000 VOLUME"}, - {"COMPAQ", "HSV110"}, - {"HP", "HSV100"}, - {"DEC", "HSG80"}, - {NULL, NULL}, -}; - -static bool hp_sw_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, - strlen(hp_sw_dh_data_list[i].vendor)) && - !strncmp(sdev->model, hp_sw_dh_data_list[i].model, - strlen(hp_sw_dh_data_list[i].model))) { - return true; - } - } - return false; -} - static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev) { struct hp_sw_dh_data *h; @@ -379,7 +350,6 @@ static struct scsi_device_handler hp_sw_dh = { .detach = hp_sw_bus_detach, .activate = hp_sw_activate, .prep_fn= hp_sw_prep_fn, - .match = hp_sw_match, }; static int __init hp_sw_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index b46ace3..d89616f 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -778,55 +778,6 @@ static int rdac_check_sense(struct scsi_device *sdev, return SCSI_RETURN_NOT_HANDLED; } -static const struct { - char *v
[PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers
From: Christoph Hellwig While allowing dm-mpath to attach device handlers is a functionality we need for backwards compatibility reason there is no reason to reference count them and detach them if dm-mpath stops using the device for some reason. If the device handler works for the given device it can just stay attached, and we can take the retain_hw_handler codepath. Signed-off-by: Christoph Hellwig Acked-by: Mike Snitzer Acked-by: Hannes Reinecke --- drivers/md/dm-mpath.c | 21 +++- drivers/scsi/device_handler/scsi_dh.c | 96 --- include/scsi/scsi_device.h| 1 - include/scsi/scsi_dh.h| 5 -- 4 files changed, 28 insertions(+), 95 deletions(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index eff7bdd..a9f58fd 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -159,12 +159,9 @@ static struct priority_group *alloc_priority_group(void) static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) { struct pgpath *pgpath, *tmp; - struct multipath *m = ti->private; list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { list_del(&pgpath->list); - if (m->hw_handler_name) - scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); dm_put_device(ti, pgpath->path.dev); free_pgpath(pgpath); } @@ -580,6 +577,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps q = bdev_get_queue(p->path.dev->bdev); if (m->retain_attached_hw_handler) { +retain: attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); if (attached_handler_name) { /* @@ -599,20 +597,14 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps } if (m->hw_handler_name) { - /* -* Increments scsi_dh reference, even when using an -* already-attached handler. -*/ r = scsi_dh_attach(q, m->hw_handler_name); if (r == -EBUSY) { - /* -* Already attached to different hw_handler: -* try to reattach with correct one. -*/ - scsi_dh_detach(q); - r = scsi_dh_attach(q, m->hw_handler_name); - } + char b[BDEVNAME_SIZE]; + printk(KERN_INFO "dm-mpath: retaining handler on device %s\n", + bdevname(p->path.dev->bdev, b)); + goto retain; + } if (r < 0) { ti->error = "error attaching hardware handler"; dm_put_device(ti, p->path.dev); @@ -624,7 +616,6 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps if (r < 0) { ti->error = "unable to set hardware " "handler parameters"; - scsi_dh_detach(q); dm_put_device(ti, p->path.dev); goto bad; } diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 1efebc9..869b5bd 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -100,14 +100,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, { struct scsi_dh_data *d; - if (sdev->scsi_dh_data) { - if (sdev->scsi_dh_data->scsi_dh != scsi_dh) - return -EBUSY; - - kref_get(&sdev->scsi_dh_data->kref); - return 0; - } - if (!try_module_get(scsi_dh->module)) return -EINVAL; @@ -120,7 +112,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, } d->scsi_dh = scsi_dh; - kref_init(&d->kref); d->sdev = sdev; spin_lock_irq(sdev->request_queue->queue_lock); @@ -129,12 +120,14 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, return 0; } -static void __detach_handler (struct kref *kref) +/* + * scsi_dh_handler_detach - Detach a device handler from a device + * @sdev - SCSI device the device handler should be detached from + */ +static void scsi_dh_handler_detach(struct scsi_device *sdev) { - struct scsi_dh_data *scsi_dh_data = - container_of(kref, struct scsi_dh_data, kref); + struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; - struct scsi_device *sdev = scsi_dh_data->sdev; scsi_dh->detach(sdev); @@ -147,30 +140,6 @@ st
[PATCH 03/10] scsi_dh: move to drivers/scsi
From: Christoph Hellwig Prepare for building scsi_dh.c into the core SCSI module by moving it to drivers/scsi. Signed-off-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/Makefile | 1 + drivers/scsi/device_handler/Makefile | 1 - drivers/scsi/device_handler/scsi_dh.c | 570 -- drivers/scsi/scsi_dh.c| 570 ++ 4 files changed, 571 insertions(+), 571 deletions(-) delete mode 100644 drivers/scsi/device_handler/scsi_dh.c create mode 100644 drivers/scsi/scsi_dh.c diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 91209e3..22f54b0 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -171,6 +171,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS)+= scsi_proc.o scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-$(CONFIG_PM) += scsi_pm.o +obj-$(CONFIG_SCSI_DH) += scsi_dh.o hv_storvsc-y := storvsc_drv.o diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile index e1d2ea0..09866c5 100644 --- a/drivers/scsi/device_handler/Makefile +++ b/drivers/scsi/device_handler/Makefile @@ -1,7 +1,6 @@ # # SCSI Device Handler # -obj-$(CONFIG_SCSI_DH) += scsi_dh.o obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o obj-$(CONFIG_SCSI_DH_HP_SW)+= scsi_dh_hp_sw.o obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c deleted file mode 100644 index 5bd0af6..000 --- a/drivers/scsi/device_handler/scsi_dh.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * SCSI device handler infrastruture. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2007 - * Authors: - * Chandra Seetharaman - * Mike Anderson - */ - -#include -#include -#include -#include "../scsi_priv.h" - -static DEFINE_SPINLOCK(list_lock); -static LIST_HEAD(scsi_dh_list); - -static struct scsi_device_handler *__scsi_dh_lookup(const char *name) -{ - struct scsi_device_handler *tmp, *found = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp, &scsi_dh_list, list) { - if (!strncmp(tmp->name, name, strlen(tmp->name))) { - found = tmp; - break; - } - } - spin_unlock(&list_lock); - return found; -} - -static struct scsi_device_handler *scsi_dh_lookup(const char *name) -{ - struct scsi_device_handler *dh; - - dh = __scsi_dh_lookup(name); - if (!dh) { - request_module(name); - dh = __scsi_dh_lookup(name); - } - - return dh; -} - -/* - * device_handler_match_function - Match a device handler to a device - * @sdev - SCSI device to be tested - * - * Tests @sdev against the match function of all registered device_handler. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match_function(struct scsi_device *sdev) -{ - struct scsi_device_handler *tmp_dh, *found_dh = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp_dh, &scsi_dh_list, list) { - if (tmp_dh->match && tmp_dh->match(sdev)) { - found_dh = tmp_dh; - break; - } - } - spin_unlock(&list_lock); - return found_dh; -} - -/* - * device_handler_match - Attach a device handler to a device - * @scsi_dh - The device handler to match against or NULL - * @sdev - SCSI device to be tested against @scsi_dh - * - * Tests @sdev against the device handler @scsi_dh or against - * all registered device_handler if @scsi_dh == NULL. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match(struct scsi_device_handler *scsi_dh, -struct scsi_device *sdev) -{ - struct scsi_device_handler *found_dh; - - found_dh = device_handler_match_function(sdev); - - if (scsi_dh && found_dh != scsi_dh) - found_dh = NULL; - - return found_dh; -} - -/* - * scsi_dh_handler_attach - Att
[PATCH 06/10] scsi_dh: kill struct scsi_dh_data
From: Christoph Hellwig Add a ->handler and a ->handler_data field to struct scsi_device and kill this indirection. Also move struct scsi_device_handler to scsi_dh.h so that changes to it don't require rebuilding every SCSI LLDD. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 25 -- drivers/scsi/device_handler/scsi_dh_emc.c | 29 +-- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 25 -- drivers/scsi/device_handler/scsi_dh_rdac.c | 30 +--- drivers/scsi/scsi_dh.c | 75 +++-- drivers/scsi/scsi_error.c | 6 +-- drivers/scsi/scsi_lib.c | 6 +-- include/scsi/scsi_device.h | 25 ++ include/scsi/scsi_dh.h | 17 +++ 9 files changed, 98 insertions(+), 140 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ace2457..cc2773b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -62,7 +62,6 @@ #define ALUA_OPTIMIZE_STPG 1 struct alua_dh_data { - struct scsi_dh_data dh_data; int group_id; int rel_port; int tpgs; @@ -86,11 +85,6 @@ struct alua_dh_data { static char print_alua_state(int); static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); -static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data); -} - static int realloc_buffer(struct alua_dh_data *h, unsigned len) { if (h->buff && h->buff != h->inq) @@ -708,7 +702,7 @@ out: */ static int alua_set_params(struct scsi_device *sdev, const char *params) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; unsigned int optimize = 0, argc; const char *p = params; int result = SCSI_DH_OK; @@ -746,7 +740,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than static int alua_activate(struct scsi_device *sdev, activate_complete fn, void *data) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; int err = SCSI_DH_OK; int stpg = 0; @@ -804,7 +798,7 @@ out: */ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->state == TPGS_STATE_TRANSITIONING) @@ -823,14 +817,14 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) * alua_bus_attach - Attach device handler * @sdev: device to be attached to */ -static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev) +static int alua_bus_attach(struct scsi_device *sdev) { struct alua_dh_data *h; int err; h = kzalloc(sizeof(*h) , GFP_KERNEL); if (!h) - return ERR_PTR(-ENOMEM); + return -ENOMEM; h->tpgs = TPGS_MODE_UNINITIALIZED; h->state = TPGS_STATE_OPTIMIZED; h->group_id = -1; @@ -843,11 +837,11 @@ static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev) if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED) goto failed; - sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME); - return &h->dh_data; + sdev->handler_data = h; + return 0; failed: kfree(h); - return ERR_PTR(-EINVAL); + return -EINVAL; } /* @@ -856,10 +850,11 @@ failed: */ static void alua_bus_detach(struct scsi_device *sdev) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; if (h->buff && h->inq != h->buff) kfree(h->buff); + sdev->handler_data = NULL; kfree(h); } diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index fd31e67..e6fb97c 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -72,7 +72,6 @@ static const char * lun_state[] = }; struct clariion_dh_data { - struct scsi_dh_data dh_data; /* * Flags: * CLARIION_SHORT_TRESPASS @@ -114,13 +113,6 @@ struct clariion_dh_data { int current_sp; }; -static inline struct clariion_dh_data - *get_clariion_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct clariion_dh_data, - dh_data); -} - /* * Parse MODE_SELECT cmd reply. */ @@ -450,7 +442,7 @@ static int clariion
[PATCH 04/10] scsi_dh: integrate into the core SCSI code
From: Christoph Hellwig Stop building scsi_dh as a separate module and integrate it fully into the core SCSI code with explicit callouts at bus scan time. For now the callouts are placed at the same point as the old bus notifiers were called, but in the future we will be able to look at ALUA INQUIRY data earlier on. Note that this also means that the device handler modules need to be loaded by the time we scan the bus. The next patches will add support for autoloading device handlers at bus scan time to make sure they are always loaded if they are enabled in the kernel config. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer --- drivers/scsi/Makefile | 2 +- drivers/scsi/device_handler/Kconfig | 2 +- drivers/scsi/scsi_dh.c | 183 +++- drivers/scsi/scsi_priv.h| 9 ++ drivers/scsi/scsi_sysfs.c | 10 ++ include/scsi/scsi_dh.h | 2 +- 6 files changed, 34 insertions(+), 174 deletions(-) diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 22f54b0..ef260bb 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -171,7 +171,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS)+= scsi_proc.o scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-$(CONFIG_PM) += scsi_pm.o -obj-$(CONFIG_SCSI_DH) += scsi_dh.o +scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o hv_storvsc-y := storvsc_drv.o diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 69abd0a..e5647d5 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig @@ -3,7 +3,7 @@ # menuconfig SCSI_DH - tristate "SCSI Device Handlers" + bool "SCSI Device Handlers" depends on SCSI default n help diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 3c06c72..2d6a8bd 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -57,15 +57,8 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name) return dh; } -/* - * device_handler_match_function - Match a device handler to a device - * @sdev - SCSI device to be tested - * - * Tests @sdev against the match function of all registered device_handler. - * Returns the found device handler or NULL if not found. - */ static struct scsi_device_handler * -device_handler_match_function(struct scsi_device *sdev) +device_handler_match(struct scsi_device *sdev) { struct scsi_device_handler *tmp_dh, *found_dh = NULL; @@ -81,29 +74,6 @@ device_handler_match_function(struct scsi_device *sdev) } /* - * device_handler_match - Attach a device handler to a device - * @scsi_dh - The device handler to match against or NULL - * @sdev - SCSI device to be tested against @scsi_dh - * - * Tests @sdev against the device handler @scsi_dh or against - * all registered device_handler if @scsi_dh == NULL. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match(struct scsi_device_handler *scsi_dh, -struct scsi_device *sdev) -{ - struct scsi_device_handler *found_dh; - - found_dh = device_handler_match_function(sdev); - - if (scsi_dh && found_dh != scsi_dh) - found_dh = NULL; - - return found_dh; -} - -/* * scsi_dh_handler_attach - Attach a device handler to a device * @sdev - SCSI device the device handler should attach to * @scsi_dh - The device handler to attach @@ -211,119 +181,26 @@ static struct device_attribute scsi_dh_state_attr = __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, store_dh_state); -/* - * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh - */ -static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) +int scsi_dh_add_device(struct scsi_device *sdev) { - struct scsi_device *sdev; + struct scsi_device_handler *devinfo; int err; - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - err = device_create_file(&sdev->sdev_gendev, -&scsi_dh_state_attr); - - return 0; -} - -/* - * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh - */ -static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) -{ - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - device_remove_file(&sdev->sdev_gendev, - &scsi_dh_state_attr); - - return 0; -} + err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr); + if (err) + return err; -/* - * scsi_dh_notifier - notifier chain callback - */ -static int scsi_dh_notifier(struct notifier_block *nb, -
[PATCH 00/10] Integrate scsi_dh better into the scsi core V4
This series ties scsi_dh deeper into the scsi core, and fixes all kinds of issues in it, most importantly the race between using and detaching device handlers. Changes since V1: - updated comments / strings based on review feedback - moved scsi_dh.c to drivers/scsi to fix the srcdir = objdir build - changed the old patch 2 to have saner handling of mismatching device handlers in dm. - dropped patch 1: not having a hw handler is fine if we don't plan to change it anyway - dropped patch 3: not necessary anymore. Changes since V2: - Fixup issues during attaching device_handler from dm-multipath - Add patch to clarify scsi_dh_activate() error codes Changes since V3: - Fixup minor bugs discovered during testing - Fixup patch description Christoph Hellwig (8): dm-mpath, scsi_dh: don't let dm detach device handlers dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath scsi_dh: move to drivers/scsi scsi_dh: integrate into the core SCSI code scsi_dh: move device matching to the core code scsi_dh: kill struct scsi_dh_data scsi_dh: add a common helper to get a scsi_device from a request_queue scsi_dh: don't allow to detach device handlers at runtime Hannes Reinecke (2): scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() scsi_dh: move 'dh_state' sysfs attribute to generic code drivers/md/dm-mpath.c | 27 +- drivers/scsi/Makefile | 1 + drivers/scsi/device_handler/Kconfig | 2 +- drivers/scsi/device_handler/Makefile| 1 - drivers/scsi/device_handler/scsi_dh.c | 621 drivers/scsi/device_handler/scsi_dh_alua.c | 31 +- drivers/scsi/device_handler/scsi_dh_emc.c | 58 +-- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 55 +-- drivers/scsi/device_handler/scsi_dh_rdac.c | 80 +--- drivers/scsi/scsi_dh.c | 371 + drivers/scsi/scsi_error.c | 6 +- drivers/scsi/scsi_lib.c | 6 +- drivers/scsi/scsi_priv.h| 9 + drivers/scsi/scsi_sysfs.c | 68 +++ include/scsi/scsi_device.h | 27 +- include/scsi/scsi_dh.h | 29 +- 16 files changed, 527 insertions(+), 865 deletions(-) delete mode 100644 drivers/scsi/device_handler/scsi_dh.c create mode 100644 drivers/scsi/scsi_dh.c -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code
As scsi_dh.c is now always compiled in we should be moving the 'dh_state' attribute to the generic code. Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_dh.c| 67 +-- drivers/scsi/scsi_sysfs.c | 58 2 files changed, 59 insertions(+), 66 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 2d93bc9..1584080 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -153,75 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev) module_put(sdev->handler->module); } -/* - * Functions for sysfs attribute 'dh_state' - */ -static ssize_t -store_dh_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct scsi_device_handler *scsi_dh; - int err = -EINVAL; - - if (sdev->sdev_state == SDEV_CANCEL || - sdev->sdev_state == SDEV_DEL) - return -ENODEV; - - if (!sdev->handler) { - /* -* Attach to a device handler -*/ - if (!(scsi_dh = scsi_dh_lookup(buf))) - return err; - err = scsi_dh_handler_attach(sdev, scsi_dh); - } else { - if (!strncmp(buf, "detach", 6)) { - /* -* Detach from a device handler -*/ - sdev_printk(KERN_WARNING, sdev, - "can't detach handler %s.\n", - sdev->handler->name); - err = -EINVAL; - } else if (!strncmp(buf, "activate", 8)) { - /* -* Activate a device handler -*/ - if (sdev->handler->activate) - err = sdev->handler->activate(sdev, NULL, NULL); - else - err = 0; - } - } - - return err<0?err:count; -} - -static ssize_t -show_dh_state(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - if (!sdev->handler) - return snprintf(buf, 20, "detached\n"); - - return snprintf(buf, 20, "%s\n", sdev->handler->name); -} - -static struct device_attribute scsi_dh_state_attr = - __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, - store_dh_state); - int scsi_dh_add_device(struct scsi_device *sdev) { struct scsi_device_handler *devinfo = NULL; const char *drv; - int err; - - err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr); - if (err) - return err; + int err = 0; drv = scsi_dh_find_driver(sdev); if (drv) @@ -235,7 +171,6 @@ void scsi_dh_remove_device(struct scsi_device *sdev) { if (sdev->handler) scsi_dh_handler_detach(sdev); - device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr); } /* diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index b89..5d64c3f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -875,6 +876,60 @@ sdev_show_function(queue_depth, "%d\n"); static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, sdev_store_queue_depth); +#ifdef CONFIG_SCSI_DH +static ssize_t +sdev_show_dh_state(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + if (!sdev->handler) + return snprintf(buf, 20, "detached\n"); + + return snprintf(buf, 20, "%s\n", sdev->handler->name); +} + +static ssize_t +sdev_store_dh_state(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + int err = -EINVAL; + + if (sdev->sdev_state == SDEV_CANCEL || + sdev->sdev_state == SDEV_DEL) + return -ENODEV; + + if (!sdev->handler) { + /* +* Attach to a device handler +*/ + err = scsi_dh_attach(sdev->request_queue, buf); + } else if (!strncmp(buf, "activate", 8)) { + /* +* Activate a device handler +*/ + if (sdev->handler->activate) + err = sdev->handler->activate(sdev, NULL, NULL); + else + err = 0; + } else if (!strncmp(buf, "detach", 6)) { + /* +* Detach from a device handler +*/ + sdev_printk(KERN_WARNING,
[PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath
From: Christoph Hellwig This way we can reused the same code any attachment method, not just those requested from dm-mpath. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer --- drivers/md/dm-mpath.c | 6 -- drivers/scsi/device_handler/scsi_dh.c | 35 ++- include/scsi/scsi_dh.h| 5 - 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index a9f58fd..5a67671 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -725,12 +725,6 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) return 0; m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL); - if (!try_then_request_module(scsi_dh_handler_exist(m->hw_handler_name), -"scsi_dh_%s", m->hw_handler_name)) { - ti->error = "unknown hardware handler type"; - ret = -EINVAL; - goto fail; - } if (hw_argc > 1) { char *p; diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 869b5bd..5bd0af6 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(list_lock); static LIST_HEAD(scsi_dh_list); -static struct scsi_device_handler *get_device_handler(const char *name) +static struct scsi_device_handler *__scsi_dh_lookup(const char *name) { struct scsi_device_handler *tmp, *found = NULL; @@ -44,6 +44,19 @@ static struct scsi_device_handler *get_device_handler(const char *name) return found; } +static struct scsi_device_handler *scsi_dh_lookup(const char *name) +{ + struct scsi_device_handler *dh; + + dh = __scsi_dh_lookup(name); + if (!dh) { + request_module(name); + dh = __scsi_dh_lookup(name); + } + + return dh; +} + /* * device_handler_match_function - Match a device handler to a device * @sdev - SCSI device to be tested @@ -158,7 +171,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Attach to a device handler */ - if (!(scsi_dh = get_device_handler(buf))) + if (!(scsi_dh = scsi_dh_lookup(buf))) return err; err = scsi_dh_handler_attach(sdev, scsi_dh); } else { @@ -322,8 +335,7 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) */ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) { - - if (get_device_handler(scsi_dh->name)) + if (__scsi_dh_lookup(scsi_dh->name)) return -EBUSY; if (!scsi_dh->attach || !scsi_dh->detach) @@ -350,7 +362,7 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler); int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) { - if (!get_device_handler(scsi_dh->name)) + if (!__scsi_dh_lookup(scsi_dh->name)) return -ENODEV; bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, @@ -455,17 +467,6 @@ int scsi_dh_set_params(struct request_queue *q, const char *params) EXPORT_SYMBOL_GPL(scsi_dh_set_params); /* - * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for - * the given name. FALSE(0) otherwise. - * @name - name of the device handler. - */ -int scsi_dh_handler_exist(const char *name) -{ - return (get_device_handler(name) != NULL); -} -EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); - -/* * scsi_dh_attach - Attach device handler * @q - Request queue that is associated with the scsi_device * the handler should be attached to @@ -478,7 +479,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name) struct scsi_device_handler *scsi_dh; int err = 0; - scsi_dh = get_device_handler(name); + scsi_dh = scsi_dh_lookup(name); if (!scsi_dh) return -EINVAL; diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 99c9196..966b921 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -57,7 +57,6 @@ enum { }; #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); -extern int scsi_dh_handler_exist(const char *); extern int scsi_dh_attach(struct request_queue *, const char *); extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); extern int scsi_dh_set_params(struct request_queue *, const char *); @@ -68,10 +67,6 @@ static inline int scsi_dh_activate(struct request_queue *req, fn(data, 0); return 0; } -static inline int scsi_dh_handler_exist(const char *name) -{ - return 0; -} static inline int scsi_dh_attach(struct request_queue *re
Re: [PATCH v1 14/15] scsi: ufs: commit descriptors before setting the doorbell
>> On Aug 21, 2015 3:10 PM, "Yaniv Gardi" wrote: >>> >>> Add a write memory barrier to make sure descriptors prepared are >>> actually >>> written to memory before ringing the doorbell. We have also added the >>> write memory barrier after ringing the doorbell register so that >>> controller sees the new request immediately. >>> >>> Signed-off-by: Yaniv Gardi >>> >>> --- >>> drivers/scsi/ufs/ufshcd.c | 6 ++ >>> 1 file changed, 6 insertions(+) >>> >>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c >>> index fef0660..876148b 100644 >>> --- a/drivers/scsi/ufs/ufshcd.c >>> +++ b/drivers/scsi/ufs/ufshcd.c >>> @@ -833,6 +833,8 @@ void ufshcd_send_command(struct ufs_hba *hba, >>> unsigned int task_tag) >>> ufshcd_clk_scaling_start_busy(hba); >>> __set_bit(task_tag, &hba->outstanding_reqs); >>> ufshcd_writel(hba, 1 << task_tag, >>> REG_UTP_TRANSFER_REQ_DOOR_BELL); >>> + /* Make sure that doorbell is committed immediately */ >>> + wmb(); >> >> Is this really necessary? Is there a measurable difference? > > I'm not sure if there is a measurable difference, but as the Door-Bell > register is the one that actually responsible for the HW execution of the > requests, anyhow, it's recommended to its value will be written > instantly to the memory. > > Also, as the Interrupt context reads this register, and compare it to the > SW mirroring value (hba->outstanding_reqs) in order to realize what > requests are already completed, it's important to get the correct value > by reading this register, otherwise we might realize a request completion > while it was never even submitted. > >> >>> } >>> >>> /** >>> @@ -1418,6 +1420,8 @@ static int ufshcd_queuecommand(struct Scsi_Host >>> *host, struct scsi_cmnd *cmd) >>> goto out; >>> } >>> >>> + /* Make sure descriptors are ready before ringing the doorbell >>> */ >>> + wmb(); >> >> The writel for the doorbell will do a barrier first. (I didn't check >> what exactly ufshcd_writel does, but that is why I don't like these >> private access wrappers.) the barrier here is important and a must. before it we prepare descriptors. after it we write to DOOR-BELL. (and after the DOOR-BELL we have another one.) if we remove it, we might get the DOOR-BELL written, before the descriptors written. >> >>> /* issue command to the controller */ >>> spin_lock_irqsave(hba->host->host_lock, flags); >>> ufshcd_send_command(hba, tag); >>> @@ -1627,6 +1631,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba >>> *hba, >>> >>> hba->dev_cmd.complete = &wait; >>> >>> + /* Make sure descriptors are ready before ringing the doorbell >>> */ >>> + wmb(); >>> spin_lock_irqsave(hba->host->host_lock, flags); >>> ufshcd_send_command(hba, tag); >>> spin_unlock_irqrestore(hba->host->host_lock, flags); >>> -- >>> 1.8.5.2 >>> >>> -- >>> QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a >>> member of Code Aurora Forum, hosted by The Linux Foundation >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in >> the body of a message to majord...@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/23] scsi_dh_alua: use unaligned access macros
Use 'get_unaligned_XX' and 'put_unaligned_XX' instead of open-coding it. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 23 --- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 9d8fc53..0636721 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -153,10 +154,7 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else rq->cmd[1] = MI_REPORT_TARGET_PGS; - rq->cmd[6] = (h->bufflen >> 24) & 0xff; - rq->cmd[7] = (h->bufflen >> 16) & 0xff; - rq->cmd[8] = (h->bufflen >> 8) & 0xff; - rq->cmd[9] = h->bufflen & 0xff; + put_unaligned_be32(h->bufflen, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); rq->sense = h->sense; @@ -239,8 +237,7 @@ static unsigned submit_stpg(struct alua_dh_data *h) /* Prepare the data buffer */ memset(h->buff, 0, stpg_len); h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; - h->buff[6] = (h->group_id >> 8) & 0xff; - h->buff[7] = h->group_id & 0xff; + put_unaligned_be16(h->group_id, &h->buff[6]); rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); if (!rq) @@ -249,10 +246,7 @@ static unsigned submit_stpg(struct alua_dh_data *h) /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_OUT; rq->cmd[1] = MO_SET_TARGET_PGS; - rq->cmd[6] = (stpg_len >> 24) & 0xff; - rq->cmd[7] = (stpg_len >> 16) & 0xff; - rq->cmd[8] = (stpg_len >> 8) & 0xff; - rq->cmd[9] = stpg_len & 0xff; + put_unaligned_be32(stpg_len, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); rq->sense = h->sense; @@ -341,11 +335,11 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) switch (d[1] & 0xf) { case 0x4: /* Relative target port */ - h->rel_port = (d[6] << 8) + d[7]; + h->rel_port = get_unaligned_be16(&d[6]); break; case 0x5: /* Target port group */ - h->group_id = (d[6] << 8) + d[7]; + h->group_id = get_unaligned_be16(&d[6]); break; default: break; @@ -540,8 +534,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ return SCSI_DH_IO; } - len = (h->buff[0] << 24) + (h->buff[1] << 16) + - (h->buff[2] << 8) + h->buff[3] + 4; + len = get_unaligned_be32(&h->buff[0]) + 4; if (len > h->bufflen) { /* Resubmit with the correct length */ @@ -576,7 +569,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ k < len; k += off, ucp += off) { - if (h->group_id == (ucp[2] << 8) + ucp[3]) { + if (h->group_id == get_unaligned_be16(&ucp[2])) { h->state = ucp[0] & 0x0f; h->pref = ucp[0] >> 7; valid_states = ucp[1]; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 00/23] asynchronous ALUA device handler
Hi all, here is an update to the ALUA device handler. The main features are: - Topology discovery: the device handler creates a separate port_group structure, which is used to update all paths to the same port group. With that we achieve a significant reduction of the number of RTPGs. - Asynchronous state update: The ALUA state is now updated from a workqueue item, so all concurrent RTPG calls are coaleasced. The ALUA state update is also triggered by sense codes indicating an ALUA state change. - Use the existing vpd page 0x83 to detect device IDs The patchset is relative to the V4 version of the scsi_dh update. The entire tree can be found at kernel/hare/scsi-devel branch alua.v4 on git.kernel.org As usual, reviews and comments are welcome. Changes to v1: - Split off rtpg workqueue into separate items - User per-port workqueues - Incorporate review from Bart - Incorporate review from hch Changes to v2: - Fixup patch descriptions - Split off 'Improve error handling' patch Changes to v3: - Implement generic 'scsi_vpd_lun_id()' function to parse vpd page 0x83 Hannes Reinecke (23): scsi_dh_alua: Disable ALUA handling for non-disk devices scsi_dh_alua: Use vpd_pg83 information scsi_dh_alua: improved logging scsi_dh_alua: use standard logging functions scsi_dh_alua: return standard SCSI return codes in submit_rtpg scsi_dh_alua: fixup description of stpg_endio() scsi: remove scsi_show_sense_hdr() scsi_dh_alua: use flag for RTPG extended header scsi_dh_alua: use unaligned access macros scsi_dh_alua: Pass buffer as function argument scsi_dh_alua: Make stpg synchronous scsi_dh_alua: switch to scsi_execute_req_flags() scsi_dh_alua: Use separate alua_port_group structure scsi_dh_alua: allocate RTPG buffer separately scsi_dh_alua: simplify sense code handling scsi: Add scsi_vpd_lun_id() scsi_dh_alua: use unique device id revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning" scsi_dh_alua: Use workqueue for RTPG scsi_dh_alua: Recheck state on unit attention scsi_dh_alua: update all port states scsi_dh_alua: Send TEST UNIT READY to poll for transitioning scsi_dh_alua: Update version to 2.0 drivers/scsi/device_handler/scsi_dh_alua.c | 1140 +--- drivers/scsi/scsi_lib.c| 121 +++ include/scsi/scsi_dbg.h|2 - include/scsi/scsi_device.h |1 + 4 files changed, 838 insertions(+), 426 deletions(-) -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 08/15] scsi: ufs: add retries to dme_peer get and set attribute
The dme_peer get/set attribute commands are prone to errors, therefore we add three retries for the UIC command sending. Error code returned from ufshcd_send_uic_cmd() is checked, and unless it was successful or the retries have finished, another command will be sent. Signed-off-by: Lee Susman Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 40 +--- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 217b5cf..8d5bdf0 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -69,6 +69,9 @@ /* Task management command timeout */ #define TM_CMD_TIMEOUT 100 /* msecs */ +/* maximum number of retries for a general UIC command */ +#define UFS_UIC_COMMAND_RETRIES 3 + /* maximum number of link-startup retries */ #define DME_LINKSTARTUP_RETRIES 3 @@ -2184,6 +2187,7 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, }; const char *set = action[!!peer]; int ret; + int retries = UFS_UIC_COMMAND_RETRIES; uic_cmd.command = peer ? UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; @@ -2191,10 +2195,18 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set); uic_cmd.argument3 = mib_val; - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", - set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); + do { + /* for peer attributes we retry upon failure */ + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", + set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); + } while (ret && peer && --retries); + + if (!retries) + dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n", + set, UIC_GET_ATTR_ID(attr_sel), mib_val, + retries); return ret; } @@ -2219,6 +2231,7 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, }; const char *get = action[!!peer]; int ret; + int retries = UFS_UIC_COMMAND_RETRIES; struct ufs_pa_layer_attr orig_pwr_info; struct ufs_pa_layer_attr temp_pwr_info; bool pwr_mode_change = false; @@ -2249,14 +2262,19 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; uic_cmd.argument1 = attr_sel; - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) { - dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n", - get, UIC_GET_ATTR_ID(attr_sel), ret); - goto out; - } + do { + /* for peer attributes we retry upon failure */ + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n", + get, UIC_GET_ATTR_ID(attr_sel), ret); + } while (ret && peer && --retries); + + if (!retries) + dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n", + get, UIC_GET_ATTR_ID(attr_sel), retries); - if (mib_val) + if (mib_val && !ret) *mib_val = uic_cmd.argument3; if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE) -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 15/15] scsi: ufs: add wrapper for retrying sending query attribute
Sometimes queries from the device might return a failure so it is recommended to retry sending the query, before giving up. This change adds a wrapper to retry sending a query attribute, in cases where we need to wait longer, before we continue, or before reporting a failure. Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 51 --- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 024cc86..1c37a7d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1827,6 +1827,43 @@ out: } /** + * ufshcd_query_attr_retry() - API function for sending query + * attribute with retries + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @selector: selector field + * @attr_val: the attribute value after the query request + * completes + * + * Returns 0 for success, non-zero in case of failure +*/ +static int ufshcd_query_attr_retry(struct ufs_hba *hba, + enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, + u32 *attr_val) +{ + int ret = 0; + u32 retries; + +for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { + ret = ufshcd_query_attr(hba, opcode, idn, index, + selector, attr_val); + if (ret) + dev_dbg(hba->dev, "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + + if (ret) + dev_err(hba->dev, + "%s: query attribute, idn %d, failed with error %d after %d retires\n", + __func__, idn, ret, QUERY_REQ_RETRIES); + return ret; +} + +/** * ufshcd_query_descriptor - API function for sending descriptor requests * hba: per-adapter instance * opcode: attribute opcode @@ -3407,7 +3444,7 @@ static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask) val = hba->ee_ctrl_mask & ~mask; val &= 0x; /* 2 bytes */ - err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); if (!err) hba->ee_ctrl_mask &= ~mask; @@ -3435,7 +3472,7 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) val = hba->ee_ctrl_mask | mask; val &= 0x; /* 2 bytes */ - err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); if (!err) hba->ee_ctrl_mask |= mask; @@ -3541,7 +3578,7 @@ static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) { - return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, + return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, status); } @@ -3604,7 +3641,7 @@ static int ufshcd_urgent_bkops(struct ufs_hba *hba) static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status) { - return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, + return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_EE_STATUS, 0, 0, status); } @@ -4360,9 +4397,9 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, hba->init_prefetch_data.icc_level); - ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, - &hba->init_prefetch_data.icc_level); + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, + &hba->init_prefetch_data.icc_level); if (ret) dev_err(hba->dev, -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 14/15] scsi: ufs: commit descriptors before setting the doorbell
Add a write memory barrier to make sure descriptors prepared are actually written to memory before ringing the doorbell. We have also added the write memory barrier after ringing the doorbell register so that controller sees the new request immediately. Signed-off-by: Gilad Broner Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 298511a..024cc86 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -833,6 +833,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + /* Make sure that doorbell is committed immediately */ + wmb(); } /** @@ -1418,6 +1420,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } + /* Make sure descriptors are ready before ringing the doorbell */ + wmb(); /* issue command to the controller */ spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_send_command(hba, tag); @@ -1627,6 +1631,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, hba->dev_cmd.complete = &wait; + /* Make sure descriptors are ready before ringing the doorbell */ + wmb(); spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_send_command(hba, tag); spin_unlock_irqrestore(hba->host->host_lock, flags); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 13/15] scsi: ufs: add missing memory barriers
Performing several writes to UFS host controller registers has no gurrantee of ordering, so we must make sure register writes to setup request list base address etc. are performed before the run/stop register is enabled. In addition, when setting up a task request, we must make sure the updating of descriptors takes places before ringing the doorbell, similarly to setting up a transfer request. Signed-off-by: Gilad Broner Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 21 +++-- 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index fc2a52d..298511a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -401,11 +401,9 @@ static inline int ufshcd_get_lists_status(u32 reg) * 1 UTRLRDY * 2 UTMRLRDY * 3 UCRDY -* 4 HEI -* 5 DEI -* 6-7 reserved +* 4-7 reserved */ - return (((reg) & (0xFF)) >> 1) ^ (0x07); + return ((reg & 0xFF) >> 1) ^ 0x07; } /** @@ -2726,7 +2724,7 @@ out: * To bring UFS host controller to operational state, * 1. Enable required interrupts * 2. Configure interrupt aggregation - * 3. Program UTRL and UTMRL base addres + * 3. Program UTRL and UTMRL base address * 4. Configure run-stop-registers * * Returns 0 on success, non-zero value on failure @@ -2756,8 +2754,13 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) REG_UTP_TASK_REQ_LIST_BASE_H); /* +* Make sure base address and interrupt setup are updated before +* enabling the run/stop registers below. +*/ + wmb(); + + /* * UCRDY, UTMRLDY and UTRLRDY bits must be 1 -* DEI, HEI bits must be 0 */ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS); if (!(ufshcd_get_lists_status(reg))) { @@ -3920,7 +3923,13 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, /* send command to the controller */ __set_bit(free_slot, &hba->outstanding_tasks); + + /* Make sure descriptors are ready before ringing the task doorbell */ + wmb(); + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL); + /* Make sure that doorbell is committed immediately */ + wmb(); spin_unlock_irqrestore(host->host_lock, flags); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 12/15] scsi: ufs: reduce the interrupts for power mode change requests
DME commands such as Hibern8 enter/exit and gear switch generate 2 completion interrupts, one for confirmation that command is received by local UniPro and 2nd one is the final confirmation after communication with remote UniPro. Currently both of these completions are registered as interrupt events which is not quite necessary and instead we can just wait for the interrupt of 2nd completion, this should reduce the number of interrupts and could reduce the unnecessary CPU wakeups to handle extra interrupts. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 41 +++-- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index f2d4301..fc2a52d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -986,13 +986,15 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result * @hba: per adapter instance * @uic_cmd: UIC command + * @completion: initialize the completion only if this is set to true * * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called * with mutex held and host_lock locked. * Returns 0 only if success. */ static int -__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, + bool completion) { if (!ufshcd_ready_for_uic_cmd(hba)) { dev_err(hba->dev, @@ -1000,7 +1002,8 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) return -EIO; } - init_completion(&uic_cmd->done); + if (completion) + init_completion(&uic_cmd->done); ufshcd_dispatch_uic_cmd(hba, uic_cmd); @@ -1025,7 +1028,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) ufshcd_add_delay_before_dme_cmd(hba); spin_lock_irqsave(hba->host->host_lock, flags); - ret = __ufshcd_send_uic_cmd(hba, uic_cmd); + ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true); spin_unlock_irqrestore(hba->host->host_lock, flags); if (!ret) ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); @@ -2346,6 +2349,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) unsigned long flags; u8 status; int ret; + bool reenable_intr = false; mutex_lock(&hba->uic_cmd_mutex); init_completion(&uic_async_done); @@ -2353,15 +2357,17 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) spin_lock_irqsave(hba->host->host_lock, flags); hba->uic_async_done = &uic_async_done; - ret = __ufshcd_send_uic_cmd(hba, cmd); - spin_unlock_irqrestore(hba->host->host_lock, flags); - if (ret) { - dev_err(hba->dev, - "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", - cmd->command, cmd->argument3, ret); - goto out; + if (ufshcd_readl(hba, REG_INTERRUPT_ENABLE) & UIC_COMMAND_COMPL) { + ufshcd_disable_intr(hba, UIC_COMMAND_COMPL); + /* +* Make sure UIC command completion interrupt is disabled before +* issuing UIC command. +*/ + wmb(); + reenable_intr = true; } - ret = ufshcd_wait_for_uic_cmd(hba, cmd); + ret = __ufshcd_send_uic_cmd(hba, cmd, false); + spin_unlock_irqrestore(hba->host->host_lock, flags); if (ret) { dev_err(hba->dev, "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", @@ -2387,7 +2393,10 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) } out: spin_lock_irqsave(hba->host->host_lock, flags); + hba->active_uic_cmd = NULL; hba->uic_async_done = NULL; + if (reenable_intr) + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); spin_unlock_irqrestore(hba->host->host_lock, flags); mutex_unlock(&hba->uic_cmd_mutex); @@ -3812,16 +3821,20 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) */ static irqreturn_t ufshcd_intr(int irq, void *__hba) { - u32 intr_status; + u32 intr_status, enabled_intr_status; irqreturn_t retval = IRQ_NONE; struct ufs_hba *hba = __hba; spin_lock(hba->host->host_lock); intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + enabled_intr_status = + intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE); - if (intr_status) { + if (intr_status) ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); - ufshcd_sl_intr(hba, intr_status); + + if (enabled_intr_status) { + ufshcd_sl_intr(
[PATCH v2 11/15] scsi: ufs: retry failed query flag requests
UFS flag query requests may fail sometimes due to timeouts etc. Add a wrapper function to retry up to 10 times in case of such failure, similar to retries being made for attribute queries. Signed-off-by: Gilad Broner Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 63 --- drivers/scsi/ufs/ufshcd.h | 4 +++ 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 1dbef7d..f2d4301 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1662,6 +1662,29 @@ static inline void ufshcd_init_query(struct ufs_hba *hba, (*request)->upiu_req.selector = selector; } +static int ufshcd_query_flag_retry(struct ufs_hba *hba, + enum query_opcode opcode, enum flag_idn idn, bool *flag_res) +{ + int ret; + int retries; + + for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) { + ret = ufshcd_query_flag(hba, opcode, idn, flag_res); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + + if (ret) + dev_err(hba->dev, + "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + /** * ufshcd_query_flag() - API function for sending flag query requests * hba: per-adapter instance @@ -1671,7 +1694,7 @@ static inline void ufshcd_init_query(struct ufs_hba *hba, * * Returns 0 for success, non-zero in case of failure */ -static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, +int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res) { struct ufs_query_req *request = NULL; @@ -2656,17 +2679,12 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, */ static int ufshcd_complete_dev_init(struct ufs_hba *hba) { - int i, retries, err = 0; + int i; + int err; bool flag_res = 1; - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - /* Set the fDeviceInit flag */ - err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG, - QUERY_FLAG_IDN_FDEVICEINIT, NULL); - if (!err || err == -ETIMEDOUT) - break; - dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); - } + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, + QUERY_FLAG_IDN_FDEVICEINIT, NULL); if (err) { dev_err(hba->dev, "%s setting fDeviceInit flag failed with error %d\n", @@ -2674,18 +2692,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba) goto out; } - /* poll for max. 100 iterations for fDeviceInit flag to clear */ - for (i = 0; i < 100 && !err && flag_res; i++) { - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - err = ufshcd_query_flag(hba, - UPIU_QUERY_OPCODE_READ_FLAG, - QUERY_FLAG_IDN_FDEVICEINIT, &flag_res); - if (!err || err == -ETIMEDOUT) - break; - dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, - err); - } - } + /* poll for max. 1000 iterations for fDeviceInit flag to clear */ + for (i = 0; i < 1000 && !err && flag_res; i++) + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, + QUERY_FLAG_IDN_FDEVICEINIT, &flag_res); + if (err) dev_err(hba->dev, "%s reading fDeviceInit flag failed with error %d\n", @@ -3432,7 +3443,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) if (hba->auto_bkops_enabled) goto out; - err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG, + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, QUERY_FLAG_IDN_BKOPS_EN, NULL); if (err) { dev_err(hba->dev, "%s: failed to enable bkops %d\n", @@ -3481,7 +3492,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) goto out; } - err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, QUERY_FLAG_IDN_BKOPS_EN, NULL); if (err) { dev_err(hba->dev, "%s: failed to disable bkops %d\n", @@ -4452,8 +4463,8 @@ static int ufshc
[PATCH v2 09/15] scsi: ufs: add retries for hibern8 enter
If hibern8 enter command fails then UFS link state may be unknown which may result into timeout of all the commands issued after failure. This change does 2 things (for pre-defined number of retry counts) after hibern8 enter failure: 1. Recovers the UFS link to active state 2. If link is recovered to active state, tries to put the UFS link in hibern8 enter again until retry count expires. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 26 -- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8d5bdf0..5800b08 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -75,6 +75,9 @@ /* maximum number of link-startup retries */ #define DME_LINKSTARTUP_RETRIES 3 +/* Maximum retries for Hibern8 enter */ +#define UIC_HIBERN8_ENTER_RETRIES 3 + /* maximum number of reset retries before giving up */ #define MAX_HOST_RESET_RETRIES 5 @@ -2389,13 +2392,32 @@ out: return ret; } -static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) +static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) { + int ret; struct uic_command uic_cmd = {0}; uic_cmd.command = UIC_CMD_DME_HIBER_ENTER; + ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + + if (ret) + dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", + __func__, ret); + + return ret; +} + +static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) +{ + int ret = 0, retries; - return ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) { + ret = __ufshcd_uic_hibern8_enter(hba); + if (!ret || ret == -ENOLINK) + goto out; + } +out: + return ret; } static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 10/15] scsi: ufs: fix error recovery after the hibern8 exit failure
Hibern8 exit can be called from 3 different context: - ufshcd_hibern8_exit_work - ufshcd_ungate_work - runtime/system resume If hibern8 exit fails for some reason then we try to bring the link to active state by link startup but this recovery mechanism results into deadlock or errors from first 2 context listed above. This change fixes the recovery by adding proper error handling mechanism. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 58 +++ 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5800b08..1dbef7d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -609,6 +609,11 @@ int ufshcd_hold(struct ufs_hba *hba, bool async) spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.active_reqs++; + if (ufshcd_eh_in_progress(hba)) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + return 0; + } + start: switch (hba->clk_gating.state) { case CLKS_ON: @@ -724,7 +729,8 @@ static void __ufshcd_release(struct ufs_hba *hba) if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || hba->lrb_in_use || hba->outstanding_tasks - || hba->active_uic_cmd || hba->uic_async_done) + || hba->active_uic_cmd || hba->uic_async_done + || ufshcd_eh_in_progress(hba)) return; hba->clk_gating.state = REQ_CLKS_OFF; @@ -1362,6 +1368,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); goto out_unlock; } + + /* if error handling is in progress, don't issue commands */ + if (ufshcd_eh_in_progress(hba)) { + set_host_byte(cmd, DID_ERROR); + cmd->scsi_done(cmd); + goto out_unlock; + } spin_unlock_irqrestore(hba->host->host_lock, flags); /* acquire the tag to make sure device cmds don't use it */ @@ -2392,6 +2405,31 @@ out: return ret; } +static int ufshcd_link_recovery(struct ufs_hba *hba) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(hba->host->host_lock, flags); + hba->ufshcd_state = UFSHCD_STATE_RESET; + ufshcd_set_eh_in_progress(hba); + spin_unlock_irqrestore(hba->host->host_lock, flags); + + ret = ufshcd_host_reset_and_restore(hba); + + spin_lock_irqsave(hba->host->host_lock, flags); + if (ret) + hba->ufshcd_state = UFSHCD_STATE_ERROR; + ufshcd_clear_eh_in_progress(hba); + spin_unlock_irqrestore(hba->host->host_lock, flags); + + if (ret) + dev_err(hba->dev, "%s: link recovery failed, err %d", + __func__, ret); + + return ret; +} + static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) { int ret; @@ -2400,10 +2438,18 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) uic_cmd.command = UIC_CMD_DME_HIBER_ENTER; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); - if (ret) + if (ret) { dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", __func__, ret); + /* +* If link recovery fails then return error so that caller +* don't retry the hibern8 enter again. +*/ + if (ufshcd_link_recovery(hba)) + ret = -ENOLINK; + } + return ret; } @@ -2428,8 +2474,9 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) uic_cmd.command = UIC_CMD_DME_HIBER_EXIT; ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); if (ret) { - ufshcd_set_link_off(hba); - ret = ufshcd_host_reset_and_restore(hba); + dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d", + __func__, ret); + ret = ufshcd_link_recovery(hba); } return ret; @@ -4381,7 +4428,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* UFS device is also active now */ ufshcd_set_ufs_dev_active(hba); ufshcd_force_reset_auto_bkops(hba); - hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; hba->wlun_dev_clr_ua = true; if (ufshcd_get_max_pwr_mode(hba)) { @@ -4395,6 +4441,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) __func__, ret); } + /* set the state as operational after switching to desired gear */ + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; /* * If we are in error handling context or in power management callbacks * context, no need to scan the host -- 1.8.5.2 -- QUALCOMM ISRAEL, on
[PATCH v2 06/15] scsi: ufs: avoid exception event handler racing with PM callbacks
If device raises the exception event in the response to the commands sent during the runtime/system PM callbacks, exception event handler might run in parallel with PM callbacks and may see unclocked register accesses. This change fixes this issue by not scheduling the exception event handler while PM callbacks are running. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 573a8cb..0e54183 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3145,7 +3145,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) scsi_status = result & MASK_SCSI_STATUS; result = ufshcd_scsi_cmd_status(lrbp, scsi_status); - if (ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) + /* +* Currently we are only supporting BKOPs exception +* events hence we can ignore BKOPs exception event +* during power management callbacks. BKOPs exception +* event is not expected to be raised in runtime suspend +* callback as it allows the urgent bkops. +* During system suspend, we are anyway forcefully +* disabling the bkops and if urgent bkops is needed +* it will be enabled on system resume. Long term +* solution could be to abort the system suspend if +* UFS device needs urgent BKOPs. +*/ + if (!hba->pm_op_in_progress && + ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) schedule_work(&hba->eeh_work); break; case UPIU_TRANSACTION_REJECT_UPIU: -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 07/15] scsi: ufs: set REQUEST_SENSE command size to 18 bytes
According to UFS device specification REQUEST_SENSE command can only report back up to 18 bytes of data. Signed-off-by: Gilad Broner Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 11 ++- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0e54183..217b5cf 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -42,6 +42,7 @@ #include "ufshcd.h" #include "unipro.h" +#define UFSHCD_REQ_SENSE_SIZE 18 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\ UTP_TASK_REQ_COMPL |\ @@ -836,7 +837,7 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len); memcpy(lrbp->sense_buffer, lrbp->ucd_rsp_ptr->sr.sense_data, - min_t(int, len, SCSI_SENSE_BUFFERSIZE)); + min_t(int, len, UFSHCD_REQ_SENSE_SIZE)); } } @@ -1381,7 +1382,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) WARN_ON(lrbp->cmd); lrbp->cmd = cmd; - lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE; + lrbp->sense_bufflen = UFSHCD_REQ_SENSE_SIZE; lrbp->sense_buffer = cmd->sense_buffer; lrbp->task_tag = tag; lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); @@ -4817,19 +4818,19 @@ ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp) 0, 0, 0, - SCSI_SENSE_BUFFERSIZE, + UFSHCD_REQ_SENSE_SIZE, 0}; char *buffer; int ret; - buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + buffer = kzalloc(UFSHCD_REQ_SENSE_SIZE, GFP_KERNEL); if (!buffer) { ret = -ENOMEM; goto out; } ret = scsi_execute_req_flags(sdp, cmd, DMA_FROM_DEVICE, buffer, - SCSI_SENSE_BUFFERSIZE, NULL, + UFSHCD_REQ_SENSE_SIZE, NULL, msecs_to_jiffies(1000), 3, NULL, REQ_PM); if (ret) pr_err("%s: failed with err %d\n", __func__, ret); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 19/23] scsi_dh_alua: Use workqueue for RTPG
The current ALUA device_handler has two drawbacks: - We're sending a 'SET TARGET PORT GROUP' command to every LUN, disregarding the fact that several LUNs might be in a port group and will be automatically switched whenever _any_ LUN within that port group receives the command. - Whenever a LUN is in 'transitioning' mode we cannot block I/O to that LUN, instead the controller has to abort the command. This leads to increased traffic across the wire and heavy load on the controller during switchover. With this patch the RTPG handling is moved to a per-portgroup workqueue. This reduces the number of 'REPORT TARGET PORT GROUP' and 'SET TARGET PORT GROUPS' sent to the controller as we're sending them now per port group, and not per device as previously. It also allows us to block I/O to any LUN / port group found to be in 'transitioning' ALUA mode, as the workqueue item will be requeued until the controller moves out of transitioning. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 414 - 1 file changed, 349 insertions(+), 65 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index b52db8b..85fd597 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -59,10 +61,15 @@ #define ALUA_RTPG_SIZE 128 #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 +#define ALUA_RTPG_DELAY_MSECS 5 /* device handler flags */ -#define ALUA_OPTIMIZE_STPG 1 -#define ALUA_RTPG_EXT_HDR_UNSUPP 2 +#define ALUA_OPTIMIZE_STPG 0x01 +#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02 +/* State machine flags */ +#define ALUA_PG_RUN_RTPG 0x10 +#define ALUA_PG_RUN_STPG 0x20 + static LIST_HEAD(port_group_list); static DEFINE_SPINLOCK(port_group_lock); @@ -78,13 +85,28 @@ struct alua_port_group { int pref; unsignedflags; /* used for optimizing STPG */ unsigned char transition_tmo; + unsigned long expiry; + unsigned long interval; + struct workqueue_struct *work_q; + struct delayed_work rtpg_work; + struct delayed_work stpg_work; + struct delayed_work qdata_work; + spinlock_t rtpg_lock; + struct list_headrtpg_list; + struct scsi_device *rtpg_sdev; }; struct alua_dh_data { struct alua_port_group *pg; + spinlock_t pg_lock; int rel_port; int tpgs; - struct scsi_device *sdev; + int init_error; + struct mutexinit_mutex; +}; + +struct alua_queue_data { + struct list_headentry; activate_complete callback_fn; void*callback_data; }; @@ -93,6 +115,10 @@ struct alua_dh_data { #define ALUA_POLICY_SWITCH_ALL 1 static char print_alua_state(int); +static void alua_rtpg_work(struct work_struct *work); +static void alua_stpg_work(struct work_struct *work); +static void alua_qdata_work(struct work_struct *work); +static void alua_check(struct scsi_device *sdev); static void release_port_group(struct kref *kref) { @@ -103,6 +129,9 @@ static void release_port_group(struct kref *kref) spin_lock(&port_group_lock); list_del(&pg->node); spin_unlock(&port_group_lock); + WARN_ON(pg->rtpg_sdev); + if (pg->work_q) + destroy_workqueue(pg->work_q); kfree(pg); } @@ -296,13 +325,17 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) if (strncmp(tmp_pg->device_id_str, device_id_str, device_id_size)) continue; - h->pg = tmp_pg; kref_get(&tmp_pg->kref); + spin_lock(&h->pg_lock); + rcu_assign_pointer(h->pg, tmp_pg); + spin_unlock(&h->pg_lock); break; } spin_unlock(&port_group_lock); - if (h->pg) + if (h->pg) { + synchronize_rcu(); return SCSI_DH_OK; + } pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); if (!pg) { @@ -322,6 +355,19 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) pg->tpgs = h->tpgs; pg->state = TPGS_STATE_OPTIMIZED; kref_init(&pg->kref); + INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work); + INIT_DELAYED_WORK(&pg->stpg_work, alua_stpg_work); + INIT_DELAYED_WORK(&pg->qdata_work, alua_qdata_work); + INIT_LIST_HEAD(&pg->rtpg_list); + INIT_LIST_HEAD(&pg->node
[PATCH v2 04/15] scsi: ufs: clear outstanding_request bit in case query timeout
When sending a query to the device returns with a timeout error, we clear the corresponding bit in the DOORBELL register but we don't clear the outstanding_request field as we should. This patch fixes this bug. Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 22 -- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8860a57..e0b8755 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -364,6 +364,16 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) } /** + * ufshcd_outstanding_req_clear - Clear a bit in outstanding request field + * @hba: per adapter instance + * @tag: position of the bit to be cleared + */ +static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag) +{ + __clear_bit(tag, &hba->outstanding_reqs); +} + +/** * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY * @reg: Register value of host controller status * @@ -1502,9 +1512,17 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, if (!time_left) { err = -ETIMEDOUT; + dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n", + __func__, lrbp->task_tag); if (!ufshcd_clear_cmd(hba, lrbp->task_tag)) - /* sucessfully cleared the command, retry if needed */ + /* successfully cleared the command, retry if needed */ err = -EAGAIN; + /* +* in case of an error, after clearing the doorbell, +* we also need to clear the outstanding_request +* field in hba +*/ + ufshcd_outstanding_req_clear(hba, lrbp->task_tag); } return err; @@ -3942,7 +3960,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) scsi_dma_unmap(cmd); spin_lock_irqsave(host->host_lock, flags); - __clear_bit(tag, &hba->outstanding_reqs); + ufshcd_outstanding_req_clear(hba, tag); hba->lrb[tag].cmd = NULL; spin_unlock_irqrestore(host->host_lock, flags); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 05/15] scsi: ufs: increase fDeviceInit query response timeout
fDeviceInit query response time for some devices is too long that default query request timeout of 100ms may not be enough. Experiments show that fDeviceInit response sometimes takes 500ms so to be on safer side this change sets the timeout to 600ms. Without this change, we might unnecessarily have to retry fDeviceInit query requests multiple times and each query request timeout prints one error message. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e0b8755..573a8cb 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -58,6 +58,12 @@ #define QUERY_REQ_RETRIES 10 /* Query request timeout */ #define QUERY_REQ_TIMEOUT 30 /* msec */ +/* + * Query request timeout for fDeviceInit flag + * fDeviceInit query response time for some devices is too large that default + * QUERY_REQ_TIMEOUT may not be enough for such devices. + */ +#define QUERY_FDEVICEINIT_REQ_TIMEOUT 600 /* msec */ /* Task management command timeout */ #define TM_CMD_TIMEOUT 100 /* msecs */ @@ -1651,6 +1657,7 @@ static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; int err, index = 0, selector = 0; + int timeout = QUERY_REQ_TIMEOUT; BUG_ON(!hba); @@ -1683,7 +1690,10 @@ static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, goto out_unlock; } - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); + if (idn == QUERY_FLAG_IDN_FDEVICEINIT) + timeout = QUERY_FDEVICEINIT_REQ_TIMEOUT; + + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout); if (err) { dev_err(hba->dev, -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 03/15] scsi: ufs: verify command tag validity
A race condition appear to exist between request completion when scsi_done() is called to end the request and set the tag back to -1 (at blk_queue_end_tag() scsi_end_request), and scsi layer error handling which aborts the command and reuses it to request sense data. Sending the request sense is done with tag which was set to -1 and so it is invalid. Assert command tag passed from scsi layer is valid. Signed-off-by: Gilad Broner Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 24 ++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2d3ebca..8860a57 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -190,6 +190,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode); static int ufshcd_change_power_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *pwr_mode); +static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag) +{ + return tag >= 0 && tag < hba->nutrs; +} static inline int ufshcd_enable_irq(struct ufs_hba *hba) { @@ -1310,6 +1314,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) hba = shost_priv(host); tag = cmd->request->tag; + if (!ufshcd_valid_tag(hba, tag)) { + dev_err(hba->dev, + "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p", + __func__, tag, cmd, cmd->request); + BUG(); + } spin_lock_irqsave(hba->host->host_lock, flags); switch (hba->ufshcd_state) { @@ -3862,13 +3872,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) host = cmd->device->host; hba = shost_priv(host); tag = cmd->request->tag; + if (!ufshcd_valid_tag(hba, tag)) { + dev_err(hba->dev, + "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p", + __func__, tag, cmd, cmd->request); + BUG(); + } ufshcd_hold(hba, false); + reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* If command is already aborted/completed, return SUCCESS */ - if (!(test_bit(tag, &hba->outstanding_reqs))) + if (!(test_bit(tag, &hba->outstanding_reqs))) { + dev_err(hba->dev, + "%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n", + __func__, tag, hba->outstanding_reqs, reg); goto out; + } - reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); if (!(reg & (1 << tag))) { dev_err(hba->dev, "%s: cmd was completed, but without a notifying intr, tag = %d", -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 15/23] scsi_dh_alua: simplify sense code handling
Most sense code is already handled in the generic code, so we shouldn't be adding special cases here. However, when doing so we need to check for unit attention whenever we're sending an internal command. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 50 +++--- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 4157fe2..dbe9ff2 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -91,7 +91,6 @@ struct alua_dh_data { #define ALUA_POLICY_SWITCH_ALL 1 static char print_alua_state(int); -static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); static void release_port_group(struct kref *kref) { @@ -323,28 +322,6 @@ static int alua_check_sense(struct scsi_device *sdev, * LUN Not Accessible - ALUA state transition */ return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b) - /* -* LUN Not Accessible -- Target port in standby state -*/ - return SUCCESS; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c) - /* -* LUN Not Accessible -- Target port in unavailable state -*/ - return SUCCESS; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12) - /* -* LUN Not Ready -- Offline -*/ - return SUCCESS; - if (sdev->allow_restart && - sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02) - /* -* if the device is not started, we need to wake -* the error handler to start the motor -*/ - return FAILED; break; case UNIT_ATTENTION: if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) @@ -359,7 +336,7 @@ static int alua_check_sense(struct scsi_device *sdev, return ADD_TO_MLQUEUE; if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01) /* -* Mode Parameters Changed +* Mode Parameter Changed */ return ADD_TO_MLQUEUE; if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) @@ -372,18 +349,6 @@ static int alua_check_sense(struct scsi_device *sdev, * Implicit ALUA state transition failed */ return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03) - /* -* Inquiry data has changed -*/ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e) - /* -* REPORTED_LUNS_DATA_HAS_CHANGED is reported -* when switching controllers on targets like -* Intel Multi-Flex. We can just retry. -*/ - return ADD_TO_MLQUEUE; break; } @@ -448,9 +413,16 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP; goto retry; } - - err = alua_check_sense(sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) { + /* +* Retry on ALUA state transition or if any +* UNIT ATTENTION occurred. +*/ + if (sense_hdr.sense_key == NOT_READY && + sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) + err = SCSI_DH_RETRY; + else if (sense_hdr.sense_key == UNIT_ATTENTION) + err = SCSI_DH_RETRY; + if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) { sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n", ALUA_DH_NAME); scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 22/23] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
Sending a 'REPORT TARGET PORT GROUP' command is a costly operation, as the array has to gather information about all ports. So instead of using RTPG to poll for a status update when a port is in transitioning we should be sending a TEST UNIT READY, and wait for the sense code to report success. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 33 ++ 1 file changed, 33 insertions(+) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 2fa985e..3c6b365 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -467,6 +467,30 @@ static int alua_check_sense(struct scsi_device *sdev, } /* + * alua_tur - Send a TEST UNIT READY + * @sdev: device to which the TEST UNIT READY command should be send + * + * Send a TEST UNIT READY to @sdev to figure out the device state + * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING, + * SCSI_DH_OK if no error occured, and SCSI_DH_IO otherwise. + */ +static int alua_tur(struct scsi_device *sdev) +{ + struct scsi_sense_hdr sense_hdr; + int retval; + + retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ, + ALUA_FAILOVER_RETRIES, &sense_hdr); + if (sense_hdr.sense_key == NOT_READY && + sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) + return SCSI_DH_RETRY; + else if (retval) + return SCSI_DH_IO; + else + return SCSI_DH_OK; +} + +/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * @@ -725,7 +749,16 @@ static void alua_rtpg_work(struct work_struct *work) return; } if (pg->flags & ALUA_PG_RUN_RTPG) { + int state = pg->state; spin_unlock_irqrestore(&pg->rtpg_lock, flags); + if (state == TPGS_STATE_TRANSITIONING) { + if (alua_tur(sdev) == SCSI_DH_RETRY) { + queue_delayed_work(pg->work_q, &pg->rtpg_work, + pg->interval * HZ); + return; + } + /* Send RTPG on failure or if TUR indicates SUCCESS */ + } err = alua_rtpg(sdev, pg); if (err == SCSI_DH_RETRY) { queue_delayed_work(pg->work_q, &pg->rtpg_work, -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 20/23] scsi_dh_alua: Recheck state on unit attention
When we receive a unit attention code of 'ALUA state changed' we should recheck the state, as it might be due to an implicit ALUA state transition. At the same time a workqueue item might already be queued, which should be started immediately to avoid any delays. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 48 +++--- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 85fd597..8717fd3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -118,7 +118,7 @@ static char print_alua_state(int); static void alua_rtpg_work(struct work_struct *work); static void alua_stpg_work(struct work_struct *work); static void alua_qdata_work(struct work_struct *work); -static void alua_check(struct scsi_device *sdev); +static void alua_check(struct scsi_device *sdev, bool force); static void release_port_group(struct kref *kref) { @@ -423,7 +423,7 @@ static char print_alua_state(int state) } static int alua_check_sense(struct scsi_device *sdev, - struct scsi_sense_hdr *sense_hdr) +struct scsi_sense_hdr *sense_hdr) { switch (sense_hdr->sense_key) { case NOT_READY: @@ -432,36 +432,34 @@ static int alua_check_sense(struct scsi_device *sdev, * LUN Not Accessible - ALUA state transition * Kickoff worker to update internal state. */ - alua_check(sdev); - return ADD_TO_MLQUEUE; + alua_check(sdev, false); + return NEEDS_RETRY; } break; case UNIT_ATTENTION: - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) - /* -* Power On, Reset, or Bus Device Reset, just retry. -*/ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04) - /* -* Device internal reset -*/ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01) + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) { /* -* Mode Parameter Changed +* Power On, Reset, or Bus Device Reset. +* Might have obscured a state transition, +* so schedule a recheck. */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) + } + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) { /* * ALUA state changed */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) + } + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) { /* * Implicit ALUA state transition failed */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; + } break; } @@ -811,7 +809,7 @@ static void alua_qdata_work(struct work_struct *work) static void alua_rtpg_queue(struct alua_port_group *pg, struct scsi_device *sdev, - struct alua_queue_data *qdata) + struct alua_queue_data *qdata, bool force) { int start_queue = 0; unsigned long flags; @@ -832,7 +830,9 @@ static void alua_rtpg_queue(struct alua_port_group *pg, pg->rtpg_sdev = sdev; scsi_device_get(sdev); start_queue = 1; - } + } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) + start_queue = 1; + spin_unlock_irqrestore(&pg->rtpg_lock, flags); if (start_queue) @@ -873,7 +873,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) mutex_unlock(&h->init_mutex); if (pg) { pg->expiry = 0; - alua_rtpg_queue(pg, sdev, NULL); + alua_rtpg_queue(pg, sdev, NULL, true); kref_put(&pg->kref, release_port_group); } return error; @@ -982,7 +982,7 @@ static int alua_activate(struct scsi_device *sdev, pg->flags |= ALUA_OPTIMIZE_STPG; spin_unlock_irqrestore(&pg->rtpg_lock, flags); } - alua_rtpg_queue(pg, s
[PATCH 18/23] revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning"
This reverts commit a8e5a2d593cbfccf530c3382c2c328d2edaa7b66 Obsoleted by the next patch. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 29 +++-- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index c2b2100b..b52db8b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -418,13 +418,12 @@ static int alua_check_sense(struct scsi_device *sdev, /* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. - * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unusable. */ -static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition) +static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; @@ -517,8 +516,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w else pg->transition_tmo = ALUA_FAILOVER_TIMEOUT; - if (wait_for_transition && - (orig_transition_tmo != pg->transition_tmo)) { + if (orig_transition_tmo != pg->transition_tmo) { sdev_printk(KERN_INFO, sdev, "%s: transition timeout set to %d seconds\n", ALUA_DH_NAME, pg->transition_tmo); @@ -556,19 +554,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w switch (pg->state) { case TPGS_STATE_TRANSITIONING: - if (wait_for_transition) { - if (time_before(jiffies, expiry)) { - /* State transition, retry */ - interval += 2000; - msleep(interval); - goto retry; - } - err = SCSI_DH_RETRY; - } else { - err = SCSI_DH_OK; + if (time_before(jiffies, expiry)) { + /* State transition, retry */ + interval += 2000; + msleep(interval); + goto retry; } - /* Transitioning time exceeded, set port to standby */ + err = SCSI_DH_RETRY; pg->state = TPGS_STATE_STANDBY; break; case TPGS_STATE_OFFLINE: @@ -665,7 +658,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) goto out; kref_get(&h->pg->kref); - err = alua_rtpg(sdev, h->pg, 0); + err = alua_rtpg(sdev, h->pg); kref_put(&h->pg->kref, release_port_group); out: return err; @@ -739,14 +732,14 @@ static int alua_activate(struct scsi_device *sdev, if (optimize_stpg) h->pg->flags |= ALUA_OPTIMIZE_STPG; - err = alua_rtpg(sdev, h->pg, 1); + err = alua_rtpg(sdev, h->pg); if (err != SCSI_DH_OK) { kref_put(&h->pg->kref, release_port_group); goto out; } err = alua_stpg(sdev, h->pg); if (err == SCSI_DH_RETRY) - err = alua_rtpg(sdev, h->pg, 1); + err = alua_rtpg(sdev, h->pg); kref_put(&h->pg->kref, release_port_group); out: if (fn) -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 14/23] scsi_dh_alua: allocate RTPG buffer separately
The RTPG buffer will only evaluated within alua_rtpg(), so we can allocate it locally there and avoid having to put it into the global structure. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 56 +++--- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index d1010dd..4157fe2 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -56,7 +56,7 @@ #define TPGS_MODE_IMPLICIT 0x1 #define TPGS_MODE_EXPLICIT 0x2 -#define ALUA_INQUIRY_SIZE 36 +#define ALUA_RTPG_SIZE 128 #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 @@ -75,9 +75,6 @@ struct alua_port_group { int state; int pref; unsignedflags; /* used for optimizing STPG */ - unsigned char inq[ALUA_INQUIRY_SIZE]; - unsigned char *buff; - int bufflen; unsigned char transition_tmo; }; @@ -96,21 +93,6 @@ struct alua_dh_data { static char print_alua_state(int); static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); -static int realloc_buffer(struct alua_port_group *pg, unsigned len) -{ - if (pg->buff && pg->buff != pg->inq) - kfree(pg->buff); - - pg->buff = kmalloc(len, GFP_NOIO); - if (!pg->buff) { - pg->buff = pg->inq; - pg->bufflen = ALUA_INQUIRY_SIZE; - return 1; - } - pg->bufflen = len; - return 0; -} - static void release_port_group(struct kref *kref) { struct alua_port_group *pg; @@ -120,8 +102,6 @@ static void release_port_group(struct kref *kref) spin_lock(&port_group_lock); list_del(&pg->node); spin_unlock(&port_group_lock); - if (pg->buff && pg->inq != pg->buff) - kfree(pg->buff); kfree(pg); } @@ -300,8 +280,6 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) return SCSI_DH_DEV_TEMP_BUSY; } pg->group_id = group_id; - pg->buff = pg->inq; - pg->bufflen = ALUA_INQUIRY_SIZE; pg->tpgs = h->tpgs; pg->state = TPGS_STATE_OPTIMIZED; kref_init(&pg->kref); @@ -424,8 +402,8 @@ static int alua_check_sense(struct scsi_device *sdev, static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition) { struct scsi_sense_hdr sense_hdr; - int len, k, off, valid_states = 0; - unsigned char *ucp; + int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; + unsigned char *ucp, *buff; unsigned err, retval; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; @@ -436,9 +414,12 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w else expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ); + buff = kzalloc(bufflen, GFP_KERNEL); + if (!buff) + return SCSI_DH_DEV_TEMP_BUSY; + retry: - retval = submit_rtpg(sdev, pg->buff, pg->bufflen, -&sense_hdr, pg->flags); + retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags); if (retval) { if (!scsi_sense_valid(&sense_hdr)) { @@ -449,6 +430,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w err = SCSI_DH_DEV_TEMP_BUSY; else err = SCSI_DH_IO; + kfree(buff); return err; } @@ -477,14 +459,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n", ALUA_DH_NAME); scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); + kfree(buff); return SCSI_DH_IO; } - len = get_unaligned_be32(&pg->buff[0]) + 4; + len = get_unaligned_be32(&buff[0]) + 4; - if (len > pg->bufflen) { + if (len > bufflen) { /* Resubmit with the correct length */ - if (realloc_buffer(pg, len)) { + kfree(buff); + bufflen = len; + buff = kmalloc(bufflen, GFP_KERNEL); + if (!buff) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ @@ -494,9 +480,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w }
[PATCH 17/23] scsi_dh_alua: use unique device id
Use scsi_vpd_lun_id() to assign a unique device identification to the alua port group structure. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 70 +++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index dbe9ff2..c2b2100b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock); struct alua_port_group { struct kref kref; struct list_headnode; + unsigned char device_id_str[256]; + int device_id_size; int group_id; int tpgs; int state; @@ -229,7 +231,9 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) { unsigned char *d; int group_id = -1; - struct alua_port_group *pg = NULL; + char device_id_str[256]; + int device_id_size; + struct alua_port_group *tmp_pg, *pg = NULL; if (!sdev->vpd_pg83) return SCSI_DH_DEV_UNSUPP; @@ -266,9 +270,39 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) h->tpgs = TPGS_MODE_NONE; return SCSI_DH_DEV_UNSUPP; } + device_id_size = scsi_vpd_lun_id(sdev, device_id_str, 256); + if (device_id_size <= 0) { + /* +* Internal error: TPGS supported by no +* device identifcation found. +* Disable ALUA support. +*/ + sdev_printk(KERN_INFO, sdev, + "%s: No device descriptors found\n", + ALUA_DH_NAME); + h->tpgs = TPGS_MODE_NONE; + return SCSI_DH_DEV_UNSUPP; + } sdev_printk(KERN_INFO, sdev, - "%s: port group %02x rel port %02x\n", - ALUA_DH_NAME, group_id, h->rel_port); + "%s: device %s port group %02x " + "rel port %02x\n", ALUA_DH_NAME, + device_id_str, group_id, h->rel_port); + spin_lock(&port_group_lock); + list_for_each_entry(tmp_pg, &port_group_list, node) { + if (tmp_pg->group_id != group_id) + continue; + if (tmp_pg->device_id_size != device_id_size) + continue; + if (strncmp(tmp_pg->device_id_str, device_id_str, + device_id_size)) + continue; + h->pg = tmp_pg; + kref_get(&tmp_pg->kref); + break; + } + spin_unlock(&port_group_lock); + if (h->pg) + return SCSI_DH_OK; pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); if (!pg) { @@ -278,13 +312,39 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } + if (device_id_size) + strncpy(pg->device_id_str, device_id_str, 256); + else + pg->device_id_str[0] = '\0'; + + pg->device_id_size = device_id_size; pg->group_id = group_id; pg->tpgs = h->tpgs; pg->state = TPGS_STATE_OPTIMIZED; kref_init(&pg->kref); spin_lock(&port_group_lock); - list_add(&pg->node, &port_group_list); - h->pg = pg; + /* +* Re-check list again to catch +* concurrent updates +*/ + list_for_each_entry(tmp_pg, &port_group_list, node) { + if (tmp_pg->group_id != pg->group_id) + continue; + if (tmp_pg->device_id_size != pg->device_id_size) + continue; + if (strncmp(tmp_pg->device_id_str, pg->device_id_str, + device_id_size)) + continue; + h->pg = tmp_pg; + kref_get(&tmp_pg->kref); + kfree(pg); + pg = NULL; + break; + } + if (pg) { + list_add(&pg->node, &port_group_list); + h->pg = pg; + } spin_unlock(&port_group_lock); return SCSI_DH_OK; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 13/23] scsi_dh_alua: Use separate alua_port_group structure
The port group needs to be a separate structure as several LUNs might belong to the same group. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 211 +++-- 1 file changed, 139 insertions(+), 72 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ef4363a..d1010dd 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -64,9 +64,13 @@ #define ALUA_OPTIMIZE_STPG 1 #define ALUA_RTPG_EXT_HDR_UNSUPP 2 -struct alua_dh_data { +static LIST_HEAD(port_group_list); +static DEFINE_SPINLOCK(port_group_lock); + +struct alua_port_group { + struct kref kref; + struct list_headnode; int group_id; - int rel_port; int tpgs; int state; int pref; @@ -75,6 +79,12 @@ struct alua_dh_data { unsigned char *buff; int bufflen; unsigned char transition_tmo; +}; + +struct alua_dh_data { + struct alua_port_group *pg; + int rel_port; + int tpgs; struct scsi_device *sdev; activate_complete callback_fn; void*callback_data; @@ -86,21 +96,35 @@ struct alua_dh_data { static char print_alua_state(int); static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); -static int realloc_buffer(struct alua_dh_data *h, unsigned len) +static int realloc_buffer(struct alua_port_group *pg, unsigned len) { - if (h->buff && h->buff != h->inq) - kfree(h->buff); + if (pg->buff && pg->buff != pg->inq) + kfree(pg->buff); - h->buff = kmalloc(len, GFP_NOIO); - if (!h->buff) { - h->buff = h->inq; - h->bufflen = ALUA_INQUIRY_SIZE; + pg->buff = kmalloc(len, GFP_NOIO); + if (!pg->buff) { + pg->buff = pg->inq; + pg->bufflen = ALUA_INQUIRY_SIZE; return 1; } - h->bufflen = len; + pg->bufflen = len; return 0; } +static void release_port_group(struct kref *kref) +{ + struct alua_port_group *pg; + + pg = container_of(kref, struct alua_port_group, kref); + printk(KERN_WARNING "alua: release port group %d\n", pg->group_id); + spin_lock(&port_group_lock); + list_del(&pg->node); + spin_unlock(&port_group_lock); + if (pg->buff && pg->inq != pg->buff) + kfree(pg->buff); + kfree(pg); +} + /* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to @@ -225,6 +249,8 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h) static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) { unsigned char *d; + int group_id = -1; + struct alua_port_group *pg = NULL; if (!sdev->vpd_pg83) return SCSI_DH_DEV_UNSUPP; @@ -241,7 +267,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) break; case 0x5: /* Target port group */ - h->group_id = get_unaligned_be16(&d[6]); + group_id = get_unaligned_be16(&d[6]); break; default: break; @@ -249,7 +275,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) d += d[3] + 4; } - if (h->group_id == -1) { + if (group_id == -1) { /* * Internal error; TPGS supported but required * VPD identification descriptors not present. @@ -258,15 +284,33 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) sdev_printk(KERN_INFO, sdev, "%s: No target port descriptors found\n", ALUA_DH_NAME); - h->state = TPGS_STATE_OPTIMIZED; h->tpgs = TPGS_MODE_NONE; return SCSI_DH_DEV_UNSUPP; } sdev_printk(KERN_INFO, sdev, "%s: port group %02x rel port %02x\n", - ALUA_DH_NAME, h->group_id, h->rel_port); + ALUA_DH_NAME, group_id, h->rel_port); - return 0; + pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); + if (!pg) { + sdev_printk(KERN_WARNING, sdev, + "%s: kzalloc port group failed\n", + ALUA_DH_NAME); + /* Temporary failure, bypass */ + return SCSI_DH_DEV_TEMP_BUSY; + } + pg->group_id = group_id; + pg->b
[PATCH 16/23] scsi: Add scsi_vpd_lun_id()
Add a function scsi_vpd_lun_id() to return a unique device identifcation based on the designation descriptors of VPD page 0x83. As devices might implement several descriptors the order of preference is: - NAA IEE Registered Extended - EUI-64 based 16-byte - EUI-64 based 12-byte - NAA IEEE Registered - NAA IEEE Extended A SCSI name string descriptor is preferred to all of them if the identification is longer than 16 bytes. The returned unique device identification will be formatted as a SCSI Name string to avoid clashes between different designator types. Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_lib.c| 121 + include/scsi/scsi_device.h | 1 + 2 files changed, 122 insertions(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 2a864b8..48d6ff6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3145,3 +3145,124 @@ void sdev_enable_disk_events(struct scsi_device *sdev) atomic_dec(&sdev->disk_events_disable_depth); } EXPORT_SYMBOL(sdev_enable_disk_events); + +/* + * scsi_vpd_lun_id - return a unique device identification + * @sdev: SCSI device + * @id: buffer for the identification + * @id_len: length of the buffer + * + * Copies a unique device identification into @id based + * on the information in the VPD page 0x83 of the device. + * The string will be formatted as a SCSI name string. + * + * Returns the length of the identification or error on failure. + */ +int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) +{ + u8 cur_id_type = 0xff; + u8 cur_id_size = 0; + unsigned char *d, *cur_id_str; + int id_size = -EAGAIN; + + /* +* Look for the correct descriptor. +* Order of preference for lun descriptor: +* - SCSI name string +* - NAA IEEE Registered Extended +* - EUI-64 based 16-byte +* - EUI-64 based 12-byte +* - NAA IEEE Registered +* - NAA IEEE Extended +* as longer descriptors reduce the likelyhood +* of identification clashes. +*/ + + /* The id string must be at least 20 bytes + terminating NULL byte */ + if (id_len < 21) + return -EINVAL; + + memset(id, 0, id_len); + d = sdev->vpd_pg83 + 4; + while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) { + /* Skip designators not referring to the LUN */ + if ((d[1] & 0x30) != 0x00) + goto next_desig; + + switch (d[1] & 0xf) { + case 0x2: + /* EUI-64 */ + if (cur_id_size > d[3]) + break; + /* Prefer NAA IEEE Registered Extended */ + if (cur_id_type == 0x3 && + cur_id_size == d[3]) + break; + cur_id_size = d[3]; + cur_id_str = d + 4; + cur_id_type = d[1] & 0xf; + switch (cur_id_size) { + case 8: + id_size = snprintf(id, id_len, + "eui.%8phN", + cur_id_str); + break; + case 12: + id_size = snprintf(id, id_len, + "eui.%12phN", + cur_id_str); + break; + case 16: + id_size = snprintf(id, id_len, + "eui.%16phN", + cur_id_str); + break; + default: + cur_id_size = 0; + break; + } + break; + case 0x3: + /* NAA */ + if (cur_id_size > d[3]) + break; + cur_id_size = d[3]; + cur_id_str = d + 4; + cur_id_type = d[1] & 0xf; + switch (cur_id_size) { + case 8: + id_size = snprintf(id, id_len, + "naa.%8phN", + cur_id_str); + break; + case 16: + id_size = snprintf(id, id_len, + "naa.%16phN", + cur_id_str); + break; + default: + c
[PATCH 21/23] scsi_dh_alua: update all port states
When we read in the target port group state we should be updating all affected port groups, otherwise we risk running out of sync. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 8717fd3..2fa985e 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -477,11 +477,13 @@ static int alua_check_sense(struct scsi_device *sdev, static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) { struct scsi_sense_hdr sense_hdr; + struct alua_port_group *tmp_pg; int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; unsigned char *ucp, *buff; unsigned err, retval; unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; + unsigned long flags; if (!pg->expiry) { if (!pg->transition_tmo) @@ -584,17 +586,28 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) else tpg_desc_tbl_off = 4; + spin_lock_irqsave(&port_group_lock, flags); for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off; k < len; k += off, ucp += off) { - if (pg->group_id == get_unaligned_be16(&ucp[2])) { - pg->state = ucp[0] & 0x0f; - pg->pref = ucp[0] >> 7; - valid_states = ucp[1]; + list_for_each_entry(tmp_pg, &port_group_list, node) { + u16 group_id = get_unaligned_be16(&ucp[2]); + if (tmp_pg->group_id != group_id) + continue; + if (tmp_pg->device_id_size != pg->device_id_size) + continue; + if (strncmp(tmp_pg->device_id_str, pg->device_id_str, + tmp_pg->device_id_size)) + continue; + tmp_pg->state = ucp[0] & 0x0f; + tmp_pg->pref = ucp[0] >> 7; + if (tmp_pg == pg) + valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); } + spin_unlock_irqrestore(&port_group_lock, flags); sdev_printk(KERN_INFO, sdev, "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n", -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/23] scsi_dh_alua: use flag for RTPG extended header
We should be using a flag when RTPG extended header is not supported, that saves us sending RTPG twice for older arrays. Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 25c2045..9d8fc53 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -59,8 +59,9 @@ #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 -/* flags passed from user level */ +/* device handler flags */ #define ALUA_OPTIMIZE_STPG 1 +#define ALUA_RTPG_EXT_HDR_UNSUPP 2 struct alua_dh_data { int group_id; @@ -135,8 +136,7 @@ static struct request *get_alua_req(struct scsi_device *sdev, * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ -static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, - bool rtpg_ext_hdr_req) +static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct request *rq; int err = 0; @@ -149,7 +149,7 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; - if (rtpg_ext_hdr_req) + if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP)) rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else rq->cmd[1] = MI_REPORT_TARGET_PGS; @@ -487,7 +487,6 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ int len, k, off, valid_states = 0; unsigned char *ucp; unsigned err, retval; - bool rtpg_ext_hdr_req = 1; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; @@ -498,7 +497,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: - retval = submit_rtpg(sdev, h, rtpg_ext_hdr_req); + retval = submit_rtpg(sdev, h); if (retval) { if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, @@ -521,10 +520,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ * The retry without rtpg_ext_hdr_req set * handles this. */ - if (rtpg_ext_hdr_req == 1 && + if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) && sense_hdr.sense_key == ILLEGAL_REQUEST && sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) { - rtpg_ext_hdr_req = 0; + h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP; goto retry; } -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/23] scsi: remove scsi_show_sense_hdr()
Last caller is gone, so remove it. Reviewed-by: Bart Van Assche Reviewed-by: Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- include/scsi/scsi_dbg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index f8170e9..56710e0 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -12,8 +12,6 @@ extern size_t __scsi_format_command(char *, size_t, const unsigned char *, size_t); extern void scsi_show_extd_sense(const struct scsi_device *, const char *, unsigned char, unsigned char); -extern void scsi_show_sense_hdr(const struct scsi_device *, const char *, - const struct scsi_sense_hdr *); extern void scsi_print_sense_hdr(const struct scsi_device *, const char *, const struct scsi_sense_hdr *); extern void scsi_print_sense(const struct scsi_cmnd *); -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 23/23] scsi_dh_alua: Update version to 2.0
Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 3c6b365..5b15936 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -31,7 +31,7 @@ #include #define ALUA_DH_NAME "alua" -#define ALUA_DH_VER "1.3" +#define ALUA_DH_VER "2.0" #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED0x1 -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/23] scsi_dh_alua: Pass buffer as function argument
Pass in the buffer as a function argument for submit_rtpg(). Reviewed-by: Bart Van Assche Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 0636721..9e2b3af 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -137,12 +137,13 @@ static struct request *get_alua_req(struct scsi_device *sdev, * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ -static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) +static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff, + int bufflen, unsigned char *sense, int flags) { struct request *rq; int err = 0; - rq = get_alua_req(sdev, h->buff, h->bufflen, READ); + rq = get_alua_req(sdev, buff, bufflen, READ); if (!rq) { err = DRIVER_BUSY << 24; goto done; @@ -150,22 +151,21 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; - if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP)) + if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP)) rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else rq->cmd[1] = MI_REPORT_TARGET_PGS; - put_unaligned_be32(h->bufflen, &rq->cmd[6]); + put_unaligned_be32(bufflen, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); - rq->sense = h->sense; + rq->sense = sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; + rq->sense_len = 0; blk_execute_rq(rq->q, NULL, rq, 1); - if (rq->errors) { + if (rq->errors) err = rq->errors; - h->senselen = rq->sense_len; - } + blk_put_request(rq); done: return err; @@ -491,7 +491,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: - retval = submit_rtpg(sdev, h); + retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags); if (retval) { if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/23] scsi_dh_alua: Make stpg synchronous
We should be issuing STPG synchronously as we need to evaluate the return code on failure. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 179 + 1 file changed, 83 insertions(+), 96 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 9e2b3af..fd0385e 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -172,76 +172,28 @@ done: } /* - * stpg_endio - Evaluate SET TARGET GROUP STATES - * @sdev: the device to be evaluated - * @state: the new target group state - * - * Evaluate a SET TARGET GROUP STATES command response. - */ -static void stpg_endio(struct request *req, int error) -{ - struct alua_dh_data *h = req->end_io_data; - struct scsi_sense_hdr sense_hdr; - unsigned err = SCSI_DH_OK; - - if (host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { - err = SCSI_DH_IO; - goto done; - } - - if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, -&sense_hdr)) { - err = alua_check_sense(h->sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE) { - err = SCSI_DH_RETRY; - goto done; - } - sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n", - ALUA_DH_NAME); - scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr); - err = SCSI_DH_IO; - } else if (error) - err = SCSI_DH_IO; - - if (err == SCSI_DH_OK) { - h->state = TPGS_STATE_OPTIMIZED; - sdev_printk(KERN_INFO, h->sdev, - "%s: port group %02x switched to state %c\n", - ALUA_DH_NAME, h->group_id, - print_alua_state(h->state)); - } -done: - req->end_io_data = NULL; - __blk_put_request(req->q, req); - if (h->callback_fn) { - h->callback_fn(h->callback_data, err); - h->callback_fn = h->callback_data = NULL; - } - return; -} - -/* * submit_stpg - Issue a SET TARGET GROUP STATES command * * Currently we're only setting the current target port group state * to 'active/optimized' and let the array firmware figure out * the states of the remaining groups. */ -static unsigned submit_stpg(struct alua_dh_data *h) +static unsigned submit_stpg(struct scsi_device *sdev, int group_id, + unsigned char *sense) { struct request *rq; + unsigned char stpg_data[8]; int stpg_len = 8; - struct scsi_device *sdev = h->sdev; + int err = 0; /* Prepare the data buffer */ - memset(h->buff, 0, stpg_len); - h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; - put_unaligned_be16(h->group_id, &h->buff[6]); + memset(stpg_data, 0, stpg_len); + stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f; + put_unaligned_be16(group_id, &stpg_data[6]); - rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); + rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE); if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; + return DRIVER_BUSY << 24; /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_OUT; @@ -249,13 +201,17 @@ static unsigned submit_stpg(struct alua_dh_data *h) put_unaligned_be32(stpg_len, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); - rq->sense = h->sense; + rq->sense = sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; - rq->end_io_data = h; + rq->sense_len = 0; + + blk_execute_rq(rq->q, NULL, rq, 1); + if (rq->errors) + err = rq->errors; + + blk_put_request(rq); - blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio); - return SCSI_DH_OK; + return err; } /* @@ -619,6 +575,68 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ } /* + * alua_stpg - Issue a SET TARGET GROUP STATES command + * + * Issue a SET TARGET GROUP STATES command and evaluate the + * response. Returns SCSI_DH_RETRY per default to trigger + * a re-evaluation of the target group state. + */ +static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h) +{ + int retval; + struct scsi_sense_hdr sense_hdr; + + if (!(h->tpgs & TPGS_MODE_EXPLICIT)) { + /* Only implicit ALUA supported, retry */ + return SCSI_DH_RETRY; + } + switch (h->state) { + case TPGS_STATE_OPTIMIZED: + return SCSI_DH_OK; + case TPGS_STATE_NONOPTIMIZED: + if ((h->flags & ALUA_OPTIMIZE_STPG) && + !h->pref && + (h
[PATCH 04/23] scsi_dh_alua: use standard logging functions
Use standard logging functions instead of hand-crafted ones. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 34 +- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index a20c8bf..7b43ee3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -194,22 +195,16 @@ static void stpg_endio(struct request *req, int error) goto done; } - if (req->sense_len > 0) { - err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, - &sense_hdr); - if (!err) { - err = SCSI_DH_IO; - goto done; - } + if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, +&sense_hdr)) { err = alua_check_sense(h->sdev, &sense_hdr); if (err == ADD_TO_MLQUEUE) { err = SCSI_DH_RETRY; goto done; } - sdev_printk(KERN_INFO, h->sdev, - "%s: stpg sense code: %02x/%02x/%02x\n", - ALUA_DH_NAME, sense_hdr.sense_key, - sense_hdr.asc, sense_hdr.ascq); + sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n", + ALUA_DH_NAME); + scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr); err = SCSI_DH_IO; } else if (error) err = SCSI_DH_IO; @@ -530,16 +525,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ } err = alua_check_sense(sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) + if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) { + sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n", + ALUA_DH_NAME); + scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); goto retry; - sdev_printk(KERN_INFO, sdev, - "%s: rtpg sense code %02x/%02x/%02x\n", - ALUA_DH_NAME, sense_hdr.sense_key, - sense_hdr.asc, sense_hdr.ascq); - err = SCSI_DH_IO; + } + sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n", + ALUA_DH_NAME); + scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); + return SCSI_DH_IO; } - if (err != SCSI_DH_OK) - return err; len = (h->buff[0] << 24) + (h->buff[1] << 16) + (h->buff[2] << 8) + h->buff[3] + 4; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/23] scsi_dh_alua: return standard SCSI return codes in submit_rtpg
Fixup submit_rtpg() to always return a standard SCSI return code. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 7b43ee3..c41d662 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -139,11 +139,13 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, bool rtpg_ext_hdr_req) { struct request *rq; - int err = SCSI_DH_RES_TEMP_UNAVAIL; + int err = 0; rq = get_alua_req(sdev, h->buff, h->bufflen, READ); - if (!rq) + if (!rq) { + err = DRIVER_BUSY << 24; goto done; + } /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; @@ -161,13 +163,10 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = h->senselen = 0; - err = blk_execute_rq(rq->q, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: rtpg failed with %x\n", - ALUA_DH_NAME, rq->errors); + blk_execute_rq(rq->q, NULL, rq, 1); + if (rq->errors) { + err = rq->errors; h->senselen = rq->sense_len; - err = SCSI_DH_IO; } blk_put_request(rq); done: @@ -489,7 +488,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0; unsigned char *ucp; - unsigned err; + unsigned err, retval; bool rtpg_ext_hdr_req = 1; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; @@ -501,13 +500,20 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: - err = submit_rtpg(sdev, h, rtpg_ext_hdr_req); - - if (err == SCSI_DH_IO && h->senselen > 0) { - err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, - &sense_hdr); - if (!err) - return SCSI_DH_IO; + retval = submit_rtpg(sdev, h, rtpg_ext_hdr_req); + + if (retval) { + if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, + &sense_hdr)) { + sdev_printk(KERN_INFO, sdev, + "%s: rtpg failed, result %d\n", + ALUA_DH_NAME, retval); + if (driver_byte(retval) == DRIVER_BUSY) + err = SCSI_DH_DEV_TEMP_BUSY; + else + err = SCSI_DH_IO; + return err; + } /* * submit_rtpg() has failed on existing arrays -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 00/15] Big fixes, retries, handle a race condition
Important: This serie of 15 small patches should be pushed after the series of 8 patches "Fix error message and present UFS variant probe" V2: a few minor changes V1: This serie of 15 small patches should be pushed after the series of 8 patches I have uploaded to the upstream a week ago: "Fix error message and present UFS variant probe" Yaniv Gardi (15): scsi: ufs: clear UTRD, UPIU req and rsp before new transfers scsi: ufs: clear fields UTRD, UPIU req and rsp before new transfers scsi: ufs: verify command tag validity scsi: ufs: clear outstanding_request bit in case query timeout scsi: ufs: increase fDeviceInit query response timeout scsi: ufs: avoid exception event handler racing with PM callbacks scsi: ufs: set REQUEST_SENSE command size to 18 bytes scsi: ufs: add retries to dme_peer get and set attribute scsi: ufs: add retries for hibern8 enter scsi: ufs: fix error recovery after the hibern8 exit failure scsi: ufs: retry failed query flag requests scsi: ufs: reduce the interrupts for power mode change requests scsi: ufs: add missing memory barriers scsi: ufs: commit descriptors before setting the doorbell scsi: ufs: add wrapper for retrying sending query attribute drivers/scsi/ufs/ufshcd.c | 413 -- drivers/scsi/ufs/ufshcd.h | 4 + 2 files changed, 332 insertions(+), 85 deletions(-) -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/23] scsi_dh_alua: Disable ALUA handling for non-disk devices
Non-disk devices might support ALUA, but the firmware implementation is untested and frequently broken. As we're don't actually need it disable ALUA support for non-disk device for now. Signed-off-by: Hannes Reinecke Reviewed-by: Bart Van Assche --- drivers/scsi/device_handler/scsi_dh_alua.c | 12 1 file changed, 12 insertions(+) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index cc2773b..7d01ef0 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -320,6 +320,18 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h) { int err = SCSI_DH_OK; + /* +* ALUA support for non-disk devices is fraught with +* difficulties, so disable it for now. +*/ + if (sdev->type != TYPE_DISK) { + h->tpgs = TPGS_MODE_NONE; + sdev_printk(KERN_INFO, sdev, + "%s: disable for non-disk devices\n", + ALUA_DH_NAME); + return SCSI_DH_DEV_UNSUPP; + } + h->tpgs = scsi_device_tpgs(sdev); switch (h->tpgs) { case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT: -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/23] scsi_dh_alua: switch to scsi_execute_req_flags()
All commands are issued synchronously, so no need to open-code scsi_execute_req_flags() anymore. And we can get rid of the static sense code structure element. Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 124 - 1 file changed, 34 insertions(+), 90 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index fd0385e..ef4363a 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -75,8 +75,6 @@ struct alua_dh_data { unsigned char *buff; int bufflen; unsigned char transition_tmo; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int senselen; struct scsi_device *sdev; activate_complete callback_fn; void*callback_data; @@ -103,72 +101,30 @@ static int realloc_buffer(struct alua_dh_data *h, unsigned len) return 0; } -static struct request *get_alua_req(struct scsi_device *sdev, - void *buffer, unsigned buflen, int rw) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - - rq = blk_get_request(q, rw, GFP_NOIO); - - if (IS_ERR(rq)) { - sdev_printk(KERN_INFO, sdev, - "%s: blk_get_request failed\n", __func__); - return NULL; - } - blk_rq_set_block_pc(rq); - - if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { - blk_put_request(rq); - sdev_printk(KERN_INFO, sdev, - "%s: blk_rq_map_kern failed\n", __func__); - return NULL; - } - - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | -REQ_FAILFAST_DRIVER; - rq->retries = ALUA_FAILOVER_RETRIES; - rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ; - - return rq; -} - /* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ -static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff, - int bufflen, unsigned char *sense, int flags) +static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff, + int bufflen, struct scsi_sense_hdr *sshdr, int flags) { - struct request *rq; - int err = 0; - - rq = get_alua_req(sdev, buff, bufflen, READ); - if (!rq) { - err = DRIVER_BUSY << 24; - goto done; - } + u8 cdb[16]; + int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; /* Prepare the command. */ - rq->cmd[0] = MAINTENANCE_IN; + memset(cdb, 0x0, 16); + cdb[0] = MAINTENANCE_IN; if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP)) - rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; + cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else - rq->cmd[1] = MI_REPORT_TARGET_PGS; - put_unaligned_be32(bufflen, &rq->cmd[6]); - rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); - - rq->sense = sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; + cdb[1] = MI_REPORT_TARGET_PGS; + put_unaligned_be32(bufflen, &cdb[6]); - blk_execute_rq(rq->q, NULL, rq, 1); - if (rq->errors) - err = rq->errors; - - blk_put_request(rq); -done: - return err; + return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE, + buff, bufflen, sshdr, + ALUA_FAILOVER_TIMEOUT * HZ, + ALUA_FAILOVER_RETRIES, NULL, req_flags); } /* @@ -178,40 +134,30 @@ done: * to 'active/optimized' and let the array firmware figure out * the states of the remaining groups. */ -static unsigned submit_stpg(struct scsi_device *sdev, int group_id, - unsigned char *sense) +static int submit_stpg(struct scsi_device *sdev, int group_id, + struct scsi_sense_hdr *sshdr) { - struct request *rq; + u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)]; unsigned char stpg_data[8]; int stpg_len = 8; - int err = 0; + int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; /* Prepare the data buffer */ memset(stpg_data, 0, stpg_len); stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f; put_unaligned_be16(group_id, &stpg_data[6]); - rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE); - if (!rq) - return DRIVER_BUSY << 24; - /* Prepare the command. */ - rq->cmd[0] = MAINTENANCE_OUT; - rq->cmd[1] = MO_SE
[PATCH v2 02/15] scsi: ufs: clear fields UTRD, UPIU req and rsp before new transfers
Some of the data structures (like response UPIU) and/or its elements (unused fields) should be cleared before sending out the respective command to UFS device. This change clears the UPIU response data structure for query commands and NOP command before sending out the command. We also initialize the PRDT table length to zero which should take care of commands which doesn't have any data associated with it. We are also clearing the unused fields in request UPIU for NOP command. Signed-off-by: Subhash Jadavani Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3428f72..2d3ebca 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1129,6 +1129,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, cpu_to_le32(OCS_INVALID_COMMAND_STATUS); /* dword_3 is reserved, hence it is set to 0 */ req_desc->header.dword_3 = 0; + + req_desc->prd_table_length = 0; } /** @@ -1198,6 +1200,7 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) memcpy(descp, query->descriptor, len); + memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); } static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) @@ -1210,6 +1213,11 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag); + /* clear rest of the fields of basic header */ + ucd_req_ptr->header.dword_1 = 0; + ucd_req_ptr->header.dword_2 = 0; + + memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); } /** -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 01/15] scsi: ufs: clear UTRD, UPIU req and rsp before new transfers
Clear the UFS data structures before sending new request. The SCSI command is sent to the device within the UFS UPIU request. As part of the transfer UPIU preparation, the SCSI command is copied to the UPIU structure according to the SCSI command size. As different SCSI commands differ in size from each other, we need to clear the whole SCSI command field to prevent sending uninitialized data to the device. The UPIU response doesn't always include the sense data and can differ in size. Hence, the UPIU response should also be cleared before the transfer. Signed-off-by: Subhash Jadavani Signed-off-by: Maya Erez Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufshcd.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 131c720..3428f72 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3,7 +3,7 @@ * * This code is based on drivers/scsi/ufs/ufshcd.c * Copyright (C) 2011-2013 Samsung India Software Operations - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * Authors: * Santosh Yaraganavi @@ -1035,6 +1035,7 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp) cpu_to_le32(lower_32_bits(sg->dma_address)); prd_table[i].upper_addr = cpu_to_le32(upper_32_bits(sg->dma_address)); + prd_table[i].reserved = 0; } } else { lrbp->utr_descriptor_ptr->prd_table_length = 0; @@ -1117,7 +1118,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, /* Transfer request descriptor header fields */ req_desc->header.dword_0 = cpu_to_le32(dword_0); - + /* dword_1 is reserved, hence it is set to 0 */ + req_desc->header.dword_1 = 0; /* * assigning invalid value for command status. Controller * updates OCS on command completion, with the command @@ -1125,6 +1127,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, */ req_desc->header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + /* dword_3 is reserved, hence it is set to 0 */ + req_desc->header.dword_3 = 0; } /** @@ -1137,6 +1141,7 @@ static void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags) { struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr; + unsigned short cdb_len; /* command descriptor fields */ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( @@ -1151,8 +1156,12 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags) ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(lrbp->cmd->sdb.length); - memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, - (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE))); + cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE); + memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, cdb_len); + if (cdb_len < MAX_CDB_SIZE) + memset(ucd_req_ptr->sc.cdb + cdb_len, 0, + (MAX_CDB_SIZE - cdb_len)); + memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); } /** -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/23] scsi_dh_alua: improved logging
Issue different logging messages if ALUA is not supported or the TPGS setting is invalid. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index f15b977..a20c8bf 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -310,12 +310,18 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h) sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n", ALUA_DH_NAME); break; - default: - h->tpgs = TPGS_MODE_NONE; + case TPGS_MODE_NONE: sdev_printk(KERN_INFO, sdev, "%s: not supported\n", ALUA_DH_NAME); err = SCSI_DH_DEV_UNSUPP; break; + default: + sdev_printk(KERN_INFO, sdev, + "%s: unsupported TPGS setting %d\n", + ALUA_DH_NAME, h->tpgs); + h->tpgs = TPGS_MODE_NONE; + err = SCSI_DH_DEV_UNSUPP; + break; } return err; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/23] scsi_dh_alua: Use vpd_pg83 information
The SCSI device now has the VPD page 0x83 information attached, so there is no need to query it again. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 83 +- 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 7d01ef0..f15b977 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -131,43 +131,6 @@ static struct request *get_alua_req(struct scsi_device *sdev, } /* - * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command - * @sdev: sdev the command should be sent to - */ -static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) -{ - struct request *rq; - int err = SCSI_DH_RES_TEMP_UNAVAIL; - - rq = get_alua_req(sdev, h->buff, h->bufflen, READ); - if (!rq) - goto done; - - /* Prepare the command. */ - rq->cmd[0] = INQUIRY; - rq->cmd[1] = 1; - rq->cmd[2] = 0x83; - rq->cmd[4] = h->bufflen; - rq->cmd_len = COMMAND_SIZE(INQUIRY); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; - - err = blk_execute_rq(rq->q, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: evpd inquiry failed with %x\n", - ALUA_DH_NAME, rq->errors); - h->senselen = rq->sense_len; - err = SCSI_DH_IO; - } - blk_put_request(rq); -done: - return err; -} - -/* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ @@ -359,43 +322,24 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h) } /* - * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83 + * alua_check_vpd - Evaluate INQUIRY vpd page 0x83 * @sdev: device to be checked * * Extract the relative target port and the target port group * descriptor from the list of identificators. */ -static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) +static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) { - int len; - unsigned err; unsigned char *d; - retry: - err = submit_vpd_inquiry(sdev, h); - - if (err != SCSI_DH_OK) - return err; - - /* Check if vpd page exceeds initial buffer */ - len = (h->buff[2] << 8) + h->buff[3] + 4; - if (len > h->bufflen) { - /* Resubmit with the correct length */ - if (realloc_buffer(h, len)) { - sdev_printk(KERN_WARNING, sdev, - "%s: kmalloc buffer failed\n", - ALUA_DH_NAME); - /* Temporary failure, bypass */ - return SCSI_DH_DEV_TEMP_BUSY; - } - goto retry; - } + if (!sdev->vpd_pg83) + return SCSI_DH_DEV_UNSUPP; /* -* Now look for the correct descriptor. +* Look for the correct descriptor. */ - d = h->buff + 4; - while (d < h->buff + len) { + d = sdev->vpd_pg83 + 4; + while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) { switch (d[1] & 0xf) { case 0x4: /* Relative target port */ @@ -422,14 +366,13 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) ALUA_DH_NAME); h->state = TPGS_STATE_OPTIMIZED; h->tpgs = TPGS_MODE_NONE; - err = SCSI_DH_DEV_UNSUPP; - } else { - sdev_printk(KERN_INFO, sdev, - "%s: port group %02x rel port %02x\n", - ALUA_DH_NAME, h->group_id, h->rel_port); + return SCSI_DH_DEV_UNSUPP; } + sdev_printk(KERN_INFO, sdev, + "%s: port group %02x rel port %02x\n", + ALUA_DH_NAME, h->group_id, h->rel_port); - return err; + return 0; } static char print_alua_state(int state) @@ -692,7 +635,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) if (err != SCSI_DH_OK) goto out; - err = alua_vpd_inquiry(sdev, h); + err = alua_check_vpd(sdev, h); if (err != SCSI_DH_OK) goto out; -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/23] scsi_dh_alua: fixup description of stpg_endio()
Fixup copy-and-paste error in the description of stpg_endio(). Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index c41d662..25c2045 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -174,13 +174,11 @@ done: } /* - * alua_stpg - Evaluate SET TARGET GROUP STATES + * stpg_endio - Evaluate SET TARGET GROUP STATES * @sdev: the device to be evaluated * @state: the new target group state * - * Send a SET TARGET GROUP STATES command to the device. - * We only have to test here if we should resubmit the command; - * any other error is assumed as a failure. + * Evaluate a SET TARGET GROUP STATES command response. */ static void stpg_endio(struct request *req, int error) { -- 1.8.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi_debug: fix failure to probe with scsi_level=1 or 2 due to NULL devip
On 15-08-25 03:47 PM, Ewan D. Milne wrote: From: "Ewan D. Milne" commit cbf67842c3d9 ("scsi_debug: support scsi-mq, queues and locks") added a test for devip == NULL in schedule_resp which returned SCSI_MLQUEUE_HOST_BUSY. Unfortunately, if scsi_level 1 or 2 is specified, devip will be NULL for the INQUIRY command for the next LUN above the configured value and it will be retried indefinitely with an error message. Fix this by returning the command in the same context if no devip exists. Signed-off-by: Ewan D. Milne Acked-by: Douglas Gilbert -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] mpt3sas: Reference counting fixes from in-flight mpt2sas
On Thu, 2015-08-27 at 10:37 +0530, Sreekanth Reddy wrote: > HI Nicholas & Calvin, > > Thanks for the patchset. Sure We will review and we do some unit > testing on this patch series. Currently my bandwidth is occupied with > some internal activity, so by end of next week I will acknowledge this > series if all the thing are fine with this patch series. Calvin responded to your review feedback and that series has been outstanding for a while, so I'm not going to drop it from the misc tree. However, I will reorder to make it ready for the second push. You have until Friday week to find a problem with it. James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] mpt3sas: Reference counting fixes from in-flight mpt2sas
Ok James, by 9/4/2015 we will provide our feedback over this patch series. Thanks, Sreekanth On Thu, Aug 27, 2015 at 8:10 PM, James Bottomley wrote: > On Thu, 2015-08-27 at 10:37 +0530, Sreekanth Reddy wrote: >> HI Nicholas & Calvin, >> >> Thanks for the patchset. Sure We will review and we do some unit >> testing on this patch series. Currently my bandwidth is occupied with >> some internal activity, so by end of next week I will acknowledge this >> series if all the thing are fine with this patch series. > > Calvin responded to your review feedback and that series has been > outstanding for a while, so I'm not going to drop it from the misc tree. > However, I will reorder to make it ready for the second push. You have > until Friday week to find a problem with it. > > James > > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V7 1/9] [SCSI] aacraid: Fix for logical device name and UID not exposed to the OS
On Thu, 2015-08-27 at 06:50 -0400, Mahesh Rajashekhara wrote: > Description: > Driver sends the right size of the response buffer. > > Changes from V2: > None > > Reviewed By: Tomas Henzl , Murthy Bhat > , Karthikeya Sunkesula > > Signed-off-by: Mahesh Rajashekhara You've had hundreds of upstream confirmation emails over the years. They've all had one line per tag with no spaces. Next time can we please use the right format so I don't have to keep editing your commit messages. That is: Subject: One line summary Detailed Description of the change (without a Description: prefix) Reviewed-by: Tomas Henzl Reviewed-by: Murthy Bhat Reviewed-by: Karthikeya Sunkesula Signed-off-by: Mahesh Rajashekhara --- Version notices and other context relevant only to the upstream process come here after the three dashes so it doesn't appear in the patch detailed description James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v1 14/15] scsi: ufs: commit descriptors before setting the doorbell
On Thu, Aug 27, 2015 at 7:28 AM, wrote: >>> On Aug 21, 2015 3:10 PM, "Yaniv Gardi" wrote: Add a write memory barrier to make sure descriptors prepared are actually written to memory before ringing the doorbell. We have also added the write memory barrier after ringing the doorbell register so that controller sees the new request immediately. [...] + /* Make sure descriptors are ready before ringing the doorbell */ + wmb(); >>> >>> The writel for the doorbell will do a barrier first. (I didn't check >>> what exactly ufshcd_writel does, but that is why I don't like these >>> private access wrappers.) > > the barrier here is important and a must. > before it we prepare descriptors. > after it we write to DOOR-BELL. > (and after the DOOR-BELL we have another one.) > if we remove it, we might get the DOOR-BELL written, before the > descriptors written. If you dig into what writel does, you will see that what the code here ends up being is: descriptor setup wmb() __iomwb() -> wmb on arm64 doorbell register write So explain why you need 2 barriers. Barriers in a driver are a red flag. Usually they are not needed, but sometimes they are. You have to be able to explain why if they are. Pretty much every descriptor based DMA device works as you describe and has the ordering problem. Because of that, the core code takes care of this. Rob -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v1 14/15] scsi: ufs: commit descriptors before setting the doorbell
On Thu, Aug 27, 2015 at 7:11 AM, wrote: >> On Tue, Aug 25, 2015 at 7:36 AM, wrote: On Aug 21, 2015 3:10 PM, "Yaniv Gardi" wrote: > > Add a write memory barrier to make sure descriptors prepared are > actually > written to memory before ringing the doorbell. We have also added the > write memory barrier after ringing the doorbell register so that > controller sees the new request immediately. > > Signed-off-by: Yaniv Gardi > > --- > drivers/scsi/ufs/ufshcd.c | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c > index fef0660..876148b 100644 > --- a/drivers/scsi/ufs/ufshcd.c > +++ b/drivers/scsi/ufs/ufshcd.c > @@ -833,6 +833,8 @@ void ufshcd_send_command(struct ufs_hba *hba, > unsigned int task_tag) > ufshcd_clk_scaling_start_busy(hba); > __set_bit(task_tag, &hba->outstanding_reqs); > ufshcd_writel(hba, 1 << task_tag, > REG_UTP_TRANSFER_REQ_DOOR_BELL); > + /* Make sure that doorbell is committed immediately */ > + wmb(); Is this really necessary? Is there a measurable difference? >>> >>> I'm not sure if there is a measurable difference, but as the Door-Bell >>> register is the one that actually responsible for the HW execution of >>> the >>> requests, anyhow, it's recommended to its value will be written >>> instantly to the memory. >> >> A barrier doesn't guarantee speed, only ordering. Unless you can >> measure the difference, you should not have it. > > Rob, > let me have an example: > context#1 updates outstanding_reqs variable and write(DOOR_BELL) > context#2 upon interrupt of a request completion the following happens: > report completion on each one of the bits in: > outstanding_reqs ^ read(DOOR_BELL); > > 0. let's assume the DOOR_BELL = 0x1 (which means 1 active request in slot 0) > 1. context#1: update the DOOR_BELL to be 0x3; (2 active requests: in slot > 0 and 1) > 2. the new value 0x3 is still not written to the DR so DORR_BELL is still > 0x1, but outstanding_reqs is already updated = 0x3 > 3. the request in slot 0 just completed, and interrupt happens, so > DORR_BELL is now 0 (request in slot 0 completed) > 4. context#2: outstanding_reqs ^ read(DOOR_BELL) = 0x3 ^ 0x0 = 0x3 => > wrong conclusion since the request in slot 1 never completed, and actually > never started. Barriers alone will never solve this problem. They may narrow the window possibly, but the problem is still there. What you have to have is a spinlock around all accesses to both outstanding_reqs and doorbell register. And guess what, spinlocks have appropriate barriers to ensure visibility of what they protect. Or perhaps the h/w provides another way to signal what slots have completed. Using the same register for doorbell and completion status is not ideal. Rob -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 6/8] scsi: ufs: make the UFS variant a platform device
On Sun, Aug 23, 2015 at 8:09 AM, Yaniv Gardi wrote: > This change turns the UFS variant (SCSI_UFS_QCOM) into a UFS > a platform device. > In order to do so a few additional changes are required: > 1. The ufshcd-pltfrm is no longer serves as a platform device. >Now it only serves as a group of platform APIs such as PM APIs >(runtime suspend/resume, system suspend/resume etc), parsers of >clocks, regulators and pm_levels from DT. > 2. What used to be the old platform "probe" is now "only" >a pltfrm_init() routine, that does exactly the same, but only >being called by the new probe function of the UFS variant. > > Signed-off-by: Yaniv Gardi > > --- > .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 2 +- > drivers/scsi/ufs/ufs-qcom.c| 78 +- > drivers/scsi/ufs/ufshcd-pltfrm.c | 92 > ++ > drivers/scsi/ufs/ufshcd-pltfrm.h | 41 ++ > drivers/scsi/ufs/ufshcd.c | 10 +++ > drivers/scsi/ufs/ufshcd.h | 1 + > 6 files changed, 152 insertions(+), 72 deletions(-) > create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h > > diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt > b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt > index 5357919..b39e765 100644 > --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt > +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt > @@ -4,7 +4,7 @@ UFSHC nodes are defined to describe on-chip UFS host > controllers. > Each UFS controller instance should have its own node. > > Required properties: > -- compatible: compatible list, contains "jedec,ufs-1.1" > +- compatible: compatible list, contains "jedec,ufs-1.1" or > "qcom,ufshc" Replying again as I inadvertently dropped everyone. This should also have a more specific compatible string with the SOC name/number in it. It may be "the same in all SOCs", but there is always the possibility for bugs/limitations to be found that are specific to an SOC even if all RTL versions are identical (e.g. different max clock speeds). It is about making the dtb future proof, not about what exactly you need today. You can keep qcom,ufshc for driver matching if you want. > - interrupts: > - reg : What about phy properties? No Unipro PHY block that requires setup? Rob -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] scsi: fix scsi_error_handler vs. scsi_host_dev_release race
From: Michal Hocko b9d5c6b7ef57 ("[SCSI] cleanup setting task state in scsi_error_handler()") has introduced a race between scsi_error_handler and scsi_host_dev_release resulting in the hang when the device goes away because scsi_error_handler might miss a wake up: CPU0CPU1 scsi_error_handler scsi_host_dev_release kthread_stop() kthread_should_stop() test_bit(KTHREAD_SHOULD_STOP) set_bit(KTHREAD_SHOULD_STOP) wake_up_process() wait_for_completion() set_current_state(TASK_INTERRUPTIBLE) schedule() The most straightforward solution seems to be to invert the ordering of the set_current_state and kthread_should_stop. The issue has been noticed during reboot test on a 3.0 based kernel but the current code seems to be affected in the same way. Cc: stable # 3.6+ Reported-and-Debugged-by: Mike Mayer Signed-off-by: Michal Hocko --- drivers/scsi/scsi_error.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6457a8a0db9c..2c0a817d5dbe 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -2169,8 +2169,11 @@ int scsi_error_handler(void *data) * We never actually get interrupted because kthread_run * disables signal delivery for the created thread. */ - while (!kthread_should_stop()) { + while (true) { set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) + break; + if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || shost->host_failed != atomic_read(&shost->host_busy)) { SCSI_LOG_ERROR_RECOVERY(1, -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: fix scsi_error_handler vs. scsi_host_dev_release race
On Thu, Aug 27, 2015 at 11:16 AM, wrote: > From: Michal Hocko > > b9d5c6b7ef57 ("[SCSI] cleanup setting task state in > scsi_error_handler()") has introduced a race between scsi_error_handler > and scsi_host_dev_release resulting in the hang when the device goes > away because scsi_error_handler might miss a wake up: > > CPU0CPU1 > scsi_error_handler scsi_host_dev_release > kthread_stop() > kthread_should_stop() > test_bit(KTHREAD_SHOULD_STOP) > set_bit(KTHREAD_SHOULD_STOP) > wake_up_process() > wait_for_completion() > > set_current_state(TASK_INTERRUPTIBLE) > schedule() > > The most straightforward solution seems to be to invert the ordering of > the set_current_state and kthread_should_stop. > > The issue has been noticed during reboot test on a 3.0 based kernel but > the current code seems to be affected in the same way. > > Cc: stable # 3.6+ > Reported-and-Debugged-by: Mike Mayer > Signed-off-by: Michal Hocko Acked-by: Dan Williams -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] mpt3sas: Reference counting fixes from in-flight mpt2sas
On Thu, 2015-08-27 at 07:40 -0700, James Bottomley wrote: > On Thu, 2015-08-27 at 10:37 +0530, Sreekanth Reddy wrote: > > HI Nicholas & Calvin, > > > > Thanks for the patchset. Sure We will review and we do some unit > > testing on this patch series. Currently my bandwidth is occupied with > > some internal activity, so by end of next week I will acknowledge this > > series if all the thing are fine with this patch series. > > Calvin responded to your review feedback and that series has been > outstanding for a while, so I'm not going to drop it from the misc tree. > However, I will reorder to make it ready for the second push. You have > until Friday week to find a problem with it. > James, as mentioned this series is functionally identical to Calvin's mpt2sas series. Please consider merging it to scsi.git/for-next, so both series are together and in-sync. --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] ipr: Enable SIS pipe commands for SIS-32 devices.
Gabriel Krisman Bertazi linux.vnet.ibm.com> writes: > > Remove unnecessary check that disabled SIS pipe commands for SIS-32 > devices. This change was sufficient to enable raw mode and send SIS > pipe commands for a 57B3 device. > Reviewed-by: Wen Xiong Thanks, Wendy -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [scsi 5/7 RESEND] scsi_debug: schedule_resp fix input variable check
On Wed, 2015-08-26 at 16:38 -0700, James Bottomley wrote: > On Tue, 2015-08-25 at 21:03 +, Winkler, Tomas wrote: > > > > > > + /* this should never happen */ > > > > + if (WARN_ON(!cmnd)) > > > > + return SCSI_MLQUEUE_HOST_BUSY; > > > > > > > > - if (NULL == cmnd || NULL == devip) { > > > > - pr_warn("called with NULL cmnd or devip pointer\n"); > > > > + if (NULL == devip) { > > > > + pr_warn("called devip == NULL\n"); > > > > /* no particularly good error to report back */ > > > > return SCSI_MLQUEUE_HOST_BUSY; > > > > } > > > > > > Please refer to the patch I just posted, we can't return _HOST_BUSY here > > > if devip == NULL. I posted a fix against the current "misc" branch as > > > I don't see this patch applied, let me know if I need to update it. > > > > > > I'm just not sure why the patches are not merged or even rejected. > > Because ideally I want a Maintainer ack. That's Doug Gilbert. > > > I'm submitting patches to the Linux kernel for more than 10 years to > > various trees and I can agree that these are not some urgent fixes, > > but this is the first time my effort is ignored for such long time by > > the maintainer. > > Well, OK, I trust martin, I'll override the lack of Maintainer ack if > you fix as Ewan suggests. > Just to clarify, I didn't have a problem with Tomas' patch per se, it's just that my patch won't apply on top of his. I'll submit a v2 if you want, so you can apply Tomas' patch first. The problem I'm fixing has been in there for a while. Let me know if you want me to do that. -Ewan > James > > > > Thanks > > Tomas > > > > NrybXǧv^){.n+{"{ayʇڙ,jfhzwj:+vwjmzZ+ݢj"! > > > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[scsi:misc 95/113] drivers/scsi/mpt3sas/mpt3sas_base.c:1820:1: sparse: symbol 'mpt3sas_base_unmap_resources' was not declared. Should it be static?
tree: git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git misc head: b9e8a16466e62d46c0b8551fb807173d6a9c529f commit: 580d4e3153f0d7a9a9235b675b0b7b13e2185a8b [95/113] mpt3sas: Remove redundancy code while freeing the controller resources. reproduce: # apt-get install sparse git checkout 580d4e3153f0d7a9a9235b675b0b7b13e2185a8b make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) drivers/scsi/mpt3sas/mpt3sas_base.c:1031:52: sparse: incorrect type in argument 2 (different address spaces) drivers/scsi/mpt3sas/mpt3sas_base.c:1031:52:expected void volatile [noderef] *addr drivers/scsi/mpt3sas/mpt3sas_base.c:1031:52:got unsigned long long [usertype] * >> drivers/scsi/mpt3sas/mpt3sas_base.c:1820:1: sparse: symbol >> 'mpt3sas_base_unmap_resources' was not declared. Should it be static? drivers/scsi/mpt3sas/mpt3sas_base.c:1958:32: sparse: cast removes address space of expression drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16: sparse: incorrect type in argument 1 (different base types) drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:expected unsigned long [unsigned] val drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:got restricted __le64 [usertype] drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16: sparse: incorrect type in argument 1 (different base types) drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:expected unsigned long [unsigned] val drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:got restricted __le64 [usertype] drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16: sparse: incorrect type in argument 1 (different base types) drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:expected unsigned long [unsigned] val drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:got restricted __le64 [usertype] drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16: sparse: incorrect type in argument 1 (different base types) drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:expected unsigned long [unsigned] val drivers/scsi/mpt3sas/mpt3sas_base.c:2204:16:got restricted __le64 [usertype] drivers/scsi/mpt3sas/mpt3sas_base.c:3446:24: sparse: incorrect type in argument 1 (different base types) drivers/scsi/mpt3sas/mpt3sas_base.c:3446:24:expected unsigned int [unsigned] val drivers/scsi/mpt3sas/mpt3sas_base.c:3446:24:got restricted __le32 [usertype] drivers/scsi/mpt3sas/mpt3sas_base.c:3467:20: sparse: cast to restricted __le16 drivers/scsi/mpt3sas/mpt3sas_base.c:3476:20: sparse: cast to restricted __le16 drivers/scsi/mpt3sas/mpt3sas_base.c:3490:36: sparse: cast to restricted __le16 drivers/scsi/mpt3sas/mpt3sas_base.c:4673:55: sparse: incorrect type in argument 2 (different address spaces) drivers/scsi/mpt3sas/mpt3sas_base.c:4673:55:expected void volatile [noderef] *addr drivers/scsi/mpt3sas/mpt3sas_base.c:4673:55:got unsigned long long [usertype] * Please review and possibly fold the followup patch. --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH scsi] mpt3sas: mpt3sas_base_unmap_resources can be static
Signed-off-by: Fengguang Wu --- mpt3sas_base.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 7e8ede2..6ee54dd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1816,7 +1816,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) * mpt3sas_base_unmap_resources - free controller resources * @ioc: per adapter object */ -void +static void mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) { struct pci_dev *pdev = ioc->pdev; -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[scsi:misc 97/113] drivers/scsi/mpt3sas/mpt3sas_scsih.c:5013:27: sparse: restricted __le16 degrades to integer
tree: git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git misc head: b9e8a16466e62d46c0b8551fb807173d6a9c529f commit: e6d45e3e7e6582fa206ef84631639ce70d50e5c5 [97/113] mpt3sas: Provides the physical location of sas drives reproduce: # apt-get install sparse git checkout e6d45e3e7e6582fa206ef84631639ce70d50e5c5 make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:5013:27: sparse: restricted __le16 >> degrades to integer >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:5015:25: sparse: cast to restricted >> __le16 drivers/scsi/mpt3sas/mpt3sas_scsih.c:3524:61: sparse: incorrect type in assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:3524:61:expected restricted __le32 [usertype] PrimaryReferenceTag drivers/scsi/mpt3sas/mpt3sas_scsih.c:3524:61:got restricted __be32 [usertype] drivers/scsi/mpt3sas/mpt3sas_scsih.c:4888:35: sparse: restricted __le16 degrades to integer drivers/scsi/mpt3sas/mpt3sas_scsih.c:4891:33: sparse: cast to restricted __le16 >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:6529:63: sparse: restricted __le64 >> degrades to integer drivers/scsi/mpt3sas/mpt3sas_scsih.c:6530:60: sparse: restricted __le16 degrades to integer drivers/scsi/mpt3sas/mpt3sas_scsih.c:6554:43: sparse: restricted __le16 degrades to integer drivers/scsi/mpt3sas/mpt3sas_scsih.c:6557:36: sparse: cast to restricted __le16 drivers/scsi/mpt3sas/mpt3sas_scsih.c:6565:65: sparse: restricted __le16 degrades to integer >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:6569:44: sparse: incorrect type in >> assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:6569:44:expected unsigned short [unsigned] [usertype] handle drivers/scsi/mpt3sas/mpt3sas_scsih.c:6569:44:got restricted __le16 [usertype] DevHandle drivers/scsi/mpt3sas/mpt3sas_scsih.c:6571:62: sparse: incorrect type in assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:6571:62:expected unsigned short [unsigned] [usertype] handle drivers/scsi/mpt3sas/mpt3sas_scsih.c:6571:62:got restricted __le16 [usertype] DevHandle >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:6611:51: sparse: incorrect type in >> assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:6611:51:expected restricted __le16 [addressable] [usertype] DevHandle drivers/scsi/mpt3sas/mpt3sas_scsih.c:6611:51:got unsigned short [unsigned] [usertype] >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:6616:43: sparse: incorrect type in >> assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:6616:43:expected restricted __le64 [addressable] [usertype] SASAddress drivers/scsi/mpt3sas/mpt3sas_scsih.c:6616:43:got unsigned long long [unsigned] [usertype] >> drivers/scsi/mpt3sas/mpt3sas_scsih.c:6618:37: sparse: incorrect type in >> assignment (different base types) drivers/scsi/mpt3sas/mpt3sas_scsih.c:6618:37:expected restricted __le16 [addressable] [usertype] Slot drivers/scsi/mpt3sas/mpt3sas_scsih.c:6618:37:got unsigned short [unsigned] [usertype] vim +5013 drivers/scsi/mpt3sas/mpt3sas_scsih.c 5007 sas_device->device_info = device_info; 5008 sas_device->sas_address = sas_address; 5009 sas_device->phy = sas_device_pg0.PhyNum; 5010 sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) & 5011 MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; 5012 > 5013 if (sas_device_pg0.Flags & > MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { 5014 sas_device->enclosure_level = > 5015 le16_to_cpu(sas_device_pg0.EnclosureLevel); 5016 memcpy(&sas_device->connector_name[0], 5017 &sas_device_pg0.ConnectorName[0], 4); 5018 } else { --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH scsi] mpt3sas: mpt3sas_base_unmap_resources can be static
Hi, Please consider this patch as Ack-by: Sreekanth Reddy Thanks, Sreekanth On Fri, Aug 28, 2015 at 6:50 AM, kbuild test robot wrote: > > Signed-off-by: Fengguang Wu > --- > mpt3sas_base.c |2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c > b/drivers/scsi/mpt3sas/mpt3sas_base.c > index 7e8ede2..6ee54dd 100644 > --- a/drivers/scsi/mpt3sas/mpt3sas_base.c > +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c > @@ -1816,7 +1816,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) > * mpt3sas_base_unmap_resources - free controller resources > * @ioc: per adapter object > */ > -void > +static void > mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) > { > struct pci_dev *pdev = ioc->pdev; -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: fix scsi_error_handler vs. scsi_host_dev_release race
On 08/27/2015 08:16 PM, mho...@kernel.org wrote: > From: Michal Hocko > > b9d5c6b7ef57 ("[SCSI] cleanup setting task state in > scsi_error_handler()") has introduced a race between scsi_error_handler > and scsi_host_dev_release resulting in the hang when the device goes > away because scsi_error_handler might miss a wake up: > > CPU0 CPU1 > scsi_error_handlerscsi_host_dev_release > kthread_stop() > kthread_should_stop() > test_bit(KTHREAD_SHOULD_STOP) > set_bit(KTHREAD_SHOULD_STOP) > wake_up_process() > wait_for_completion() > > set_current_state(TASK_INTERRUPTIBLE) > schedule() > > The most straightforward solution seems to be to invert the ordering of > the set_current_state and kthread_should_stop. > > The issue has been noticed during reboot test on a 3.0 based kernel but > the current code seems to be affected in the same way. > > Cc: stable # 3.6+ > Reported-and-Debugged-by: Mike Mayer > Signed-off-by: Michal Hocko > --- > drivers/scsi/scsi_error.c | 5 - > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c > index 6457a8a0db9c..2c0a817d5dbe 100644 > --- a/drivers/scsi/scsi_error.c > +++ b/drivers/scsi/scsi_error.c > @@ -2169,8 +2169,11 @@ int scsi_error_handler(void *data) >* We never actually get interrupted because kthread_run >* disables signal delivery for the created thread. >*/ > - while (!kthread_should_stop()) { > + while (true) { > set_current_state(TASK_INTERRUPTIBLE); > + if (kthread_should_stop()) > + break; > + > if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) > || > shost->host_failed != atomic_read(&shost->host_busy)) { > SCSI_LOG_ERROR_RECOVERY(1, > Reviewed-by: Hannes Reinecke Cheers, Hannes -- Dr. Hannes ReineckezSeries & Storage h...@suse.de +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton HRB 21284 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html