From 52cf17beda05e7e3d7bc635698e89cd0eddb2444 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:11 -0500 Subject: [PATCH 001/889] Change scsi.c scsi_log_completion() to print strings for QUEUED, SOFT_ERROR, SCSI_RETURN_NOT_HANDLED, and FAST_IO_FAIL rather than "UNKNOWN". Signed-off-by: Robert Elliott --- drivers/scsi/scsi.c | 59 ++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 79c77b485a6729..a6ae88b5e32223 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -553,6 +553,23 @@ void scsi_log_send(struct scsi_cmnd *cmd) } } +/* Strings for internal return values in scsi.h */ +/* NEEDS_RETRY must be the lowest numbered value */ +static const char * const disposition_label[] = { + "NEEDS_RETRY", + "SUCCESS", + "FAILED", + "QUEUED", + "SOFT_ERROR", + "ADD_TO_MLQUEUE", + "TIMEOUT_ERROR", + "SCSI_RETURN_NOT_HANDLED", + "FAST_IO_FAIL", + "UNKNOWN", +}; +#define DISPOSITION_BASE NEEDS_RETRY +#define DISPOSITION_UNKNOWN (ARRAY_SIZE(disposition_label) - 1) + void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) { unsigned int level; @@ -574,35 +591,21 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - scmd_printk(KERN_INFO, cmd, "Done: "); + int dindex; + + if (disposition >= DISPOSITION_BASE && + disposition <= DISPOSITION_BASE + + DISPOSITION_UNKNOWN) + dindex = disposition - DISPOSITION_BASE; + else + dindex = DISPOSITION_UNKNOWN; if (level > 2) - printk("0x%p ", cmd); - /* - * Dump truncated values, so we usually fit within - * 80 chars. - */ - switch (disposition) { - case SUCCESS: - printk("SUCCESS\n"); - break; - case NEEDS_RETRY: - printk("RETRY\n"); - break; - case ADD_TO_MLQUEUE: - printk("MLQUEUE\n"); - break; - case FAILED: - printk("FAILED\n"); - break; - case TIMEOUT_ERROR: - /* - * If called via scsi_times_out. - */ - printk("TIMEOUT\n"); - break; - default: - printk("UNKNOWN\n"); - } + scmd_printk(KERN_INFO, cmd, "Done: 0x%p %s\n", + cmd, + disposition_label[dindex]); + else + scmd_printk(KERN_INFO, cmd, "Done: %s\n", + disposition_label[dindex]); scsi_print_result(cmd); scsi_print_command(cmd); if (status_byte(cmd->result) & CHECK_CONDITION) From baf5d81febcabfd6ae615f9fa1bb92682c5ddfa2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:12 -0500 Subject: [PATCH 002/889] Set scsi_logging_level to be more verbose to get better messages while booting --- drivers/scsi/scsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a6ae88b5e32223..362e443e7d5eb1 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -80,7 +80,10 @@ * Note - the initial logging level can be set here to log events at boot time. * After the system is up, you may enable logging via the /proc interface. */ -unsigned int scsi_logging_level; +unsigned int scsi_logging_level = + (0x5 & ((1 << SCSI_LOG_ERROR_BITS) - 1)) << SCSI_LOG_ERROR_SHIFT | + (0x1 & ((1 << SCSI_LOG_MLCOMPLETE_BITS) - 1)) << SCSI_LOG_MLCOMPLETE_SHIFT; + #if defined(CONFIG_SCSI_LOGGING) EXPORT_SYMBOL(scsi_logging_level); #endif From 80d71a1a2b8f023287e205ef4a730a0212ec8279 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:12 -0500 Subject: [PATCH 003/889] hpsa: remove dev_warn prints from RAID-1ADM RAID-1ADM is unusable with dev_warn called on every command. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cef5d49b59cd24..2a213fa968f21a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3809,11 +3809,6 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, offload_to_mirror = (offload_to_mirror >= map->layout_map_count - 1) ? 0 : offload_to_mirror + 1; - /* FIXME: remove after debug/dev */ - BUG_ON(offload_to_mirror >= map->layout_map_count); - dev_warn(&h->pdev->dev, - "DEBUG: Using physical disk map index %d from mirror group %d\n", - map_index, offload_to_mirror); dev->offload_to_mirror = offload_to_mirror; /* Avoid direct use of dev->offload_to_mirror within this * function since multiple threads might simultaneously From 814ce03454c024bb38f323dcb6ba24e692dc6899 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:13 -0500 Subject: [PATCH 004/889] hpsa: fix a couple pci id table mistakes Subdevice ID 0x3323 was missing from product[] table (another name for HP Smart Storage 1210m) Bogus 0x1925 subdevice id removed from hpsa_pci_device_id[] (no such thing.) Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2a213fa968f21a..34f941dc5e8584 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -103,7 +103,6 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1925}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1929}, @@ -149,6 +148,7 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324A103C, "Smart Array P712m", &SA5_access}, {0x324B103C, "Smart Array P711m", &SA5_access}, + {0x3233103C, "HP StorageWorks 1210m", &SA5_access}, /* alias of 333f */ {0x3350103C, "Smart Array P222", &SA5_access}, {0x3351103C, "Smart Array P420", &SA5_access}, {0x3352103C, "Smart Array P421", &SA5_access}, From dff76c358d9d5b3b0657b24551e91df111d4a4d0 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:13 -0500 Subject: [PATCH 005/889] hpsa: fix a string constant broken into two lines Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 34f941dc5e8584..87c8c49cd62cfb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7073,8 +7073,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irq(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { - dev_warn(&h->pdev->dev, "Failed to request_irq after " - "soft reset.\n"); + dev_warn(&h->pdev->dev, + "Failed to request_irq after soft reset.\n"); goto clean4; } From 44775dea42770d6fd758d0bf9119ab8598b8112d Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:00:14 -0500 Subject: [PATCH 006/889] hpsa: correct off-by-one sizing of chained SG block Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 87c8c49cd62cfb..bd04092909936c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6318,11 +6318,11 @@ static void hpsa_find_board_params(struct ctlr_info *h) h->max_cmd_sg_entries = 31; if (h->maxsgentries > 512) { h->max_cmd_sg_entries = 32; - h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; + h->chainsize = h->maxsgentries - h->max_cmd_sg_entries; h->maxsgentries--; /* save one for chain pointer */ } else { - h->maxsgentries = 31; /* default to traditional values */ h->chainsize = 0; + h->maxsgentries = 31; /* default to traditional values */ } /* Find out what task management functions are supported and cache */ From 8f305fae5661d922bcf4088b7ffbb4c4b7144721 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:15 -0500 Subject: [PATCH 007/889] hpsa: remove 'action required' phrasing In the case of LUN data changing, the driver will auto rescan and so it's not even true that "action" is "required". Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik --- drivers/scsi/hpsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bd04092909936c..e519f070fd10ec 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -274,12 +274,12 @@ static int check_for_unit_attention(struct ctlr_info *h, "detected, command retried\n", h->ctlr); break; case LUN_FAILED: - dev_warn(&h->pdev->dev, HPSA "%d: LUN failure " - "detected, action required\n", h->ctlr); + dev_warn(&h->pdev->dev, + HPSA "%d: LUN failure detected\n", h->ctlr); break; case REPORT_LUNS_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: report LUN data " - "changed, action required\n", h->ctlr); + dev_warn(&h->pdev->dev, + HPSA "%d: report LUN data changed\n", h->ctlr); /* * Note: this REPORT_LUNS_CHANGED condition only occurs on the external * target (array) devices. From 308ec6dd13d1a40de1d27d5eec6eca2b5c1d99ca Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:15 -0500 Subject: [PATCH 008/889] hpsa: fix allocation sizes for CISS_REPORT_LUNs commands We were allocating roughly double the amount of memory we should be due to ReportLUNdata and ExtendedReportLUNdata containing a non-zero sized array but adding extra memory to allocate as if the array were zero sized. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++------- drivers/scsi/hpsa_cmd.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e519f070fd10ec..d2386d4e24e225 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2891,7 +2891,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, * Returns 0 on success, -1 otherwise. */ static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportlunsize, + int reportphyslunsize, int reportloglunsize, struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode, struct ReportLUNdata *logdev, u32 *nlogicals) { @@ -2905,7 +2905,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, *physical_mode = HPSA_REPORT_PHYS_EXTENDED; physical_entry_size = 24; } - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, + if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize, *physical_mode)) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; @@ -2918,7 +2918,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, *nphysicals - HPSA_MAX_PHYS_LUN); *nphysicals = HPSA_MAX_PHYS_LUN; } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportlunsize)) { + if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) { dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } @@ -3011,15 +3011,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; - int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; int rescan_hba_mode; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); - physdev_list = kzalloc(reportlunsize, GFP_KERNEL); - logdev_list = kzalloc(reportlunsize, GFP_KERNEL); + physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); + logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { @@ -3039,7 +3038,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, reportlunsize, + if (hpsa_gather_lun_info(h, + sizeof(*physdev_list), sizeof(*logdev_list), (struct ReportLUNdata *) physdev_list, &nphysicals, &physical_mode, logdev_list, &nlogicals)) goto out; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index b5125dc3143912..9b19042ff3304a 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -252,7 +252,7 @@ struct ReportExtendedLUNdata { u8 LUNListLength[4]; u8 extended_response_flag; u8 reserved[3]; - struct ext_report_lun_entry LUN[HPSA_MAX_LUN]; + struct ext_report_lun_entry LUN[HPSA_MAX_PHYS_LUN]; }; struct SenseSubsystem_info { From 41592852f127dfa98da309206dd07eee58a1dc6e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:16 -0500 Subject: [PATCH 009/889] hpsa: fix endianness issue with scatter gather elements The hardware needs little endian scatter gather addresses and lengths but we were not bothering to convert from cpu byte order as we should have been. On Intel, this is all just a bunch of no-ops macros, but it makes the code endian-clean(er). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 213 ++++++++++++++++++---------------------- drivers/scsi/hpsa_cmd.h | 14 +-- 2 files changed, 103 insertions(+), 124 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d2386d4e24e225..85dcc911dcc679 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1500,22 +1500,22 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h, { struct SGDescriptor *chain_sg, *chain_block; u64 temp64; + u32 chain_len; chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; chain_block = h->cmd_sg_list[c->cmdindex]; - chain_sg->Ext = HPSA_SG_CHAIN; - chain_sg->Len = sizeof(*chain_sg) * + chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN); + chain_len = sizeof(*chain_sg) * (c->Header.SGTotal - h->max_cmd_sg_entries); - temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len, + chain_sg->Len = cpu_to_le32(chain_len); + temp64 = pci_map_single(h->pdev, chain_block, chain_len, PCI_DMA_TODEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { /* prevent subsequent unmapping */ - chain_sg->Addr.lower = 0; - chain_sg->Addr.upper = 0; + chain_sg->Addr = 0; return -1; } - chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL); - chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL); + chain_sg->Addr = cpu_to_le64(temp64); return 0; } @@ -1523,15 +1523,13 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, struct CommandList *c) { struct SGDescriptor *chain_sg; - union u64bit temp64; - if (c->Header.SGTotal <= h->max_cmd_sg_entries) + if (le16_to_cpu(c->Header.SGTotal) <= h->max_cmd_sg_entries) return; chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; - temp64.val32.lower = chain_sg->Addr.lower; - temp64.val32.upper = chain_sg->Addr.upper; - pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); + pci_unmap_single(h->pdev, le64_to_cpu(chain_sg->Addr), + le32_to_cpu(chain_sg->Len), PCI_DMA_TODEVICE); } @@ -1732,8 +1730,7 @@ static void complete_scsi_command(struct CommandList *cp) struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; - cp->Header.Tag.lower = c->Tag.lower; - cp->Header.Tag.upper = c->Tag.upper; + cp->Header.tag = c->tag; memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8); memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen); @@ -1934,14 +1931,11 @@ static void hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c, int sg_used, int data_direction) { int i; - union u64bit addr64; - for (i = 0; i < sg_used; i++) { - addr64.val32.lower = c->SG[i].Addr.lower; - addr64.val32.upper = c->SG[i].Addr.upper; - pci_unmap_single(pdev, (dma_addr_t) addr64.val, c->SG[i].Len, - data_direction); - } + for (i = 0; i < sg_used; i++) + pci_unmap_single(pdev, (dma_addr_t) le64_to_cpu(c->SG[i].Addr), + le32_to_cpu(c->SG[i].Len), + data_direction); } static int hpsa_map_one(struct pci_dev *pdev, @@ -1954,7 +1948,7 @@ static int hpsa_map_one(struct pci_dev *pdev, if (buflen == 0 || data_direction == PCI_DMA_NONE) { cp->Header.SGList = 0; - cp->Header.SGTotal = 0; + cp->Header.SGTotal = cpu_to_le16(0); return 0; } @@ -1962,17 +1956,14 @@ static int hpsa_map_one(struct pci_dev *pdev, if (dma_mapping_error(&pdev->dev, addr64)) { /* Prevent subsequent unmap of something never mapped */ cp->Header.SGList = 0; - cp->Header.SGTotal = 0; + cp->Header.SGTotal = cpu_to_le16(0); return -1; } - cp->SG[0].Addr.lower = - (u32) (addr64 & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Addr.upper = - (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Len = buflen; - cp->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining */ + cp->SG[0].Addr = cpu_to_le64(addr64); + cp->SG[0].Len = cpu_to_le32(buflen); + cp->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* we are not chaining */ cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */ + cp->Header.SGTotal = (u16) cpu_to_le16(1); /* total sgs in cmd list */ return 0; } @@ -3186,7 +3177,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, unsigned int len; struct scatterlist *sg; u64 addr64; - int use_sg, i, sg_index, chained; + int use_sg, i, sg_index, chained, last_sg; struct SGDescriptor *curr_sg; BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); @@ -3201,6 +3192,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = cp->SG; chained = 0; sg_index = 0; + last_sg = scsi_sg_count(cmd) - 1; scsi_for_each_sg(cmd, sg, use_sg, i) { if (i == h->max_cmd_sg_entries - 1 && use_sg > h->max_cmd_sg_entries) { @@ -3210,10 +3202,9 @@ static int hpsa_scatter_gather(struct ctlr_info *h, } addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); - curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); - curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); - curr_sg->Len = len; - curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST; + curr_sg->Addr = cpu_to_le64(addr64); + curr_sg->Len = cpu_to_le32(len); + curr_sg->Ext = cpu_to_le32((i == last_sg) * HPSA_SG_LAST); curr_sg++; } @@ -3295,7 +3286,7 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, unsigned int total_len = 0; struct scatterlist *sg; u64 addr64; - int use_sg, i; + int use_sg, i, last_sg; struct SGDescriptor *curr_sg; u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE; @@ -3320,20 +3311,16 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, return use_sg; if (use_sg) { + last_sg = scsi_sg_count(cmd) - 1; curr_sg = cp->SG; scsi_for_each_sg(cmd, sg, use_sg, i) { addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); total_len += len; - curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); - curr_sg->Addr.upper = - (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); - curr_sg->Len = len; - - if (i == (scsi_sg_count(cmd) - 1)) - curr_sg->Ext = HPSA_SG_LAST; - else - curr_sg->Ext = 0; /* we are not chaining */ + curr_sg->Addr = cpu_to_le64(addr64); + curr_sg->Len = cpu_to_le32(len); + curr_sg->Ext = + cpu_to_le32((i == last_sg) * HPSA_SG_LAST); curr_sg++; } @@ -4021,8 +4008,9 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT); - c->Header.Tag.lower |= DIRECT_LOOKUP_BIT; + c->Header.tag = cpu_to_le64( + (u64) ((c->cmdindex << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT)); /* Fill in the request block... */ @@ -4324,8 +4312,8 @@ static void hpsa_get_tag(struct ctlr_info *h, if (c->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *) &h->ioaccel_cmd_pool[c->cmdindex]; - *tagupper = cm1->Tag.upper; - *taglower = cm1->Tag.lower; + *tagupper = (u32) (cm1->tag >> 32); + *taglower = (u32) (cm1->tag & 0x0ffffffffULL); return; } if (c->cmd_type == CMD_IOACCEL2) { @@ -4336,11 +4324,10 @@ static void hpsa_get_tag(struct ctlr_info *h, *taglower = cm2->Tag; return; } - *tagupper = c->Header.Tag.upper; - *taglower = c->Header.Tag.lower; + *tagupper = (u32) (c->Header.tag >> 32); + *taglower = (u32) (c->Header.tag & 0x0ffffffffULL); } - static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int swizzle) { @@ -4427,7 +4414,7 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, spin_lock_irqsave(&h->lock, flags); list_for_each_entry(c, queue_head, list) { - if (memcmp(&c->Header.Tag, tag, 8) != 0) + if (memcmp(&c->Header.tag, tag, 8) != 0) continue; spin_unlock_irqrestore(&h->lock, flags); return c; @@ -4709,9 +4696,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; - c->ErrDesc.Len = sizeof(*c->err_info); + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); + c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); c->h = h; return c; @@ -4724,7 +4710,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) static struct CommandList *cmd_special_alloc(struct ctlr_info *h) { struct CommandList *c; - union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); @@ -4745,9 +4730,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); c->ErrDesc.Len = sizeof(*c->err_info); c->h = h; @@ -4768,12 +4751,9 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c) static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) { - union u64bit temp64; - - temp64.val32.lower = c->ErrDesc.Addr.lower; - temp64.val32.upper = c->ErrDesc.Addr.upper; pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, (dma_addr_t) temp64.val); + c->err_info, + (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr)); pci_free_consistent(h->pdev, sizeof(*c), c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); } @@ -4927,7 +4907,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) IOCTL_Command_struct iocommand; struct CommandList *c; char *buff = NULL; - union u64bit temp64; + u64 temp64; int rc = 0; if (!argp) @@ -4965,15 +4945,15 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) /* Fill in Command Header */ c->Header.ReplyQueue = 0; /* unused in simple mode */ if (iocommand.buf_size > 0) { /* buffer to fill */ - c->Header.SGList = 1; - c->Header.SGTotal = 1; + c->Header.SGList = (u8) 1; + c->Header.SGTotal = cpu_to_le16(1); } else { /* no buffers to fill */ c->Header.SGList = 0; - c->Header.SGTotal = 0; + c->Header.SGTotal = cpu_to_le16(0); } memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); /* use the kernel address the cmd block for tag */ - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; /* Fill in Request block */ memcpy(&c->Request, &iocommand.Request, @@ -4981,19 +4961,17 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) /* Fill in the scatter gather information */ if (iocommand.buf_size > 0) { - temp64.val = pci_map_single(h->pdev, buff, + temp64 = (u64) pci_map_single(h->pdev, buff, iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(&h->pdev->dev, temp64.val)) { - c->SG[0].Addr.lower = 0; - c->SG[0].Addr.upper = 0; - c->SG[0].Len = 0; + if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) { + c->SG[0].Addr = cpu_to_le64(0); + c->SG[0].Len = cpu_to_le32(0); rc = -ENOMEM; goto out; } - c->SG[0].Addr.lower = temp64.val32.lower; - c->SG[0].Addr.upper = temp64.val32.upper; - c->SG[0].Len = iocommand.buf_size; - c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/ + c->SG[0].Addr = cpu_to_le64(temp64); + c->SG[0].Len = cpu_to_le32(iocommand.buf_size); + c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); if (iocommand.buf_size > 0) @@ -5028,7 +5006,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) struct CommandList *c; unsigned char **buff = NULL; int *buff_size = NULL; - union u64bit temp64; + u64 temp64; BYTE sg_used = 0; int status = 0; int i; @@ -5102,28 +5080,29 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; - c->Header.SGList = c->Header.SGTotal = sg_used; + c->Header.SGList = (u8) sg_used; + c->Header.SGTotal = cpu_to_le16(sg_used); memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; for (i = 0; i < sg_used; i++) { - temp64.val = pci_map_single(h->pdev, buff[i], + temp64 = (u64) pci_map_single(h->pdev, buff[i], buff_size[i], PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(&h->pdev->dev, temp64.val)) { - c->SG[i].Addr.lower = 0; - c->SG[i].Addr.upper = 0; + if (dma_mapping_error(&h->pdev->dev, + (dma_addr_t) temp64)) { + c->SG[i].Addr = 0; c->SG[i].Len = 0; hpsa_pci_unmap(h->pdev, c, i, PCI_DMA_BIDIRECTIONAL); status = -ENOMEM; goto cleanup0; } - c->SG[i].Addr.lower = temp64.val32.lower; - c->SG[i].Addr.upper = temp64.val32.upper; - c->SG[i].Len = buff_size[i]; - c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST; + c->SG[i].Addr = cpu_to_le64(temp64); + c->SG[i].Len = cpu_to_le32(buff_size[i]); + c->SG[i].Ext = + cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); @@ -5263,17 +5242,18 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, { int pci_dir = XFER_NONE; struct CommandList *a; /* for commands to be aborted */ + u32 tupper, tlower; c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; if (buff != NULL && size > 0) { - c->Header.SGList = 1; - c->Header.SGTotal = 1; + c->Header.SGList = (u8) 1; + c->Header.SGTotal = cpu_to_le32(1); } else { c->Header.SGList = 0; c->Header.SGTotal = 0; } - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); c->Request.Type.Type = cmd_type; @@ -5371,9 +5351,10 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case HPSA_ABORT_MSG: a = buff; /* point to command to be aborted */ - dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n", - a->Header.Tag.upper, a->Header.Tag.lower, - c->Header.Tag.upper, c->Header.Tag.lower); + dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx", + a->Header.tag, c->Header.tag); + tlower = (u32) (a->Header.tag >> 32); + tupper = (u32) (a->Header.tag & 0x0ffffffffULL); c->Request.CDBLen = 16; c->Request.Type.Type = TYPE_MSG; c->Request.Type.Attribute = ATTR_SIMPLE; @@ -5384,14 +5365,14 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[2] = 0x00; /* reserved */ c->Request.CDB[3] = 0x00; /* reserved */ /* Tag to abort goes in CDB[4]-CDB[11] */ - c->Request.CDB[4] = a->Header.Tag.lower & 0xFF; - c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF; - c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF; - c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF; - c->Request.CDB[8] = a->Header.Tag.upper & 0xFF; - c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF; - c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF; - c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF; + c->Request.CDB[4] = tlower & 0xFF; + c->Request.CDB[5] = (tlower >> 8) & 0xFF; + c->Request.CDB[6] = (tlower >> 16) & 0xFF; + c->Request.CDB[7] = (tlower >> 24) & 0xFF; + c->Request.CDB[8] = tupper & 0xFF; + c->Request.CDB[9] = (tupper >> 8) & 0xFF; + c->Request.CDB[10] = (tupper >> 16) & 0xFF; + c->Request.CDB[11] = (tupper >> 24) & 0xFF; c->Request.CDB[12] = 0x00; /* reserved */ c->Request.CDB[13] = 0x00; /* reserved */ c->Request.CDB[14] = 0x00; /* reserved */ @@ -5761,8 +5742,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, cmd->CommandHeader.ReplyQueue = 0; cmd->CommandHeader.SGList = 0; cmd->CommandHeader.SGTotal = 0; - cmd->CommandHeader.Tag.lower = paddr32; - cmd->CommandHeader.Tag.upper = 0; + cmd->CommandHeader.tag = (u64) paddr32; memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); cmd->Request.CDBLen = 16; @@ -5773,9 +5753,9 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, cmd->Request.CDB[0] = opcode; cmd->Request.CDB[1] = type; memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */ - cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(*cmd); - cmd->ErrorDescriptor.Addr.upper = 0; - cmd->ErrorDescriptor.Len = sizeof(struct ErrorInfo); + cmd->ErrorDescriptor.Addr = + cpu_to_le64((u64) (paddr32 + sizeof(*cmd))); + cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo)); writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET); @@ -7426,13 +7406,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT; cp->timeout_sec = 0; cp->ReplyQueue = 0; - cp->Tag.lower = (i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT; - cp->Tag.upper = 0; - cp->host_addr.lower = - (u32) (h->ioaccel_cmd_pool_dhandle + - (i * sizeof(struct io_accel1_cmd))); - cp->host_addr.upper = 0; + cp->tag = + cpu_to_le64((u64) ((i << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT)); + cp->host_addr = + cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + + (i * sizeof(struct io_accel1_cmd)))); } } else if (trans_support & CFGTBL_Trans_io_accel2) { u64 cfg_offset, cfg_base_addr_index; @@ -7706,7 +7685,7 @@ static void __attribute__((unused)) verify_offsets(void) VERIFY_OFFSET(timeout_sec, 0x62); VERIFY_OFFSET(ReplyQueue, 0x64); VERIFY_OFFSET(reserved9, 0x65); - VERIFY_OFFSET(Tag, 0x68); + VERIFY_OFFSET(tag, 0x68); VERIFY_OFFSET(host_addr, 0x70); VERIFY_OFFSET(CISS_LUN, 0x78); VERIFY_OFFSET(SG, 0x78 + 8); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 9b19042ff3304a..575eda8a8c5e51 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -314,7 +314,7 @@ struct CommandListHeader { u8 ReplyQueue; u8 SGList; u16 SGTotal; - struct vals32 Tag; + u64 tag; union LUNAddr LUN; }; @@ -330,12 +330,12 @@ struct RequestBlock { }; struct ErrDescriptor { - struct vals32 Addr; + u64 Addr; u32 Len; }; struct SGDescriptor { - struct vals32 Addr; + u64 Addr; u32 Len; u32 Ext; }; @@ -434,8 +434,8 @@ struct io_accel1_cmd { u16 timeout_sec; /* 0x62 - 0x63 */ u8 ReplyQueue; /* 0x64 */ u8 reserved9[3]; /* 0x65 - 0x67 */ - struct vals32 Tag; /* 0x68 - 0x6F */ - struct vals32 host_addr; /* 0x70 - 0x77 */ + u64 tag; /* 0x68 - 0x6F */ + u64 host_addr; /* 0x70 - 0x77 */ u8 CISS_LUN[8]; /* 0x78 - 0x7F */ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES]; } __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT); @@ -555,8 +555,8 @@ struct hpsa_tmf_struct { u8 reserved1; /* byte 3 Reserved */ u32 it_nexus; /* SCSI I-T Nexus */ u8 lun_id[8]; /* LUN ID for TMF request */ - struct vals32 Tag; /* cciss tag associated w/ request */ - struct vals32 abort_tag;/* cciss tag of SCSI cmd or task to abort */ + u64 tag; /* cciss tag associated w/ request */ + u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */ u64 error_ptr; /* Error Pointer */ u32 error_len; /* Error Length */ }; From 0d869d7a008a8a1287c7c1faa680eb058e4ef16c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:16 -0500 Subject: [PATCH 010/889] hpsa: get rid of type/attribute/direction bit field where possible Using bit fields for hardware command fields isn't portable and relies on assumptions about how the compiler lays out the bits. We can fix this in the driver's internal command structure, but the ioctl interface we can't change because it is part of the userland ABI. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 ++++++++++++++++++++--------------------- drivers/scsi/hpsa_cmd.h | 18 +++++++++---- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 85dcc911dcc679..679668b4f019b7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4019,17 +4019,18 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB)); c->Request.CDBLen = cmd->cmd_len; memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); - c->Request.Type.Type = TYPE_CMD; - c->Request.Type.Attribute = ATTR_SIMPLE; switch (cmd->sc_data_direction) { case DMA_TO_DEVICE: - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_WRITE); break; case DMA_FROM_DEVICE: - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_READ); break; case DMA_NONE: - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_NONE); break; case DMA_BIDIRECTIONAL: /* This can happen if a buggy application does a scsi passthru @@ -4037,7 +4038,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, * ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() ) */ - c->Request.Type.Direction = XFER_RSVD; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_RSVD); /* This is technically wrong, and hpsa controllers should * reject it with CMD_INVALID, which is the most correct * response, but non-fibre backends appear to let it @@ -5256,7 +5258,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); - c->Request.Type.Type = cmd_type; if (cmd_type == TYPE_CMD) { switch (cmd) { case HPSA_INQUIRY: @@ -5266,8 +5267,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[2] = (page_code & 0xff); } c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = HPSA_INQUIRY; c->Request.CDB[4] = size & 0xFF; @@ -5278,8 +5279,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, mode = 00 target = 0. Nothing to write. */ c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = cmd; c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */ @@ -5289,8 +5290,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case HPSA_CACHE_FLUSH: c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; @@ -5299,14 +5301,14 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case TEST_UNIT_READY: c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); c->Request.Timeout = 0; break; case HPSA_GET_RAID_MAP: c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = HPSA_CISS_READ; c->Request.CDB[1] = cmd; @@ -5317,8 +5319,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case BMIC_SENSE_CONTROLLER_PARAMETERS: c->Request.CDBLen = 10; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_READ; c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS; @@ -5335,9 +5337,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, case HPSA_DEVICE_RESET_MSG: c->Request.CDBLen = 16; - c->Request.Type.Type = 1; /* It is a MSG not a CMD */ - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); c->Request.Timeout = 0; /* Don't time out */ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); c->Request.CDB[0] = cmd; @@ -5356,9 +5357,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, tlower = (u32) (a->Header.tag >> 32); tupper = (u32) (a->Header.tag & 0x0ffffffffULL); c->Request.CDBLen = 16; - c->Request.Type.Type = TYPE_MSG; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); c->Request.Timeout = 0; /* Don't time out */ c->Request.CDB[0] = HPSA_TASK_MANAGEMENT; c->Request.CDB[1] = HPSA_TMF_ABORT_TASK; @@ -5388,7 +5389,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, BUG(); } - switch (c->Request.Type.Direction) { + switch (GET_DIR(c->Request.type_attr_dir)) { case XFER_READ: pci_dir = PCI_DMA_FROMDEVICE; break; @@ -5746,9 +5747,8 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); cmd->Request.CDBLen = 16; - cmd->Request.Type.Type = TYPE_MSG; - cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE; - cmd->Request.Type.Direction = XFER_NONE; + cmd->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_MSG, ATTR_HEADOFQUEUE, XFER_NONE); cmd->Request.Timeout = 0; /* Don't time out */ cmd->Request.CDB[0] = opcode; cmd->Request.CDB[1] = type; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 575eda8a8c5e51..cb988c41cad915 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -320,11 +320,19 @@ struct CommandListHeader { struct RequestBlock { u8 CDBLen; - struct { - u8 Type:3; - u8 Attribute:3; - u8 Direction:2; - } Type; + /* + * type_attr_dir: + * type: low 3 bits + * attr: middle 3 bits + * dir: high 2 bits + */ + u8 type_attr_dir; +#define TYPE_ATTR_DIR(t, a, d) ((((d) & 0x03) << 6) |\ + (((a) & 0x07) << 3) |\ + ((t) & 0x07)) +#define GET_TYPE(tad) ((tad) & 0x07) +#define GET_ATTR(tad) (((tad) >> 3) & 0x07) +#define GET_DIR(tad) (((tad) >> 6) & 0x03) u16 Timeout; u8 CDB[16]; }; From fafd1d992ea85b1ce7ca8d2af12dc12a47a17a82 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:17 -0500 Subject: [PATCH 011/889] hpsa: use atomics for commands_outstanding instead of protecting with spin locks Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik --- drivers/scsi/hpsa.c | 26 +++++++++----------------- drivers/scsi/hpsa.h | 27 +++++++-------------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 679668b4f019b7..663a254f69f229 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -392,7 +392,8 @@ static ssize_t host_show_commands_outstanding(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ctlr_info *h = shost_to_hba(shost); - return snprintf(buf, 20, "%d\n", h->commands_outstanding); + return snprintf(buf, 20, "%d\n", + atomic_read(&h->commands_outstanding)); } static ssize_t host_show_transport_mode(struct device *dev, @@ -698,7 +699,6 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags; if (h->transMethod & CFGTBL_Trans_io_accel1) return h->access.command_completed(h, q); @@ -709,9 +709,7 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { a = rq->head[rq->current_entry]; rq->current_entry++; - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } else { a = FIFO_EMPTY; } @@ -5444,15 +5442,9 @@ static void start_io(struct ctlr_info *h, unsigned long *flags) /* Put job onto the completed Q */ addQ(&h->cmpQ, c); - - /* Must increment commands_outstanding before unlocking - * and submitting to avoid race checking for fifo full - * condition. - */ - h->commands_outstanding++; - - /* Tell the controller execute command */ + atomic_inc(&h->commands_outstanding); spin_unlock_irqrestore(&h->lock, *flags); + /* Tell the controller execute command */ h->access.submit_command(h, c); spin_lock_irqsave(&h->lock, *flags); } @@ -5498,6 +5490,7 @@ static inline void finish_cmd(struct CommandList *c) unsigned long flags; int io_may_be_stalled = 0; struct ctlr_info *h = c->h; + int count; spin_lock_irqsave(&h->lock, flags); removeQ(c); @@ -5518,11 +5511,10 @@ static inline void finish_cmd(struct CommandList *c) * want to get in a cycle where we call start_io every time * through here. */ - if (unlikely(h->fifo_recently_full) && - h->commands_outstanding < 5) - io_may_be_stalled = 1; - + count = atomic_read(&h->commands_outstanding); spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(h->fifo_recently_full) && count < 5) + io_may_be_stalled = 1; dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 24472cec7de34d..954f0de33b97f3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -118,7 +118,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; - int commands_outstanding; + atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 # define SIMPLE_MODE_INT 2 @@ -395,7 +395,7 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) { struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags, register_value = FIFO_EMPTY; + unsigned long register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ if (!(h->msi_vector || h->msix_vector)) { @@ -413,9 +413,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { register_value = rq->head[rq->current_entry]; rq->current_entry++; - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } else { register_value = FIFO_EMPTY; } @@ -433,11 +431,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) */ static unsigned long SA5_fifo_full(struct ctlr_info *h) { - if (h->commands_outstanding >= h->max_commands) - return 1; - else - return 0; - + return atomic_read(&h->commands_outstanding) >= h->max_commands; } /* * returns value read from hardware. @@ -448,13 +442,9 @@ static unsigned long SA5_completed(struct ctlr_info *h, { unsigned long register_value = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); - unsigned long flags; - if (register_value != FIFO_EMPTY) { - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); - } + if (register_value != FIFO_EMPTY) + atomic_dec(&h->commands_outstanding); #ifdef HPSA_DEBUG if (register_value != FIFO_EMPTY) @@ -510,7 +500,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) { u64 register_value; struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags; BUG_ON(q >= h->nreply_queues); @@ -528,9 +517,7 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) wmb(); writel((q << 24) | rq->current_entry, h->vaddr + IOACCEL_MODE1_CONSUMER_INDEX); - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } return (unsigned long) register_value; } From 8cc51c23393295a780f19ffa1acf242395a3dd8d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:17 -0500 Subject: [PATCH 012/889] hpsa: do not be so noisy about check conditions We were printing a lot of useless information before ultimately just passing things up to the SCSI mid layer. Just let the midlayer handle it without LLD chatter. Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik Reviewed-by: Scott Teel --- drivers/scsi/hpsa.c | 59 --------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 663a254f69f229..228bcad5852922 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1758,72 +1758,13 @@ static void complete_scsi_command(struct CommandList *cp) /* Get addition sense code qualifier */ ascq = ei->SenseInfo[13]; } - if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { - if (check_for_unit_attention(h, cp)) - break; - if (sense_key == ILLEGAL_REQUEST) { - /* - * SCSI REPORT_LUNS is commonly unsupported on - * Smart Array. Suppress noisy complaint. - */ - if (cp->Request.CDB[0] == REPORT_LUNS) - break; - - /* If ASC/ASCQ indicate Logical Unit - * Not Supported condition, - */ - if ((asc == 0x25) && (ascq == 0x0)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition\n", cp); - break; - } - } - - if (sense_key == NOT_READY) { - /* If Sense is Not Ready, Logical Unit - * Not ready, Manual Intervention - * required - */ - if ((asc == 0x04) && (ascq == 0x03)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: unit " - "not ready, manual " - "intervention required\n", cp); - break; - } - } if (sense_key == ABORTED_COMMAND) { - /* Aborted command is retryable */ - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: aborted command: " - "ASC: 0x%x, ASCQ: 0x%x\n", - cp, asc, ascq); cmd->result |= DID_SOFT_ERROR << 16; break; } - /* Must be some other type of check condition */ - dev_dbg(&h->pdev->dev, "cp %p has check condition: " - "unknown type: " - "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " - "Returning result: 0x%x, " - "cmd=[%02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x]\n", - cp, sense_key, asc, ascq, - cmd->result, - cmd->cmnd[0], cmd->cmnd[1], - cmd->cmnd[2], cmd->cmnd[3], - cmd->cmnd[4], cmd->cmnd[5], - cmd->cmnd[6], cmd->cmnd[7], - cmd->cmnd[8], cmd->cmnd[9], - cmd->cmnd[10], cmd->cmnd[11], - cmd->cmnd[12], cmd->cmnd[13], - cmd->cmnd[14], cmd->cmnd[15]); break; } - - /* Problem was not a check condition * Pass it up to the upper layers... */ From edbdf35a3b8044c612f76c36387e375bb7fda582 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 20 Oct 2014 17:00:18 -0500 Subject: [PATCH 013/889] hpsa: Convert SCSI LLD ->queuecommand() for host_lock less operation There isn't anything in hpsa that requires the host lock to be held during queuecommand. Signed-off-by: Nicholas Bellinger Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 228bcad5852922..c3e369899f122d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3880,8 +3880,11 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +/* + * Running in struct Scsi_Host->host_lock less mode using LLD internal + * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection. + */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; @@ -3894,14 +3897,14 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); if (unlikely(lockup_detected(h))) { cmd->result = DID_ERROR << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } c = cmd_alloc(h); @@ -3911,9 +3914,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, } /* Fill in the command list header */ - - cmd->scsi_done = done; /* save this for use by completion code */ - /* save c in case we have to abort it */ cmd->host_scribble = (unsigned char *) c; @@ -4005,8 +4005,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, return 0; } -static DEF_SCSI_QCMD(hpsa_scsi_queue_command) - static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) { unsigned long flags; From 40947fe86d76b58eb4b874b99fb8ea8b4844a3cd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:19 -0500 Subject: [PATCH 014/889] hpsa: remove spin lock around command allocation It is already using atomic test_and_set_bit to do the allocation. There is some microscopic chance of starvation, but it is so microscopic that it should never happen in reality. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c3e369899f122d..58d86aeddc1556 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4607,19 +4607,32 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - unsigned long flags; + int loopcount; + + /* There is some *extremely* small but non-zero chance that that + * multiple threads could get in here, and one thread could + * be scanning through the list of bits looking for a free + * one, but the free ones are always behind him, and other + * threads sneak in behind him and eat them before he can + * get to them, so that while there is always a free one, a + * very unlucky thread might be starved anyway, never able to + * beat the other threads. In reality, this happens so + * infrequently as to be indistinguishable from never. + */ - spin_lock_irqsave(&h->lock, flags); + loopcount = 0; do { i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) { - spin_unlock_irqrestore(&h->lock, flags); - return NULL; - } - } while (test_and_set_bit - (i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0); - spin_unlock_irqrestore(&h->lock, flags); + if (i == h->nr_cmds) + i = 0; + loopcount++; + } while (test_and_set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && + loopcount < 10); + + /* Thread got starved? We do not expect this to ever happen. */ + if (loopcount >= 10 && i == h->nr_cmds) + return NULL; c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); @@ -4679,13 +4692,10 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; - unsigned long flags; i = c - h->cmd_pool; - spin_lock_irqsave(&h->lock, flags); clear_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); - spin_unlock_irqrestore(&h->lock, flags); } static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) From 5870a7473e0da47267692d68bf0ab81b72d80f57 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:19 -0500 Subject: [PATCH 015/889] hpsa: reserve some commands for use by driver We need to reserve some commands for device rescans, aborts, and the pass through ioctls, etc. so we cannot give them all to the scsi mid layer. This is in preparation for removing cmd_special_alloc and cmd_special_free so that we can stop queuing commands internally in the driver so that we can remove the locks thta protect the queue that we will no longer have. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++-- drivers/scsi/hpsa.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 58d86aeddc1556..1e597f2ccadbf3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4115,11 +4115,14 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds; + sh->can_queue = h->nr_cmds - + HPSA_CMDS_RESERVED_FOR_ABORTS - + HPSA_CMDS_RESERVED_FOR_DRIVER - + HPSA_MAX_CONCURRENT_PASSTHRUS; if (h->hba_mode_enabled) sh->cmd_per_lun = 7; else - sh->cmd_per_lun = h->nr_cmds; + sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 954f0de33b97f3..4fae28e1af56e5 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -115,6 +115,8 @@ struct ctlr_info { void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ +#define HPSA_CMDS_RESERVED_FOR_ABORTS 2 +#define HPSA_CMDS_RESERVED_FOR_DRIVER 1 struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; From 74af55b8d84d86c4231622874032ae48505aaab7 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:20 -0500 Subject: [PATCH 016/889] hpsa: get rid of cmd_special_alloc and cmd_special_free Always use cmd_alloc and cmd_free instead, we should have reserved enough commands that we should not need to ever dynamically allocate any and should always have enough. This is laying the groundwork for removing the internal queue of commands from the driver so that the locks that protect that queue may be removed. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 106 +++++++++++++------------------------------- drivers/scsi/hpsa.h | 2 +- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1e597f2ccadbf3..86a22aaf920a83 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -202,9 +202,7 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); #endif static void cmd_free(struct ctlr_info *h, struct CommandList *c); -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); -static struct CommandList *cmd_special_alloc(struct ctlr_info *h); static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type); @@ -2048,10 +2046,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2067,7 +2065,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2079,10 +2077,10 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2098,7 +2096,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2109,10 +2107,9 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); - + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2128,7 +2125,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, hpsa_scsi_interpret_error(h, c); rc = -1; } - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2238,26 +2235,26 @@ static int hpsa_get_raid_map(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - cmd_special_free(h, c); + cmd_free(h, c); return -ENOMEM; } hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); - cmd_special_free(h, c); + cmd_free(h, c); return -1; } - cmd_special_free(h, c); + cmd_free(h, c); /* @todo in the future, dynamically allocate RAID map memory */ if (le32_to_cpu(this_device->raid_map.structure_size) > @@ -2377,9 +2374,9 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, unsigned char scsi3addr[8]; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -1; } /* address the controller */ @@ -2407,7 +2404,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -4153,7 +4150,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, int waittime = 1; /* seconds */ struct CommandList *c; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { dev_warn(&h->pdev->dev, "out of memory in " "wait_for_device_to_become_ready.\n"); @@ -4199,7 +4196,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, else dev_warn(&h->pdev->dev, "device is ready.\n"); - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -4278,9 +4275,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; u32 tagupper, taglower; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -4309,7 +4306,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; break; } - cmd_special_free(h, c); + cmd_free(h, c); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, tagupper, taglower); return rc; @@ -4658,40 +4655,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) return c; } -/* For operations that can wait for kmalloc to possibly sleep, - * this routine can be called. Lock need not be held to call - * cmd_special_alloc. cmd_special_free() is the complement. - */ -static struct CommandList *cmd_special_alloc(struct ctlr_info *h) -{ - struct CommandList *c; - dma_addr_t cmd_dma_handle, err_dma_handle; - - c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); - if (c == NULL) - return NULL; - - c->cmd_type = CMD_SCSI; - c->cmdindex = -1; - - c->err_info = pci_zalloc_consistent(h->pdev, sizeof(*c->err_info), - &err_dma_handle); - - if (c->err_info == NULL) { - pci_free_consistent(h->pdev, - sizeof(*c), c, cmd_dma_handle); - return NULL; - } - - INIT_LIST_HEAD(&c->list); - c->busaddr = (u32) cmd_dma_handle; - c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); - c->ErrDesc.Len = sizeof(*c->err_info); - - c->h = h; - return c; -} - static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; @@ -4701,15 +4664,6 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c) h->cmd_pool_bits + (i / BITS_PER_LONG)); } -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) -{ - pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, - (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr)); - pci_free_consistent(h->pdev, sizeof(*c), - c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); -} - #ifdef CONFIG_COMPAT static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg) @@ -4887,7 +4841,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) memset(buff, 0, iocommand.buf_size); } } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { rc = -ENOMEM; goto out_kfree; @@ -4946,7 +4900,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) } } out: - cmd_special_free(h, c); + cmd_free(h, c); out_kfree: kfree(buff); return rc; @@ -5025,7 +4979,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) data_ptr += sz; sg_used++; } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { status = -ENOMEM; goto cleanup1; @@ -5080,7 +5034,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } status = 0; cleanup0: - cmd_special_free(h, c); + cmd_free(h, c); cleanup1: if (buff) { for (i = 0; i < sg_used; i++) @@ -6232,7 +6186,7 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) static void hpsa_find_board_params(struct ctlr_info *h) { hpsa_get_max_perf_mode_cmds(h); - h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ + h->nr_cmds = h->max_commands; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); /* @@ -7074,9 +7028,9 @@ static void hpsa_flush_cache(struct ctlr_info *h) if (!flush_buf) return; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); goto out_of_memory; } if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, @@ -7088,7 +7042,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) out: dev_warn(&h->pdev->dev, "error flushing cache on controller\n"); - cmd_special_free(h, c); + cmd_free(h, c); out_of_memory: kfree(flush_buf); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 4fae28e1af56e5..fcbcf5ac977485 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -170,7 +170,7 @@ struct ctlr_info { unsigned long transMethod; /* cap concurrent passthrus at some reasonable maximum */ -#define HPSA_MAX_CONCURRENT_PASSTHRUS (20) +#define HPSA_MAX_CONCURRENT_PASSTHRUS (10) spinlock_t passthru_count_lock; /* protects passthru_count */ int passthru_count; From 07bb978644b15b5ab942841d2eda4415a8a0ae04 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:20 -0500 Subject: [PATCH 017/889] hpsa: do not queue commands internally in driver By not doing this, we can eliminate some spin locking in the main i/o path and gain significant improvement in IOPS. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 257 ++++++---------------------------------- drivers/scsi/hpsa.h | 3 - drivers/scsi/hpsa_cmd.h | 1 - 3 files changed, 34 insertions(+), 227 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 86a22aaf920a83..676691cb547f6b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -194,8 +194,6 @@ static int number_of_controllers; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); -static void lock_and_start_io(struct ctlr_info *h); -static void start_io(struct ctlr_info *h, unsigned long *flags); #ifdef CONFIG_COMPAT static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); @@ -686,13 +684,6 @@ static struct scsi_host_template hpsa_driver_template = { .no_write_same = 1, }; - -/* Enqueuing and dequeuing functions for cmdlists. */ -static inline void addQ(struct list_head *list, struct CommandList *c) -{ - list_add_tail(&c->list, list); -} - static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; @@ -826,8 +817,6 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - unsigned long flags; - switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c); @@ -839,18 +828,8 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h, set_performant_mode(h, c); } dial_down_lockup_detection_during_fw_flash(h, c); - spin_lock_irqsave(&h->lock, flags); - addQ(&h->reqQ, c); - h->Qdepth++; - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - -static inline void removeQ(struct CommandList *c) -{ - if (WARN_ON(list_empty(&c->list))) - return; - list_del_init(&c->list); + atomic_inc(&h->commands_outstanding); + h->access.submit_command(h, c); } static inline int is_hba_lunid(unsigned char scsi3addr[]) @@ -3877,10 +3856,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -/* - * Running in struct Scsi_Host->host_lock less mode using LLD internal - * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection. - */ +/* Running in struct Scsi_Host->host_lock less mode */ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; @@ -4312,56 +4288,6 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, return rc; } -/* - * hpsa_find_cmd_in_queue - * - * Used to determine whether a command (find) is still present - * in queue_head. Optionally excludes the last element of queue_head. - * - * This is used to avoid unnecessary aborts. Commands in h->reqQ have - * not yet been submitted, and so can be aborted by the driver without - * sending an abort to the hardware. - * - * Returns pointer to command if found in queue, NULL otherwise. - */ -static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h, - struct scsi_cmnd *find, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c = NULL; /* ptr into cmpQ */ - - if (!find) - return 0; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */ - continue; - if (c->scsi_cmd == find) { - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - -static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, - u8 *tag, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c; - - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (memcmp(&c->Header.tag, tag, 8) != 0) - continue; - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - /* ioaccel2 path firmware cannot handle abort task requests. * Change abort requests to physical target reset, and send to the * address of the physical disk used for the ioaccel 2 command. @@ -4448,10 +4374,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort) { - u8 swizzled_tag[8]; - struct CommandList *c; - int rc = 0, rc2 = 0; - /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, * but underlying firmware can't handle abort TMF. @@ -4460,27 +4382,8 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, if (abort->cmd_type == CMD_IOACCEL2) return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort); - /* we do not expect to find the swizzled tag in our queue, but - * check anyway just to be sure the assumptions which make this - * the case haven't become wrong. - */ - memcpy(swizzled_tag, &abort->Request.CDB[4], 8); - swizzle_abort_tag(swizzled_tag); - c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ); - if (c != NULL) { - dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n"); - return hpsa_send_abort(h, scsi3addr, abort, 0); - } - rc = hpsa_send_abort(h, scsi3addr, abort, 0); - - /* if the command is still in our queue, we can't conclude that it was - * aborted (it might have just completed normally) but in any case - * we don't need to try to abort it another way. - */ - c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ); - if (c) - rc2 = hpsa_send_abort(h, scsi3addr, abort, 1); - return rc && rc2; + return hpsa_send_abort(h, scsi3addr, abort, 0) && + hpsa_send_abort(h, scsi3addr, abort, 1); } /* Send an abort for the specified command. @@ -4494,7 +4397,6 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; struct CommandList *abort; /* pointer to command to be aborted */ - struct CommandList *found; struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */ char msg[256]; /* For debug messaging. */ int ml = 0; @@ -4540,28 +4442,6 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) dev_dbg(&h->pdev->dev, "%s\n", msg); dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); - - /* Search reqQ to See if command is queued but not submitted, - * if so, complete the command with aborted status and remove - * it from the reqQ. - */ - found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ); - if (found) { - found->err_info->CommandStatus = CMD_ABORTED; - finish_cmd(found); - dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n", - msg); - return SUCCESS; - } - - /* not in reqQ, if also not in cmpQ, must have already completed */ - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) { - dev_dbg(&h->pdev->dev, "%s Request SUCCEEDED (not known to driver).\n", - msg); - return SUCCESS; - } - /* * Command is in flight, or possibly already completed * by the firmware (but not to the scsi mid layer) but we can't @@ -4584,10 +4464,12 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ #define ABORT_COMPLETE_WAIT_SECS 30 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) + if (test_bit(abort->cmdindex & (BITS_PER_LONG - 1), + h->cmd_pool_bits + + (abort->cmdindex / BITS_PER_LONG))) + msleep(100); + else return SUCCESS; - msleep(100); } dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", msg, ABORT_COMPLETE_WAIT_SECS); @@ -4636,6 +4518,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); + c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT); cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; @@ -4645,7 +4529,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c->cmdindex = i; - INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; temp64.val = (u64) err_dma_handle; c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); @@ -4858,8 +4741,6 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGTotal = cpu_to_le16(0); } memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); - /* use the kernel address the cmd block for tag */ - c->Header.tag = c->busaddr; /* Fill in Request block */ memcpy(&c->Request, &iocommand.Request, @@ -4989,7 +4870,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGList = (u8) sg_used; c->Header.SGTotal = cpu_to_le16(sg_used); memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.tag = c->busaddr; memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; @@ -5159,7 +5039,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Header.SGList = 0; c->Header.SGTotal = 0; } - c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); if (cmd_type == TYPE_CMD) { @@ -5324,47 +5203,6 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) return page_remapped ? (page_remapped + page_offs) : NULL; } -/* Takes cmds off the submission queue and sends them to the hardware, - * then puts them on the queue of cmds waiting for completion. - * Assumes h->lock is held - */ -static void start_io(struct ctlr_info *h, unsigned long *flags) -{ - struct CommandList *c; - - while (!list_empty(&h->reqQ)) { - c = list_entry(h->reqQ.next, struct CommandList, list); - /* can't do anything if fifo is full */ - if ((h->access.fifo_full(h))) { - h->fifo_recently_full = 1; - dev_warn(&h->pdev->dev, "fifo full\n"); - break; - } - h->fifo_recently_full = 0; - - /* Get the first entry from the Request Q */ - removeQ(c); - h->Qdepth--; - - /* Put job onto the completed Q */ - addQ(&h->cmpQ, c); - atomic_inc(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, *flags); - /* Tell the controller execute command */ - h->access.submit_command(h, c); - spin_lock_irqsave(&h->lock, *flags); - } -} - -static void lock_and_start_io(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->lock, flags); - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q) { return h->access.command_completed(h, q); @@ -5393,43 +5231,12 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index, static inline void finish_cmd(struct CommandList *c) { - unsigned long flags; - int io_may_be_stalled = 0; - struct ctlr_info *h = c->h; - int count; - - spin_lock_irqsave(&h->lock, flags); - removeQ(c); - - /* - * Check for possibly stalled i/o. - * - * If a fifo_full condition is encountered, requests will back up - * in h->reqQ. This queue is only emptied out by start_io which is - * only called when a new i/o request comes in. If no i/o's are - * forthcoming, the i/o's in h->reqQ can get stuck. So we call - * start_io from here if we detect such a danger. - * - * Normally, we shouldn't hit this case, but pounding on the - * CCISS_PASSTHRU ioctl can provoke it. Only call start_io if - * commands_outstanding is low. We want to avoid calling - * start_io from in here as much as possible, and esp. don't - * want to get in a cycle where we call start_io every time - * through here. - */ - count = atomic_read(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, flags); - if (unlikely(h->fifo_recently_full) && count < 5) - io_may_be_stalled = 1; - dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI || c->cmd_type == CMD_IOACCEL2)) complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); - if (unlikely(io_may_be_stalled)) - lock_and_start_io(h); } static inline u32 hpsa_tag_contains_index(u32 tag) @@ -5474,6 +5281,10 @@ static inline void process_nonindexed_cmd(struct ctlr_info *h, struct CommandList *c = NULL; unsigned long flags; + /* FIXME finish removing process nonindexed command */ + dev_warn(&h->pdev->dev, "unexpectedly got non-indexed command\n"); + return; +#if 0 tag = hpsa_tag_discard_error_bits(h, raw_tag); spin_lock_irqsave(&h->lock, flags); list_for_each_entry(c, &h->cmpQ, list) { @@ -5485,6 +5296,7 @@ static inline void process_nonindexed_cmd(struct ctlr_info *h, } spin_unlock_irqrestore(&h->lock, flags); bad_tag(h, h->nr_cmds + 1, raw_tag); +#endif } /* Some controllers, like p400, will give us one interrupt @@ -6631,14 +6443,16 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) } /* Called when controller lockup detected. */ -static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) +static void fail_all_outstanding_cmds(struct ctlr_info *h) { + int i; struct CommandList *c = NULL; - assert_spin_locked(&h->lock); - /* Mark all outstanding commands as failed and complete them. */ - while (!list_empty(list)) { - c = list_entry(list->next, struct CommandList, list); + for (i = 0; i < h->nr_cmds; i++) { + if (!test_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG))) + continue; + c = h->cmd_pool + i; c->err_info->CommandStatus = CMD_HARDWARE_ERR; finish_cmd(c); } @@ -6678,8 +6492,7 @@ static void controller_lockup_detected(struct ctlr_info *h) lockup_detected); pci_disable_device(h->pdev); spin_lock_irqsave(&h->lock, flags); - fail_all_cmds_on_list(h, &h->cmpQ); - fail_all_cmds_on_list(h, &h->reqQ); + fail_all_outstanding_cmds(h); spin_unlock_irqrestore(&h->lock, flags); } @@ -6871,8 +6684,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->pdev = pdev; h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; - INIT_LIST_HEAD(&h->cmpQ); - INIT_LIST_HEAD(&h->reqQ); INIT_LIST_HEAD(&h->offline_device_list); spin_lock_init(&h->lock); spin_lock_init(&h->offline_device_lock); @@ -7481,19 +7292,19 @@ static int is_accelerated_cmd(struct CommandList *c) static void hpsa_drain_accel_commands(struct ctlr_info *h) { struct CommandList *c = NULL; - unsigned long flags; - int accel_cmds_out; + int i, accel_cmds_out; - do { /* wait for all outstanding commands to drain out */ + do { /* wait for all outstanding ioaccel commands to drain out */ accel_cmds_out = 0; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) - accel_cmds_out += is_accelerated_cmd(c); - list_for_each_entry(c, &h->reqQ, list) + for (i = 0; i < h->nr_cmds; i++) { + if (!test_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG))) + continue; + c = h->cmd_pool + i; accel_cmds_out += is_accelerated_cmd(c); - spin_unlock_irqrestore(&h->lock, flags); + } if (accel_cmds_out <= 0) - break; + break; msleep(100); } while (1); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index fcbcf5ac977485..16e1f4497d3a92 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -133,8 +133,6 @@ struct ctlr_info { char hba_mode_enabled; /* queue and queue Info */ - struct list_head reqQ; - struct list_head cmpQ; unsigned int Qdepth; unsigned int maxSG; spinlock_t lock; @@ -197,7 +195,6 @@ struct ctlr_info { u32 *lockup_detected; struct delayed_work monitor_ctlr_work; int remove_in_progress; - u32 fifo_recently_full; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index cb988c41cad915..a0de310622b0a4 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -405,7 +405,6 @@ struct CommandList { struct ctlr_info *h; int cmd_type; long cmdindex; - struct list_head list; struct completion *waiting; void *scsi_cmd; } __aligned(COMMANDLIST_ALIGNMENT); From 0de9b89f4dedfa85aebd7420363bf68abddc0d52 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:21 -0500 Subject: [PATCH 018/889] hpsa: remove unused interrupt handler code Now that we never use "non-indexed" method for completing commands we can remove the code to handle that from the interrupt handler Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 676691cb547f6b..266f07b8e6f6e9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5239,11 +5239,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } -static inline u32 hpsa_tag_contains_index(u32 tag) -{ - return tag & DIRECT_LOOKUP_BIT; -} - static inline u32 hpsa_tag_to_index(u32 tag) { return tag >> DIRECT_LOOKUP_SHIFT; @@ -5273,32 +5268,6 @@ static inline void process_indexed_cmd(struct ctlr_info *h, } } -/* process completion of a non-indexed command */ -static inline void process_nonindexed_cmd(struct ctlr_info *h, - u32 raw_tag) -{ - u32 tag; - struct CommandList *c = NULL; - unsigned long flags; - - /* FIXME finish removing process nonindexed command */ - dev_warn(&h->pdev->dev, "unexpectedly got non-indexed command\n"); - return; -#if 0 - tag = hpsa_tag_discard_error_bits(h, raw_tag); - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) { - if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { - spin_unlock_irqrestore(&h->lock, flags); - finish_cmd(c); - return; - } - } - spin_unlock_irqrestore(&h->lock, flags); - bad_tag(h, h->nr_cmds + 1, raw_tag); -#endif -} - /* Some controllers, like p400, will give us one interrupt * after a soft reset, even if we turned interrupts off. * Only need to check for this in the hpsa_xxx_discard_completions @@ -5376,10 +5345,7 @@ static irqreturn_t do_hpsa_intr_intx(int irq, void *queue) while (interrupt_pending(h)) { raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } } @@ -5395,10 +5361,7 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *queue) h->last_intr_timestamp = get_jiffies_64(); raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } return IRQ_HANDLED; From 480c9283d90f00642bf76f6de37e58e489b2731b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:22 -0500 Subject: [PATCH 019/889] hpsa: remove direct lookup bit from command tags Now that every commmand is "direct lookup" we don't need a bit to tell us whether it is "direct lookup" Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++------------------ drivers/scsi/hpsa_cmd.h | 9 +++------ 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 266f07b8e6f6e9..448f1a7eae7e61 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3484,8 +3484,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, set_encrypt_ioaccel2(h, c, cp); cp->scsi_nexus = ioaccel_handle; - cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT; + cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; memcpy(cp->cdb, cdb, sizeof(cp->cdb)); /* fill in sg elements */ @@ -3920,9 +3919,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.tag = cpu_to_le64( - (u64) ((c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT)); + c->Header.tag = cpu_to_le64((u64) c->cmdindex << DIRECT_LOOKUP_SHIFT); /* Fill in the request block... */ @@ -4518,10 +4515,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); - c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT); - cmd_dma_handle = h->cmd_pool_dhandle - + i * sizeof(*c); + c->Header.tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); + cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(*c->err_info)); err_dma_handle = h->errinfo_pool_dhandle @@ -5239,11 +5234,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } -static inline u32 hpsa_tag_to_index(u32 tag) -{ - return tag >> DIRECT_LOOKUP_SHIFT; -} - static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) { @@ -5261,7 +5251,7 @@ static inline void process_indexed_cmd(struct ctlr_info *h, u32 tag_index; struct CommandList *c; - tag_index = hpsa_tag_to_index(raw_tag); + tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT; if (!bad_tag(h, tag_index, raw_tag)) { c = h->cmd_pool + tag_index; finish_cmd(c); @@ -7078,9 +7068,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT; cp->timeout_sec = 0; cp->ReplyQueue = 0; - cp->tag = - cpu_to_le64((u64) ((i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT)); + cp->tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); cp->host_addr = cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + (i * sizeof(struct io_accel1_cmd)))); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index a0de310622b0a4..47d484a75013ad 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -375,22 +375,19 @@ struct ErrorInfo { #define CMD_IOACCEL1 0x04 #define CMD_IOACCEL2 0x05 -#define DIRECT_LOOKUP_SHIFT 5 -#define DIRECT_LOOKUP_BIT 0x10 +#define DIRECT_LOOKUP_SHIFT 4 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) #define HPSA_ERROR_BIT 0x02 struct ctlr_info; /* defined in hpsa.h */ -/* The size of this structure needs to be divisible by 32 - * on all architectures because low 5 bits of the addresses +/* The size of this structure needs to be divisible by 128 + * on all architectures. The low 4 bits of the addresses * are used as follows: * * bit 0: to device, used to indicate "performant mode" command * from device, indidcates error status. * bit 1-3: to device, indicates block fetch table entry for * reducing DMA in fetching commands from host memory. - * bit 4: used to indicate whether tag is "direct lookup" (index), - * or a bus address. */ #define COMMANDLIST_ALIGNMENT 128 From 355b39a48df20dee75333793b8e2f9f9fb02c570 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:22 -0500 Subject: [PATCH 020/889] hpsa: fix race between abort handler and main i/o path This means changing the allocator to reference count commands. The reference count is now the authoritative indicator of whether a command is allocated or not. The h->cmd_pool_bits bitmap is now only a heuristic hint to speed up the allocation process, it is no longer the authoritative record of allocated commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 76 ++++++++++++++++++++++++----------------- drivers/scsi/hpsa.h | 2 ++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 448f1a7eae7e61..81c19acecd71d8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4398,6 +4398,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) char msg[256]; /* For debug messaging. */ int ml = 0; u32 tagupper, taglower; + int refcount; /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); @@ -4426,9 +4427,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* Get SCSI command to be aborted */ abort = (struct CommandList *) sc->host_scribble; if (abort == NULL) { - dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n", - msg); - return FAILED; + /* This can happen if the command already completed. */ + return SUCCESS; + } + refcount = atomic_inc_return(&abort->refcount); + if (refcount == 1) { /* Command is done already. */ + cmd_free(h, abort); + return SUCCESS; } hpsa_get_tag(h, abort, &taglower, &tagupper); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); @@ -4450,6 +4455,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + cmd_free(h, abort); return FAILED; } dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); @@ -4461,19 +4467,20 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ #define ABORT_COMPLETE_WAIT_SECS 30 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - if (test_bit(abort->cmdindex & (BITS_PER_LONG - 1), - h->cmd_pool_bits + - (abort->cmdindex / BITS_PER_LONG))) - msleep(100); - else + refcount = atomic_read(&abort->refcount); + if (refcount < 2) { + cmd_free(h, abort); return SUCCESS; + } else { + msleep(100); + } } dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", msg, ABORT_COMPLETE_WAIT_SECS); + cmd_free(h, abort); return FAILED; } - /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -4486,7 +4493,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - int loopcount; + int refcount; + unsigned long offset = 0; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -4499,23 +4507,27 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. */ - loopcount = 0; - do { - i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) - i = 0; - loopcount++; - } while (test_and_set_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && - loopcount < 10); - - /* Thread got starved? We do not expect this to ever happen. */ - if (loopcount >= 10 && i == h->nr_cmds) - return NULL; - - c = h->cmd_pool + i; - memset(c, 0, sizeof(*c)); - c->Header.tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); + for (;;) { + i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); + if (unlikely(i == h->nr_cmds)) { + offset = 0; + continue; + } + c = h->cmd_pool + i; + refcount = atomic_inc_return(&c->refcount); + if (unlikely(refcount > 1)) { + cmd_free(h, c); /* already in use */ + offset = (i + 1) % h->nr_cmds; + continue; + } + set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + break; /* it's ours now. */ + } + + /* Zero out all of commandlist except the last field, refcount */ + memset(c, 0, offsetof(struct CommandList, refcount)); + c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT)); cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(*c->err_info)); @@ -4535,11 +4547,13 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { - int i; + if (atomic_dec_and_test(&c->refcount)) { + int i; - i = c - h->cmd_pool; - clear_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)); + i = c - h->cmd_pool; + clear_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + } } #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 16e1f4497d3a92..3ae854868d155d 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -296,6 +296,8 @@ struct offline_device_entry { */ #define SA5_DOORBELL 0x20 #define SA5_REQUEST_PORT_OFFSET 0x40 +#define SA5_REQUEST_PORT64_LO_OFFSET 0xC0 +#define SA5_REQUEST_PORT64_HI_OFFSET 0xC4 #define SA5_REPLY_INTR_MASK_OFFSET 0x34 #define SA5_REPLY_PORT_OFFSET 0x44 #define SA5_INTR_STATUS 0x30 diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 47d484a75013ad..ee3678bbd0d71c 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -404,6 +404,7 @@ struct CommandList { long cmdindex; struct completion *waiting; void *scsi_cmd; + atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); /* Max S/G elements in I/O accelerator command */ From e9ebd63d8461bdb7b19981ce6cee9a962957d027 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:23 -0500 Subject: [PATCH 021/889] hpsa: allow lockup detector to be turned off Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/hpsa.h | 1 + 2 files changed, 40 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 81c19acecd71d8..882aa0939ee61c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -307,6 +307,38 @@ static int check_for_busy(struct ctlr_info *h, struct CommandList *c) return 1; } +static ssize_t host_store_lockup_detector(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost; + struct ctlr_info *h; + int len, enabled; + char tmpbuf[10]; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%d", &enabled) != 1) + return -EINVAL; + shost = class_to_shost(dev); + h = shost_to_hba(shost); + h->lockup_detector_enabled = !!enabled; + return count; +} + +static ssize_t host_show_lockup_detector(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); +} + static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -640,6 +672,8 @@ static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL); static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); +static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, + host_show_lockup_detector, host_store_lockup_detector); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -657,6 +691,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, + &dev_attr_lockup_detector, NULL, }; @@ -6469,6 +6504,9 @@ static void detect_controller_lockup(struct ctlr_info *h) u32 heartbeat; unsigned long flags; + if (!h->lockup_detector_enabled) + return; + now = get_jiffies_64(); /* If we've received an interrupt recently, we're ok. */ if (time_after64(h->last_intr_timestamp + @@ -6768,6 +6806,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->acciopath_status = 1; h->drv_req_rescan = 0; + h->lockup_detector_enabled = 1; /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 3ae854868d155d..5be3611ca0f87b 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -238,6 +238,7 @@ struct ctlr_info { int acciopath_status; int drv_req_rescan; /* flag for driver to request rescan event */ int raid_offload_debug; + int lockup_detector_enabled; }; struct offline_device_entry { From 582d064e7b39c4065d2fec0a987d72c414c7fdc5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:23 -0500 Subject: [PATCH 022/889] hpsa: do not request device rescan on every ioaccel path error The original reasoning behind doing this was faulty. An error of some sort would be encountered, accelerated i/o would be disabled for that logical drive, the command would be kicked back out to the SCSI midlayer for a retry, and since i/o accelerator mode was disabled, it would get retried down the RAID path. However, something needs to turn ioaccellerator mode back on, and this rescan request was what did that. However, it was racy, and extremely bad for performance to rescan all devices, so, don't do that. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 ++------------ drivers/scsi/hpsa.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 882aa0939ee61c..0435bc30251b8b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1665,21 +1665,19 @@ static void process_ioaccel2_completion(struct ctlr_info *h, c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { dev->offload_enabled = 0; - h->drv_req_rescan = 1; /* schedule controller for a rescan */ cmd->result = DID_SOFT_ERROR << 16; cmd_free(h, c); cmd->scsi_done(cmd); return; } raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2); - /* If error found, disable Smart Path, schedule a rescan, - * and force a retry on the standard path. + /* If error found, disable Smart Path, + * force a retry on the standard path. */ if (raid_retry) { dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n", "HP SSD Smart Path"); dev->offload_enabled = 0; /* Disable Smart Path */ - h->drv_req_rescan = 1; /* schedule controller rescan */ cmd->result = DID_SOFT_ERROR << 16; } cmd_free(h, c); @@ -6541,9 +6539,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) int i; char *event_type; - /* Clear the driver-requested rescan flag */ - h->drv_req_rescan = 0; - /* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) && @@ -6589,9 +6584,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) */ static int hpsa_ctlr_needs_rescan(struct ctlr_info *h) { - if (h->drv_req_rescan) - return 1; - if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return 0; @@ -6637,7 +6629,6 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { scsi_host_get(h->scsi_host); - h->drv_req_rescan = 0; hpsa_ack_ctlr_events(h); hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); @@ -6805,7 +6796,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Enable Accelerated IO path at driver layer */ h->acciopath_status = 1; - h->drv_req_rescan = 0; h->lockup_detector_enabled = 1; /* Turn the interrupts on so we can service requests */ diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 5be3611ca0f87b..a83c8ad39cdf27 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -236,7 +236,6 @@ struct ctlr_info { spinlock_t offline_device_lock; struct list_head offline_device_list; int acciopath_status; - int drv_req_rescan; /* flag for driver to request rescan event */ int raid_offload_debug; int lockup_detector_enabled; }; From ec81ffb47c20574ca81bccb9d45d9d499cc98042 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:24 -0500 Subject: [PATCH 023/889] hpsa: factor out hpsa_ciss_submit function Factor out the bottom part of the queuecommand function which is the part that builds commands for submitting down the "normal' RAID stack path of a Smart Array. Need to factor this out to improve how commands that were initially sent down one of the "ioaccellerated" paths but which have some sort of error condition are retried down the "normal" path. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 124 +++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0435bc30251b8b..f3ff255078d678 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3888,68 +3888,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -/* Running in struct Scsi_Host->host_lock less mode */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +/* Submit commands down the "normal" RAID stack path */ +static int hpsa_ciss_submit(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd, + unsigned char scsi3addr[]) { - struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; - struct CommandList *c; - int rc = 0; - - /* Get the ptr to our adapter structure out of cmd->host. */ - h = sdev_to_hba(cmd->device); - dev = cmd->device->hostdata; - if (!dev) { - cmd->result = DID_NO_CONNECT << 16; - cmd->scsi_done(cmd); - return 0; - } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - - if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return 0; - } - c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* Fill in the command list header */ - /* save c in case we have to abort it */ cmd->host_scribble = (unsigned char *) c; - c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; - - /* Call alternate submit routine for I/O accelerated commands. - * Retries always go down the normal I/O path. - */ - if (likely(cmd->retries == 0 && - cmd->request->cmd_type == REQ_TYPE_FS && - h->acciopath_status)) { - if (dev->offload_enabled) { - rc = hpsa_scsi_ioaccel_raid_map(h, c); - if (rc == 0) - return 0; /* Sent on ioaccel path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } else if (dev->ioaccel_handle) { - rc = hpsa_scsi_ioaccel_direct_map(h, c); - if (rc == 0) - return 0; /* Sent on direct map path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } - } - c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); c->Header.tag = cpu_to_le64((u64) c->cmdindex << DIRECT_LOOKUP_SHIFT); @@ -4008,6 +3954,68 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } +/* Running in struct Scsi_Host->host_lock less mode */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct ctlr_info *h; + struct hpsa_scsi_dev_t *dev; + unsigned char scsi3addr[8]; + struct CommandList *c; + int rc = 0; + + /* Get the ptr to our adapter structure out of cmd->host. */ + h = sdev_to_hba(cmd->device); + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); + + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + return 0; + } + c = cmd_alloc(h); + if (c == NULL) { /* trouble... */ + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + + /* Call alternate submit routine for I/O accelerated commands. + * Retries always go down the normal I/O path. + */ + if (likely(cmd->retries == 0 && + cmd->request->cmd_type == REQ_TYPE_FS && + h->acciopath_status)) { + + cmd->host_scribble = (unsigned char *) c; + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + + if (dev->offload_enabled) { + rc = hpsa_scsi_ioaccel_raid_map(h, c); + if (rc == 0) + return 0; /* Sent on ioaccel path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } else if (dev->ioaccel_handle) { + rc = hpsa_scsi_ioaccel_direct_map(h, c); + if (rc == 0) + return 0; /* Sent on direct map path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + } + return hpsa_ciss_submit(h, c, cmd, scsi3addr); +} + static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) { unsigned long flags; From 2fc2aeb31f56a055f731fef8691d925c3f450bd9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:24 -0500 Subject: [PATCH 024/889] hpsa: use workqueue to resubmit failed ioaccel commands Instead of kicking the commands all the way back to the mid layer, use a work queue. This enables having a mechanism for the driver to be able to resubmit the commands down the "normal" raid path without turning off the ioaccel feature entirely whenever an error is encountered on the ioaccel path, and prevent excessive rescanning of devices. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 60 ++++++++++++++++++++++++++++------------- drivers/scsi/hpsa_cmd.h | 1 + 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f3ff255078d678..f622062b74bb73 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -245,6 +245,7 @@ static void hpsa_flush_cache(struct ctlr_info *h); static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, u8 *scsi3addr); +static void hpsa_command_resubmit_worker(struct work_struct *work); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -1647,7 +1648,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev) { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - int raid_retry = 0; /* check for good status */ if (likely(c2->error_data.serv_response == 0 && @@ -1664,24 +1664,22 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (is_logical_dev_addr_mode(dev->scsi3addr) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { - dev->offload_enabled = 0; - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - } - raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2); - /* If error found, disable Smart Path, - * force a retry on the standard path. - */ - if (raid_retry) { - dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n", - "HP SSD Smart Path"); - dev->offload_enabled = 0; /* Disable Smart Path */ - cmd->result = DID_SOFT_ERROR << 16; + if (c2->error_data.status == + IOACCEL2_STATUS_SR_IOACCEL_DISABLED) + dev->offload_enabled = 0; + goto retry_cmd; } + + if (handle_ioaccel_mode2_error(h, c, cmd, c2)) + goto retry_cmd; + cmd_free(h, c); cmd->scsi_done(cmd); + return; + +retry_cmd: + INIT_WORK(&c->work, hpsa_command_resubmit_worker); + schedule_work_on(raw_smp_processor_id(), &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1749,9 +1747,8 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, cp); - cmd->scsi_done(cmd); + INIT_WORK(&cp->work, hpsa_command_resubmit_worker); + schedule_work_on(raw_smp_processor_id(), &cp->work); return; } } @@ -3954,6 +3951,31 @@ static int hpsa_ciss_submit(struct ctlr_info *h, return 0; } +static void hpsa_command_resubmit_worker(struct work_struct *work) +{ + struct scsi_cmnd *cmd; + struct hpsa_scsi_dev_t *dev; + struct CommandList *c = + container_of(work, struct CommandList, work); + + cmd = c->scsi_cmd; + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return; + } + if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + /* + * If we get here, it means dma mapping failed. Try + * again via scsi mid layer, which will then get + * SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } +} + /* Running in struct Scsi_Host->host_lock less mode */ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index ee3678bbd0d71c..0ccb35d215a6b2 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -404,6 +404,7 @@ struct CommandList { long cmdindex; struct completion *waiting; void *scsi_cmd; + struct work_struct work; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 6ee2f3f3ab7acf588ed1b04b8e9693361bb2a832 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:25 -0500 Subject: [PATCH 025/889] hpsa: use driver instead of system work queue for command resubmission There is a possibility of deadlock if we use the system work queue for command resubmission since something in the queue may be depending on the i/o that gets resubmitted, and the resubmitted i/o will be behind the thing that depends on it in the queue. Using a driver specific work queue avoids this. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f622062b74bb73..c98508855af0f2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -190,6 +190,7 @@ static struct board_type products[] = { }; static int number_of_controllers; +static struct workqueue_struct *hpsa_wq; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); @@ -1679,7 +1680,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, retry_cmd: INIT_WORK(&c->work, hpsa_command_resubmit_worker); - schedule_work_on(raw_smp_processor_id(), &c->work); + queue_work_on(raw_smp_processor_id(), hpsa_wq, &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1748,7 +1749,8 @@ static void complete_scsi_command(struct CommandList *cp) if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; INIT_WORK(&cp->work, hpsa_command_resubmit_worker); - schedule_work_on(raw_smp_processor_id(), &cp->work); + queue_work_on(raw_smp_processor_id(), + hpsa_wq, &cp->work); return; } } @@ -7339,12 +7341,19 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) */ static int __init hpsa_init(void) { + hpsa_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!hpsa_wq) { + pr_warn(HPSA "Failed to allocate work queue\n"); + return -ENOMEM; + } return pci_register_driver(&hpsa_pci_driver); } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); + if (hpsa_wq) + destroy_workqueue(hpsa_wq); } static void __attribute__((unused)) verify_offsets(void) From 68ecb3f26fd5fe841bd1802a3a050a3d34d8d34a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:26 -0500 Subject: [PATCH 026/889] hpsa: optimize cmd_alloc function by remembering last allocation Empirically, this improves performance slightly (~2% max IOPS) by allowing cmd_alloc to remember where it left off searching for free commands between calls instead of always starting its search at command 0. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +++- drivers/scsi/hpsa.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c98508855af0f2..7a45b3bbc9b43a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4559,7 +4559,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; int refcount; - unsigned long offset = 0; + unsigned long offset; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -4572,6 +4572,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. */ + offset = h->last_allocation; /* benighly racy */ for (;;) { i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); if (unlikely(i == h->nr_cmds)) { @@ -4589,6 +4590,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) h->cmd_pool_bits + (i / BITS_PER_LONG)); break; /* it's ours now. */ } + h->last_allocation = i; /* benignly racy */ /* Zero out all of commandlist except the last field, refcount */ memset(c, 0, offsetof(struct CommandList, refcount)); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index a83c8ad39cdf27..b8664b386b5b1f 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -120,6 +120,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_allocation; atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 From 73bd83595d4113439802bd74d754c9675cbd7d81 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:26 -0500 Subject: [PATCH 027/889] hpsa: Count passthru cmds with atomics, not a spin locked int Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 39 +++++---------------------------------- drivers/scsi/hpsa.h | 3 +-- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7a45b3bbc9b43a..cc1b9c0aa56513 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5010,35 +5010,6 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, (void) check_for_unit_attention(h, c); } -static int increment_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return -1; - } - h->passthru_count++; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return 0; -} - -static void decrement_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count <= 0) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - /* not expecting to get here. */ - dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n"); - return; - } - h->passthru_count--; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); -} - /* * ioctl */ @@ -5061,16 +5032,16 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) case CCISS_GETDRIVVER: return hpsa_getdrivver_ioctl(h, argp); case CCISS_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; case CCISS_BIG_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_big_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; default: return -ENOTTY; @@ -6718,7 +6689,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->lock); spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); - spin_lock_init(&h->passthru_count_lock); + atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index b8664b386b5b1f..d95497c6c0b512 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -170,8 +170,7 @@ struct ctlr_info { /* cap concurrent passthrus at some reasonable maximum */ #define HPSA_MAX_CONCURRENT_PASSTHRUS (10) - spinlock_t passthru_count_lock; /* protects passthru_count */ - int passthru_count; + atomic_t passthru_cmds_avail; /* * Performant mode completion buffers From 540072633d81030eb586a5ea9c13b713f6f775e8 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:27 -0500 Subject: [PATCH 028/889] hpsa: remove unused fifo_full function Now that the passthru commands share the same command pool as the main i/o path, and the total size of the pool is less than or equal to the number of commands that will fit in the hardware fifo, there is no need to check to see if we are exceeding the hardware fifo's depth. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index d95497c6c0b512..7523d21b4d02b4 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -32,7 +32,6 @@ struct access_method { void (*submit_command)(struct ctlr_info *h, struct CommandList *c); void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); - unsigned long (*fifo_full)(struct ctlr_info *h); bool (*intr_pending)(struct ctlr_info *h); unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; @@ -426,14 +425,6 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) return register_value; } -/* - * Returns true if fifo is full. - * - */ -static unsigned long SA5_fifo_full(struct ctlr_info *h) -{ - return atomic_read(&h->commands_outstanding) >= h->max_commands; -} /* * returns value read from hardware. * returns FIFO_EMPTY if there is nothing to read @@ -526,7 +517,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) static struct access_method SA5_access = { SA5_submit_command, SA5_intr_mask, - SA5_fifo_full, SA5_intr_pending, SA5_completed, }; @@ -534,7 +524,6 @@ static struct access_method SA5_access = { static struct access_method SA5_ioaccel_mode1_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_ioaccel_mode1_intr_pending, SA5_ioaccel_mode1_completed, }; @@ -542,7 +531,6 @@ static struct access_method SA5_ioaccel_mode1_access = { static struct access_method SA5_ioaccel_mode2_access = { SA5_submit_command_ioaccel2, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -550,7 +538,6 @@ static struct access_method SA5_ioaccel_mode2_access = { static struct access_method SA5_performant_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -558,7 +545,6 @@ static struct access_method SA5_performant_access = { static struct access_method SA5_performant_access_no_read = { SA5_submit_command_no_read, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; From e1cf11ae2b287ad5f88cf063a31f81eab805b362 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:27 -0500 Subject: [PATCH 029/889] hpsa: slightly optimize SA5_performant_completed Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7523d21b4d02b4..1fa19461b65661 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -398,19 +398,19 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) unsigned long register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ - if (!(h->msi_vector || h->msix_vector)) { + if (unlikely(!(h->msi_vector || h->msix_vector))) { /* flush the controller write of the reply queue by reading * outbound doorbell status register. */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); /* Do a read in order to flush the write to the controller * (as per spec.) */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); } - if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { + if ((((u32) rq->head[rq->current_entry]) & 1) == rq->wraparound) { register_value = rq->head[rq->current_entry]; rq->current_entry++; atomic_dec(&h->commands_outstanding); From 36f252c53a533c3aad6ce7119246a7f26ecaa35b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:28 -0500 Subject: [PATCH 030/889] hpsa: do not check for msi(x) in interrupt_pending No need to check whether interrupt pending for MSI(X) and conversely, no need to check whether MSI(X) interrupts are being used when checking if interrupts are pending. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1fa19461b65661..67439795bf8b50 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -465,9 +465,6 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h) if (!register_value) return false; - if (h->msi_vector || h->msix_vector) - return true; - /* Read outbound doorbell to flush */ register_value = readl(h->vaddr + SA5_OUTDB_STATUS); return register_value & SA5_OUTDB_STATUS_PERF_BIT; From e2cd2582e1558ff2c448d8ded97712c0d31c294d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:28 -0500 Subject: [PATCH 031/889] hpsa: fix fail_all_outstanding_cmds to use reference counting Since we changed the command allocator to use reference counting as the authoritative indicator of whether a command is allocated, fail_all_outstanding_cmds needs to use the reference count not h->cmd_pool_bits for this purpose. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cc1b9c0aa56513..070f8dfb6bd420 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6450,16 +6450,17 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) /* Called when controller lockup detected. */ static void fail_all_outstanding_cmds(struct ctlr_info *h) { - int i; - struct CommandList *c = NULL; + int i, refcount; + struct CommandList *c; for (i = 0; i < h->nr_cmds; i++) { - if (!test_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG))) - continue; c = h->cmd_pool + i; - c->err_info->CommandStatus = CMD_HARDWARE_ERR; - finish_cmd(c); + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) { + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + finish_cmd(c); + } + cmd_free(h, c); } } @@ -6496,9 +6497,7 @@ static void controller_lockup_detected(struct ctlr_info *h) dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", lockup_detected); pci_disable_device(h->pdev); - spin_lock_irqsave(&h->lock, flags); fail_all_outstanding_cmds(h); - spin_unlock_irqrestore(&h->lock, flags); } static void detect_controller_lockup(struct ctlr_info *h) From b8f33d703e102b418793c1ddb749b5de43996656 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:29 -0500 Subject: [PATCH 032/889] hpsa: do not use function pointers in fast path command submission Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 +++++--- drivers/scsi/hpsa.h | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 070f8dfb6bd420..bb4b2e9caed29a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -854,19 +854,21 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { + dial_down_lockup_detection_during_fw_flash(h, c); + atomic_inc(&h->commands_outstanding); switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); break; case CMD_IOACCEL2: set_ioaccel2_performant_mode(h, c); + writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; default: set_performant_mode(h, c); + h->access.submit_command(h, c); } - dial_down_lockup_detection_during_fw_flash(h, c); - atomic_inc(&h->commands_outstanding); - h->access.submit_command(h, c); } static inline int is_hba_lunid(unsigned char scsi3addr[]) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 67439795bf8b50..2b5704f21cd45c 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -353,10 +353,7 @@ static void SA5_submit_command_no_read(struct ctlr_info *h, static void SA5_submit_command_ioaccel2(struct ctlr_info *h, struct CommandList *c) { - if (c->cmd_type == CMD_IOACCEL2) - writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); - else - writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); } /* From 2e0a929f833aa62ea3853f7602eba64f11d76f7d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:30 -0500 Subject: [PATCH 033/889] hpsa: do not wait for aborted commands to complete after abort After an abort command completes successfully there is no need or sense in trying to wait for the aborted command to complete. It will have already completed (either normally, or as aborted) before the abort command completes. Trying to wait for it to complete later doesn't make sense -- it would only be waiting for the command to be re-used for something else and for *that* to complete, which would be crazy. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bb4b2e9caed29a..218371a977a095 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4457,7 +4457,7 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) { - int i, rc; + int rc; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; struct CommandList *abort; /* pointer to command to be aborted */ @@ -4526,26 +4526,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); - - /* If the abort(s) above completed and actually aborted the - * command, then the command to be aborted should already be - * completed. If not, wait around a bit more to see if they - * manage to complete normally. - */ -#define ABORT_COMPLETE_WAIT_SECS 30 - for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - refcount = atomic_read(&abort->refcount); - if (refcount < 2) { - cmd_free(h, abort); - return SUCCESS; - } else { - msleep(100); - } - } - dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", - msg, ABORT_COMPLETE_WAIT_SECS); cmd_free(h, abort); - return FAILED; + return SUCCESS; } /* From 98a6e2dd0d38d755206a9bd2e6d15670cabcc50e Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:30 -0500 Subject: [PATCH 034/889] hpsa: allow interrupt coalescing count and time to be adjusted in sysfs Note: Rob says that empirically, default values appear to be optimal, so it is not clear that allowing this to be adjusted is wise. We may wish to drop this patch. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 88 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 218371a977a095..6dc38509d1a6ec 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -247,6 +247,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, u8 *scsi3addr); static void hpsa_command_resubmit_worker(struct work_struct *work); +static void print_cfg_table(struct device *dev, struct CfgTable *tb); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -401,6 +402,85 @@ static ssize_t host_store_rescan(struct device *dev, return count; } +static ssize_t host_store_hpsa_intcoal_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int len; + unsigned int value; + char tmpbuf[8]; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%u", &value) != 1) + return -EINVAL; + /* the device policies the values written, so no need here */ + + h = shost_to_hba(shost); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(value, &h->cfgtable->HostWrite.CoalIntDelay); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); + return count; +} + +static ssize_t host_store_hpsa_intcoal_count(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int len; + unsigned int value; + char tmpbuf[8]; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%u", &value) != 1) + return -EINVAL; + /* the device policies the values written, so no need here */ + + h = shost_to_hba(shost); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(value, &h->cfgtable->HostWrite.CoalIntCount); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); + return count; +} + +static ssize_t host_show_hpsa_intcoal_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int value; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + value = readl(&h->cfgtable->HostWrite.CoalIntDelay); + return snprintf(buf, 20, "%u\n", value); +} + +static ssize_t host_show_hpsa_intcoal_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int value; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + value = readl(&h->cfgtable->HostWrite.CoalIntCount); + return snprintf(buf, 20, "%u\n", value); +} + + static ssize_t host_show_firmware_revision(struct device *dev, struct device_attribute *attr, char *buf) { @@ -659,6 +739,8 @@ static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL); static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static DEVICE_ATTR(hpsa_intcoal_delay, S_IWUSR|S_IRUGO, host_show_hpsa_intcoal_delay, host_store_hpsa_intcoal_delay); +static DEVICE_ATTR(hpsa_intcoal_count, S_IWUSR|S_IRUGO, host_show_hpsa_intcoal_count, host_store_hpsa_intcoal_count); static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO, host_show_hp_ssd_smart_path_enabled, NULL); static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH, @@ -690,6 +772,8 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_firmware_revision, &dev_attr_commands_outstanding, &dev_attr_transport_mode, + &dev_attr_hpsa_intcoal_delay, + &dev_attr_hpsa_intcoal_count, &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, @@ -5732,7 +5816,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) */ static void print_cfg_table(struct device *dev, struct CfgTable *tb) { -#ifdef HPSA_DEBUG int i; char temp_name[17]; @@ -5762,7 +5845,6 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb) dev_info(dev, " Server Name = %s\n", temp_name); dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat))); -#endif /* HPSA_DEBUG */ } static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) @@ -7054,6 +7136,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_warn(&h->pdev->dev, "unable to get board into" @@ -7129,6 +7212,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) From 3eeff3fe95e66dcf610a9a0ff8b9033c32f82565 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:31 -0500 Subject: [PATCH 035/889] hpsa: fix hpsa_drain_accel_commands to use reference counting instead of bitmap Fix hpsa_drain_accel_commands to use the reference count as the authoritative indicator of whether a command is allocated instead of the h->cmd_pool_bits bitmap. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6dc38509d1a6ec..ecea9334377847 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7359,18 +7359,19 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) { struct CommandList *c = NULL; int i, accel_cmds_out; + int refcount; do { /* wait for all outstanding ioaccel commands to drain out */ accel_cmds_out = 0; for (i = 0; i < h->nr_cmds; i++) { - if (!test_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG))) - continue; c = h->cmd_pool + i; - accel_cmds_out += is_accelerated_cmd(c); + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) /* Command is allocated */ + accel_cmds_out += is_accelerated_cmd(c); + cmd_free(h, c); } if (accel_cmds_out <= 0) - break; + break; msleep(100); } while (1); } From 4b9b887d9ebc942a5e08edfcb60ada793896fed2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:31 -0500 Subject: [PATCH 036/889] hpsa: fix race when updating raid map data. When enabling io accelerator paths for a logical drive make sure to update the raid map data prior to setting the ioaccel_enabled flag for that logical drive, and when disabling ioaccelerator path for a logical drive, do not update the raid map data at all. One of the reasons that the ioaccel_enabled flag might not be set is because getting the raid map data failed, in which case, updating the raid map data is certainly the wrong thing to do. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ecea9334377847..eab471bc00a0f1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1084,12 +1084,22 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, /* Raid level changed. */ h->dev[entry]->raid_level = new_entry->raid_level; - /* Raid offload parameters changed. */ + /* Raid offload parameters changed. Careful about the ordering. */ + if (new_entry->offload_config && new_entry->offload_enabled) { + /* if drive is newly offload_enabled, we want to copy the + * raid map data first. If previously offload_enabled and + * offload_config were set, raid map data had better be + * the same as it was before. if raid map data is changed + * then it had better be the case that + * h->dev[entry]->offload_enabled is currently 0. + */ + h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; + wmb(); /* ensure raid map updated prior to ->offload_enabled */ + } h->dev[entry]->offload_config = new_entry->offload_config; - h->dev[entry]->offload_enabled = new_entry->offload_enabled; - h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; - h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->offload_enabled = new_entry->offload_enabled; dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", scsi_device_type(new_entry->devtype), hostno, new_entry->bus, From c148b6cd972923365de51d6d1795e78b9e75539c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:32 -0500 Subject: [PATCH 037/889] hpsa: allow commands to be completed on specified reply queue This is to enable fixing a race between command completions and abort completions on different reply queues in a subsequent patch. We want to be able to specify which reply queue an abort completion should occur on so that it cannot race the completion of the command it is trying to abort. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 54 +++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index eab471bc00a0f1..78937d9fbc77cb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -861,25 +861,35 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) * set bit 0 for pull model, bits 3-1 for block fetch * register number */ -static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) +#define DEFAULT_REPLY_QUEUE (-1) +static void set_performant_mode(struct ctlr_info *h, struct CommandList *c, + int reply_queue) { if (likely(h->transMethod & CFGTBL_Trans_Performant)) { c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); - if (likely(h->msix_vector > 0)) + if (unlikely(!h->msix_vector)) + return; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) c->Header.ReplyQueue = raw_smp_processor_id() % h->nreply_queues; + else + c->Header.ReplyQueue = reply_queue % h->nreply_queues; } } static void set_ioaccel1_performant_mode(struct ctlr_info *h, - struct CommandList *c) + struct CommandList *c, + int reply_queue) { struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex]; /* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - cp->ReplyQueue = smp_processor_id() % h->nreply_queues; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->ReplyQueue = smp_processor_id() % h->nreply_queues; + else + cp->ReplyQueue = reply_queue % h->nreply_queues; /* Set the bits in the address sent down to include: * - performant mode bit (bit 0) * - pull count (bits 1-3) @@ -890,14 +900,18 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h, } static void set_ioaccel2_performant_mode(struct ctlr_info *h, - struct CommandList *c) + struct CommandList *c, + int reply_queue) { struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex]; /* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - cp->reply_queue = smp_processor_id() % h->nreply_queues; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->reply_queue = smp_processor_id() % h->nreply_queues; + else + cp->reply_queue = reply_queue % h->nreply_queues; /* Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 * - pull count (bits 0-3) @@ -935,26 +949,32 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; } -static void enqueue_cmd_and_start_io(struct ctlr_info *h, - struct CommandList *c) +static void __enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c, int reply_queue) { dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); switch (c->cmd_type) { case CMD_IOACCEL1: - set_ioaccel1_performant_mode(h, c); + set_ioaccel1_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); break; case CMD_IOACCEL2: - set_ioaccel2_performant_mode(h, c); + set_ioaccel2_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; default: - set_performant_mode(h, c); + set_performant_mode(h, c, reply_queue); h->access.submit_command(h, c); } } +static void enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c) +{ + __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); +} + static inline int is_hba_lunid(unsigned char scsi3addr[]) { return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0; @@ -2011,16 +2031,22 @@ static int hpsa_map_one(struct pci_dev *pdev, return 0; } -static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c) +static inline void __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, int reply_queue) { DECLARE_COMPLETION_ONSTACK(wait); c->waiting = &wait; - enqueue_cmd_and_start_io(h, c); + __enqueue_cmd_and_start_io(h, c, reply_queue); wait_for_completion(&wait); } +static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c) +{ + __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE); +} + static u32 lockup_detected(struct ctlr_info *h) { int cpu; From 7e9184ae58afcd0b195a2ea5c95ffc1aad7a7afb Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:32 -0500 Subject: [PATCH 038/889] hpsa: fix completion race in abort handler The following race was possible in theory: 1. Abort command is sent to hardware. 2. Command to be aborted simultaneously completes on another reply queue. 3. Hardware receives abort command, decides command has already completed and indicates this to the driver via another different reply queue. 4. driver processes abort completion finds that the hardware does not know about the command, concludes that therefore the command cannot complete, returns SUCCESS indicating to the mid-layer that the scsi_cmnd may be re-used. 5. Command from step 2 is processed and completed back to scsi mid layer (after we already promised that would never happen.) Fix by forcing aborts to complete on the same reply queue as the command they are aborting. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 78937d9fbc77cb..046754d5617494 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4428,7 +4428,7 @@ static void hpsa_get_tag(struct ctlr_info *h, } static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, - struct CommandList *abort, int swizzle) + struct CommandList *abort, int swizzle, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -4446,7 +4446,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); - hpsa_scsi_do_simple_cmd_core(h, c); + __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", __func__, tagupper, taglower); @@ -4480,7 +4480,8 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, */ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort) + unsigned char *scsi3addr, struct CommandList *abort, + __attribute__((unused)) int reply_queue) { int rc = IO_OK; struct scsi_cmnd *scmd; /* scsi command within request being aborted */ @@ -4556,7 +4557,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, * make this true someday become false. */ static int hpsa_send_abort_both_ways(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort) + unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, @@ -4564,10 +4565,20 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, * Change abort to physical device reset. */ if (abort->cmd_type == CMD_IOACCEL2) - return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort); + return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, + abort, reply_queue); + + return hpsa_send_abort(h, scsi3addr, abort, 0, reply_queue) && + hpsa_send_abort(h, scsi3addr, abort, 1, reply_queue); +} - return hpsa_send_abort(h, scsi3addr, abort, 0) && - hpsa_send_abort(h, scsi3addr, abort, 1); +/* Find out which reply queue a command was meant to return on */ +static int hpsa_extract_reply_queue(struct ctlr_info *h, + struct CommandList *c) +{ + if (c->cmd_type == CMD_IOACCEL2) + return h->ioaccel2_cmd_pool[c->cmdindex].reply_queue; + return c->Header.ReplyQueue; } /* Send an abort for the specified command. @@ -4585,7 +4596,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) char msg[256]; /* For debug messaging. */ int ml = 0; u32 tagupper, taglower; - int refcount; + int refcount, reply_queue; /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); @@ -4623,6 +4634,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } hpsa_get_tag(h, abort, &taglower, &tagupper); + reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); as = (struct scsi_cmnd *) abort->scsi_cmd; if (as != NULL) @@ -4636,7 +4648,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * by the firmware (but not to the scsi mid layer) but we can't * distinguish which. Send the abort down. */ - rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort); + rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); if (rc != 0) { dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", From 17dc9b9b635fd816e5c0bdcd16df7d279add3c58 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:33 -0500 Subject: [PATCH 039/889] hpsa: fix aborting of reused commands The following race was possible in theory. 1. LLD is requested to abort a scsi command 2. scsi command completes 3. The struct CommandList associated with 2 is made available. 4. new io request to LLD to another LUN re-uses struct CommandList 5. abort handler follows scsi_cmnd->host_scribble and finds struct CommandList and tries to aborts it. Now we have aborted the wrong command. Fix by zeroing the scsi_cmd field of struct CommandList upon completion and making the abort handler check that the scsi_cmd pointer in the CommadList struct matches the scsi_cmnd that it has been asked to abort. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 046754d5617494..6270d2864e2ed9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1987,6 +1987,21 @@ static void complete_scsi_command(struct CommandList *cp) dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n", cp, ei->CommandStatus); } + + /* Prevent the following race in the abort handler: + * + * 1. LLD is requested to abort a scsi command + * 2. scsi command completes + * 3. The struct CommandList associated with 2 is made available. + * 4. new io request to LLD to another LUN re-uses struct CommandList + * 5. abort handler follows scsi_cmnd->host_scribble and + * finds struct CommandList and tries to aborts it. + * Now we have aborted the wrong command. + * Clear cp->scsi_cmd here so that if this get re-used, the abort + * handler will know it's a different scsi_cmnd. + */ + cp->scsi_cmd = NULL; + cmd_free(h, cp); cmd->scsi_done(cmd); } @@ -4633,6 +4648,15 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return SUCCESS; } + + /* Check that we're aborting the right command. + * It's possible the CommandList already completed and got re-used. + */ + if (abort->scsi_cmd != sc) { + cmd_free(h, abort); + return SUCCESS; + } + hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); From e37796d0b8fd286f1632e05dc8501f148036511e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:34 -0500 Subject: [PATCH 040/889] hpsa: lay groundwork for handling driver initiated command timeouts Allow driver initiated commands to have a timeout. It does not yet try to do anything with timeouts on such commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 118 ++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6270d2864e2ed9..225caa1c425a92 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2046,20 +2046,33 @@ static int hpsa_map_one(struct pci_dev *pdev, return 0; } -static inline void __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c, int reply_queue) +#define NO_TIMEOUT ((unsigned long) -1) +#define DEFAULT_TIMEOUT (30000) /* milliseconds */ +static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, int reply_queue, unsigned long timeout_msecs) { DECLARE_COMPLETION_ONSTACK(wait); c->waiting = &wait; __enqueue_cmd_and_start_io(h, c, reply_queue); - wait_for_completion(&wait); + if (timeout_msecs == NO_TIMEOUT) { + /* TODO: get rid of this no-timeout thing */ + wait_for_completion_io(&wait); + return 0; + } + if (!wait_for_completion_io_timeout(&wait, + msecs_to_jiffies(timeout_msecs))) { + dev_warn(&h->pdev->dev, "Command timed out.\n"); + return -ETIMEDOUT; + } + return 0; } -static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c) +static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, unsigned long timeout_msecs) { - __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE); + return __hpsa_scsi_do_simple_cmd_core(h, c, + DEFAULT_REPLY_QUEUE, timeout_msecs); } static u32 lockup_detected(struct ctlr_info *h) @@ -2074,25 +2087,29 @@ static u32 lockup_detected(struct ctlr_info *h) return rc; } -static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, - struct CommandList *c) +static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, + struct CommandList *c, unsigned long timeout_msecs) { /* If controller lockup detected, fake a hardware error. */ - if (unlikely(lockup_detected(h))) + if (unlikely(lockup_detected(h))) { c->err_info->CommandStatus = CMD_HARDWARE_ERR; - else - hpsa_scsi_do_simple_cmd_core(h, c); + return 0; + } + return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); } #define MAX_DRIVER_CMD_RETRIES 25 -static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, - struct CommandList *c, int data_direction) +static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, + struct CommandList *c, int data_direction, unsigned long timeout_msecs) { int backoff_time = 10, retry_count = 0; + int rc; do { memset(c->err_info, 0, sizeof(*c->err_info)); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); + if (rc) + break; retry_count++; if (retry_count > 3) { msleep(backoff_time); @@ -2103,6 +2120,9 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, check_for_busy(h, c)) && retry_count <= MAX_DRIVER_CMD_RETRIES); hpsa_pci_unmap(h->pdev, c, 1, data_direction); + if (retry_count > MAX_DRIVER_CMD_RETRIES) + rc = -1; /* FIXME do something better? */ + return rc; } static void hpsa_print_cmd(struct ctlr_info *h, char *txt, @@ -2206,7 +2226,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); @@ -2237,7 +2260,10 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, rc = -1; goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); @@ -2265,7 +2291,11 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) { + dev_warn(&h->pdev->dev, "Failed to send reset command\n"); + goto out; + } /* no unmap needed here because no data xfer. */ ei = c->err_info; @@ -2273,6 +2303,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, hpsa_scsi_interpret_error(h, c); rc = -1; } +out: cmd_free(h, c); return rc; } @@ -2392,15 +2423,18 @@ static int hpsa_get_raid_map(struct ctlr_info *h, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - cmd_free(h, c); - return -ENOMEM; + rc = -ENOMEM; + goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); - cmd_free(h, c); - return -1; + rc = -1; + goto out; } cmd_free(h, c); @@ -2412,6 +2446,9 @@ static int hpsa_get_raid_map(struct ctlr_info *h, } hpsa_debug_map_buff(h, rc, &this_device->raid_map); return rc; +out: + cmd_free(h, c); + return rc; } static int hpsa_vpd_page_supported(struct ctlr_info *h, @@ -2536,7 +2573,10 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } if (extended_response) c->Request.CDB[1] = extended_response; - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { @@ -2627,7 +2667,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, { struct CommandList *c; unsigned char *sense, sense_key, asc, ascq; - int ldstat = 0; + int rc, ldstat = 0; u16 cmd_status; u8 scsi_status; #define ASC_LUN_NOT_READY 0x04 @@ -2638,7 +2678,11 @@ static int hpsa_volume_offline(struct ctlr_info *h, if (!c) return 0; (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) { + cmd_free(h, c); + return 0; + } sense = c->err_info->SenseInfo; sense_key = sense[2]; asc = sense[12]; @@ -4349,7 +4393,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) + goto do_it_again; /* no unmap needed here because no data xfer. */ if (c->err_info->CommandStatus == CMD_SUCCESS) @@ -4360,7 +4406,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, (c->err_info->SenseInfo[2] == NO_SENSE || c->err_info->SenseInfo[2] == UNIT_ATTENTION)) break; - +do_it_again: dev_warn(&h->pdev->dev, "waiting %d secs " "for device to become ready.\n", waittime); rc = 1; /* device not ready. */ @@ -4461,7 +4507,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); - __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue); + (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", __func__, tagupper, taglower); @@ -4976,7 +5022,9 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); + rc = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + if (rc) + rc = -EIO; if (iocommand.buf_size > 0) hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -5107,7 +5155,11 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); + status = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + if (status) { + status = -EIO; + goto cleanup0; + } if (sg_used) hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -6969,6 +7021,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) { char *flush_buf; struct CommandList *c; + int rc; /* Don't bother trying to flush the cache if locked up */ if (unlikely(lockup_detected(h))) @@ -6986,7 +7039,10 @@ static void hpsa_flush_cache(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) { goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_TODEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_TODEVICE, NO_TIMEOUT); + if (rc) + goto out; if (c->err_info->CommandStatus != 0) out: dev_warn(&h->pdev->dev, From 2d01fdb79ed5ae1ac024ff98ca1e2fa50dc21f3c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:34 -0500 Subject: [PATCH 041/889] hpsa: do not send aborts to logical devices that do not support aborts Instead of relying on what the Smart Array claims for supporting logical drives, simply try an abort and see how it responds at device discovery time. This way devices that do support aborts (e.g. MSA2000) can work and we do not waste time trying to send aborts to logical drives that do not support them (important for high IOPS devices.) Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 67 ++++++++++++++++++++++++++++++++++++++++----- drivers/scsi/hpsa.h | 2 +- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 225caa1c425a92..bad6f057cd0ae7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2726,6 +2726,49 @@ static int hpsa_volume_offline(struct ctlr_info *h, return 0; } +/* Find out if a logical device supports aborts by simply trying one. + * Smart Array may claim not to support aborts on logical drives, but + * if a MSA2000 * is connected, the drives on that will be presented + * by the Smart Array as logical drives, and aborts may be sent to + * those devices successfully. So the simplest way to find out is + * to simply try an abort and see how the device responds. + */ +static int hpsa_device_supports_aborts(struct ctlr_info *h, + unsigned char *scsi3addr) +{ + struct CommandList *c; + struct ErrorInfo *ei; + int rc = 0; + + u64 tag = (u64) -1; /* bogus tag */ + + /* Assume that physical devices support aborts */ + if (!is_logical_dev_addr_mode(scsi3addr)) + return 1; + + c = cmd_alloc(h); + if (!c) + return -ENOMEM; + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); + (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); + /* no unmap needed here because no data xfer. */ + ei = c->err_info; + switch (ei->CommandStatus) { + case CMD_INVALID: + rc = 0; + break; + case CMD_UNABORTABLE: + case CMD_ABORT_FAILED: + rc = 1; + break; + default: + rc = 0; + break; + } + cmd_free(h, c); + return rc; +} + static int hpsa_update_device_info(struct ctlr_info *h, unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, unsigned char *is_OBDR_device) @@ -2790,8 +2833,11 @@ static int hpsa_update_device_info(struct ctlr_info *h, strncmp(obdr_sig, OBDR_TAPE_SIG, OBDR_SIG_LEN) == 0); } - kfree(inq_buff); + this_device->supports_aborts = + hpsa_device_supports_aborts(h, scsi3addr); + if (this_device->supports_aborts < 0) + this_device->supports_aborts = 0; return 0; bail_out: @@ -4503,7 +4549,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, } /* fill_cmd can't fail here, no buffer to map */ - (void) fill_cmd(c, HPSA_ABORT_MSG, h, abort, + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); @@ -4695,6 +4741,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } + /* Don't bother trying the abort if we know it won't work. */ + if (abort->cmd_type != CMD_IOACCEL2 && + abort->cmd_type != CMD_IOACCEL1 && !dev->supports_aborts) { + cmd_free(h, abort); + return FAILED; + } + /* Check that we're aborting the right command. * It's possible the CommandList already completed and got re-used. */ @@ -5266,7 +5319,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, int cmd_type) { int pci_dir = XFER_NONE; - struct CommandList *a; /* for commands to be aborted */ + u64 tag; /* for commands to be aborted */ u32 tupper, tlower; c->cmd_type = CMD_IOCTL_PEND; @@ -5373,11 +5426,11 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = 0x00; break; case HPSA_ABORT_MSG: - a = buff; /* point to command to be aborted */ + memcpy(&tag, buff, sizeof(tag)); dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx", - a->Header.tag, c->Header.tag); - tlower = (u32) (a->Header.tag >> 32); - tupper = (u32) (a->Header.tag & 0x0ffffffffULL); + tag, c->Header.tag); + tlower = (u32) (tag >> 32); + tupper = (u32) (tag & 0x0ffffffffULL); c->Request.CDBLen = 16; c->Request.type_attr_dir = TYPE_ATTR_DIR(cmd_type, diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 2b5704f21cd45c..03a28dc6e54337 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -53,7 +53,7 @@ struct hpsa_scsi_dev_t { * offload request to mirror drive */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ - + int supports_aborts; }; struct reply_queue_buffer { From c89b5a2d8b9f8002cea8cd1d39524366dd0af0d1 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:35 -0500 Subject: [PATCH 042/889] hpsa: remember whether devices support aborts across rescans While rescanning devices only test whether devices support aborts the first time we encounter a device rather than every time. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bad6f057cd0ae7..a98b8e69016804 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2781,6 +2781,8 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; + unsigned long flags; + int rc, entry; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) @@ -2834,10 +2836,25 @@ static int hpsa_update_device_info(struct ctlr_info *h, OBDR_SIG_LEN) == 0); } kfree(inq_buff); - this_device->supports_aborts = - hpsa_device_supports_aborts(h, scsi3addr); - if (this_device->supports_aborts < 0) - this_device->supports_aborts = 0; + + /* + * See if this device supports aborts. If we already know + * the device, we already know if it supports aborts, otherwise + * we have to find out if it supports aborts by trying one. + */ + spin_lock_irqsave(&h->devlock, flags); + rc = hpsa_scsi_find_entry(this_device, h->dev, h->ndevices, &entry); + if ((rc == DEVICE_SAME || rc == DEVICE_UPDATED) && + entry >= 0 && entry < h->ndevices) { + this_device->supports_aborts = h->dev[entry]->supports_aborts; + spin_unlock_irqrestore(&h->devlock, flags); + } else { + spin_unlock_irqrestore(&h->devlock, flags); + this_device->supports_aborts = + hpsa_device_supports_aborts(h, scsi3addr); + if (this_device->supports_aborts < 0) + this_device->supports_aborts = 0; + } return 0; bail_out: From f7fc0c26026b1d6b943a719bc29d77cd409747c7 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:35 -0500 Subject: [PATCH 043/889] hpsa: do not send two aborts with swizzled tags. Some Smart Arrays required aborts to be sent with tags in the wrong endian byte order. To avoid having to know about this, we would send two aborts with tags with each endian order. On high IOPS devices, this turns out to be not such a hot idea. So we now have a list of the devices that got the tag backwards, and we only send it one way. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 52 ++++++++++++++++++++++++++------------------- drivers/scsi/hpsa.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a98b8e69016804..c85749964ca715 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -574,24 +574,31 @@ static u32 soft_unresettable_controller[] = { 0x409D0E11, /* Smart Array 6400 EM */ }; -static int ctlr_is_hard_resettable(u32 board_id) +static u32 needs_abort_tags_swizzled[] = { + 0x324a103C, /* Smart Array P712m */ + 0x324b103C, /* SmartArray P711m */ +}; + +static int board_id_in_array(u32 a[], int nelems, u32 board_id) { int i; - for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) - if (unresettable_controller[i] == board_id) - return 0; - return 1; + for (i = 0; i < nelems; i++) + if (a[i] == board_id) + return 1; + return 0; } -static int ctlr_is_soft_resettable(u32 board_id) +static int ctlr_is_hard_resettable(u32 board_id) { - int i; + return !board_id_in_array(unresettable_controller, + ARRAY_SIZE(unresettable_controller), board_id); +} - for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++) - if (soft_unresettable_controller[i] == board_id) - return 0; - return 1; +static int ctlr_is_soft_resettable(u32 board_id) +{ + return !board_id_in_array(soft_unresettable_controller, + ARRAY_SIZE(soft_unresettable_controller), board_id); } static int ctlr_is_resettable(u32 board_id) @@ -600,6 +607,12 @@ static int ctlr_is_resettable(u32 board_id) ctlr_is_soft_resettable(board_id); } +static int ctlr_needs_abort_tags_swizzled(u32 board_id) +{ + return board_id_in_array(needs_abort_tags_swizzled, + ARRAY_SIZE(needs_abort_tags_swizzled), board_id); +} + static ssize_t host_show_resettable(struct device *dev, struct device_attribute *attr, char *buf) { @@ -4552,7 +4565,7 @@ static void hpsa_get_tag(struct ctlr_info *h, } static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, - struct CommandList *abort, int swizzle, int reply_queue) + struct CommandList *abort, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -4568,7 +4581,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, /* fill_cmd can't fail here, no buffer to map */ (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, 0, 0, scsi3addr, TYPE_MSG); - if (swizzle) + if (h->needs_abort_tags_swizzled) swizzle_abort_tag(&c->Request.CDB[4]); (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); @@ -4674,12 +4687,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, return rc; /* success */ } -/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to - * tell which kind we're dealing with, so we send the abort both ways. There - * shouldn't be any collisions between swizzled and unswizzled tags due to the - * way we construct our tags but we check anyway in case the assumptions which - * make this true someday become false. - */ static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { @@ -4691,9 +4698,7 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, if (abort->cmd_type == CMD_IOACCEL2) return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort, reply_queue); - - return hpsa_send_abort(h, scsi3addr, abort, 0, reply_queue) && - hpsa_send_abort(h, scsi3addr, abort, 1, reply_queue); + return hpsa_send_abort(h, scsi3addr, abort, reply_queue); } /* Find out which reply queue a command was meant to return on */ @@ -6397,6 +6402,9 @@ static int hpsa_pci_init(struct ctlr_info *h) h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); + h->needs_abort_tags_swizzled = + ctlr_needs_abort_tags_swizzled(h->board_id); + pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 03a28dc6e54337..283b7891c9d4a3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -237,6 +237,7 @@ struct ctlr_info { int acciopath_status; int raid_offload_debug; int lockup_detector_enabled; + int needs_abort_tags_swizzled; }; struct offline_device_entry { From 079904725ee71e40ca1b89edb6e761d77a07aacb Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:36 -0500 Subject: [PATCH 044/889] hpsa: decrement h->commands_outstanding in fail_all_outstanding_cmds Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c85749964ca715..851c967f56b461 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6727,6 +6727,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) if (refcount > 1) { c->err_info->CommandStatus = CMD_HARDWARE_ERR; finish_cmd(c); + atomic_dec(&h->commands_outstanding); } cmd_free(h, c); } From 49b386306ee3c02369025a7481977e5c48ef69b1 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:37 -0500 Subject: [PATCH 045/889] hpsa: flush work queue hpsa_wq in fail_all_outstanding_cmds This is so that fail_all_outstanding_cmds will not call finish_cmd() to operate on a partially constructed command. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 851c967f56b461..30a7eb8c8e8c98 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6721,6 +6721,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) int i, refcount; struct CommandList *c; + flush_workqueue(hpsa_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); From 58aefd15385357202feea55c7ecc07150bdfbfb2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:37 -0500 Subject: [PATCH 046/889] hpsa: use per controller not per driver work queue for command resubmission This is so that the fail_all_outstanding_cmds() does not get stuck waiting for work items on other controllers when flushing the work queue. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++++++++------------ drivers/scsi/hpsa.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 30a7eb8c8e8c98..c8cde1b06b8f59 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -190,7 +190,6 @@ static struct board_type products[] = { }; static int number_of_controllers; -static struct workqueue_struct *hpsa_wq; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); @@ -1809,7 +1808,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, retry_cmd: INIT_WORK(&c->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), hpsa_wq, &c->work); + queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1879,7 +1878,7 @@ static void complete_scsi_command(struct CommandList *cp) dev->offload_enabled = 0; INIT_WORK(&cp->work, hpsa_command_resubmit_worker); queue_work_on(raw_smp_processor_id(), - hpsa_wq, &cp->work); + h->resubmit_wq, &cp->work); return; } } @@ -6721,7 +6720,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) int i, refcount; struct CommandList *c; - flush_workqueue(hpsa_wq); /* ensure all cmds are fully built */ + flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); @@ -6960,6 +6959,12 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); + h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!h->resubmit_wq) { + dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); + rc = -ENOMEM; + goto clean1; + } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { @@ -7091,6 +7096,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) free_irqs(h); clean2: clean1: + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); if (h->lockup_detected) free_percpu(h->lockup_detected); kfree(h); @@ -7170,9 +7177,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) h->remove_in_progress = 1; cancel_delayed_work(&h->monitor_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); - hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); + destroy_workqueue(h->resubmit_wq); iounmap(h->vaddr); iounmap(h->transtable); iounmap(h->cfgtable); @@ -7590,19 +7597,12 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) */ static int __init hpsa_init(void) { - hpsa_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); - if (!hpsa_wq) { - pr_warn(HPSA "Failed to allocate work queue\n"); - return -ENOMEM; - } return pci_register_driver(&hpsa_pci_driver); } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); - if (hpsa_wq) - destroy_workqueue(hpsa_wq); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 283b7891c9d4a3..978c23fcbcf5fc 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -238,6 +238,7 @@ struct ctlr_info { int raid_offload_debug; int lockup_detector_enabled; int needs_abort_tags_swizzled; + struct workqueue_struct *resubmit_wq; }; struct offline_device_entry { From daad845562c66f7cd20271cda08585683521615f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:38 -0500 Subject: [PATCH 047/889] hpsa: always use extended report physical LUNs for physical devices The extended report physical luns gives information that is needed for ioaccellerator modes, but there's no sense in doing it two different ways unnecessarily. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 48 +++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c8cde1b06b8f59..1200a026b0ca61 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2563,7 +2563,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, } static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, - struct ReportLUNdata *buf, int bufsize, + void *buf, int bufsize, int extended_response) { int rc = IO_OK; @@ -2595,11 +2595,12 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, hpsa_scsi_interpret_error(h, c); rc = -1; } else { - if (buf->extended_response_flag != extended_response) { + struct ReportLUNdata *rld = buf; + if (rld->extended_response_flag != extended_response) { dev_err(&h->pdev->dev, "report luns requested format %u, got %u\n", extended_response, - buf->extended_response_flag); + rld->extended_response_flag); rc = -1; } } @@ -2609,10 +2610,10 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, - struct ReportLUNdata *buf, - int bufsize, int extended_response) + struct ReportExtendedLUNdata *buf, int bufsize) { - return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response); + return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, + HPSA_REPORT_PHYS_EXTENDED); } static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h, @@ -2996,7 +2997,6 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, { struct ReportExtendedLUNdata *physicals = NULL; int responsesize = 24; /* size of physical extended response */ - int extended = 2; /* flag forces reporting 'other dev info'. */ int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize; u32 nphysicals = 0; /* number of reported physical devs */ int found = 0; /* found match (1) or not (0) */ @@ -3043,8 +3043,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, physicals = kzalloc(reportsize, GFP_KERNEL); if (physicals == NULL) return 0; - if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals, - reportsize, extended)) { + if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) { dev_err(&h->pdev->dev, "Can't lookup %s device handle: report physical LUNs failed.\n", "HP SSD Smart Path"); @@ -3085,34 +3084,21 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, * Returns 0 on success, -1 otherwise. */ static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportphyslunsize, int reportloglunsize, - struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode, + struct ReportExtendedLUNdata *physdev, u32 *nphysicals, struct ReportLUNdata *logdev, u32 *nlogicals) { - int physical_entry_size = 8; - - *physical_mode = 0; - - /* For I/O accelerator mode we need to read physical device handles */ - if (h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2) { - *physical_mode = HPSA_REPORT_PHYS_EXTENDED; - physical_entry_size = 24; - } - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize, - *physical_mode)) { + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; } - *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / - physical_entry_size; + *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24; if (*nphysicals > HPSA_MAX_PHYS_LUN) { dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded." " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, *nphysicals - HPSA_MAX_PHYS_LUN); *nphysicals = HPSA_MAX_PHYS_LUN; } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) { + if (hpsa_scsi_do_report_log_luns(h, logdev, sizeof(*logdev))) { dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } @@ -3201,7 +3187,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) struct ReportLUNdata *logdev_list = NULL; u32 nphysicals = 0; u32 nlogicals = 0; - int physical_mode = 0; u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; @@ -3232,10 +3217,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, - sizeof(*physdev_list), sizeof(*logdev_list), - (struct ReportLUNdata *) physdev_list, &nphysicals, - &physical_mode, logdev_list, &nlogicals)) + if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, + logdev_list, &nlogicals)) goto out; /* We might see up to the maximum number of logical and physical disks @@ -3332,7 +3315,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; } - if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) { + if (h->transMethod & CFGTBL_Trans_io_accel1 || + h->transMethod & CFGTBL_Trans_io_accel2) { memcpy(&this_device->ioaccel_handle, &lunaddrbytes[20], sizeof(this_device->ioaccel_handle)); From d382584d0a7424dcf1b2a263c4912b54d4014850 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:00:38 -0500 Subject: [PATCH 048/889] hpsa: add masked physical devices into h->dev[] array This is so that we can store the ioaccel handle for those devices so that when we need to abort commands sent down ioaccel2 path, we can look up the 8-byte LUN ID in h->dev[] instead of having to do i/o to the controller each time. We add an expose_state field to h->dev[] elements to indicate how the device is exposed to the scsi mid layer: Not at all, without an upper level driver (no_uld_attach) or normally exposed. Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 77 +++++++++++++++++++++++++++++++---------- drivers/scsi/hpsa.h | 5 +++ drivers/scsi/hpsa_cmd.h | 3 ++ 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1200a026b0ca61..433e804135fcc2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -216,6 +216,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); static int hpsa_slave_alloc(struct scsi_device *sdev); +static int hpsa_slave_configure(struct scsi_device *sdev); static void hpsa_slave_destroy(struct scsi_device *sdev); static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); @@ -807,6 +808,7 @@ static struct scsi_host_template hpsa_driver_template = { .eh_device_reset_handler = hpsa_eh_device_reset_handler, .ioctl = hpsa_ioctl, .slave_alloc = hpsa_slave_alloc, + .slave_configure = hpsa_slave_configure, .slave_destroy = hpsa_slave_destroy, #ifdef CONFIG_COMPAT .compat_ioctl = hpsa_compat_ioctl, @@ -1519,20 +1521,23 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, sh = h->scsi_host; /* Notify scsi mid layer of any removed devices */ for (i = 0; i < nremoved; i++) { - struct scsi_device *sdev = - scsi_device_lookup(sh, removed[i]->bus, - removed[i]->target, removed[i]->lun); - if (sdev != NULL) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* We don't expect to get here. - * future cmds to this device will get selection - * timeout as if the device was gone. - */ - dev_warn(&h->pdev->dev, "didn't find c%db%dt%dl%d " - " for removal.", hostno, removed[i]->bus, - removed[i]->target, removed[i]->lun); + if (removed[i]->expose_state & HPSA_SCSI_ADD) { + struct scsi_device *sdev = + scsi_device_lookup(sh, removed[i]->bus, + removed[i]->target, removed[i]->lun); + if (sdev != NULL) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* We don't expect to get here. + * future cmds to this device will get selection + * timeout as if the device was gone. + */ + dev_warn(&h->pdev->dev, + "didn't find c%db%dt%dl%d for removal.", + hostno, removed[i]->bus, + removed[i]->target, removed[i]->lun); + } } kfree(removed[i]); removed[i] = NULL; @@ -1540,6 +1545,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* Notify scsi mid layer of any added devices */ for (i = 0; i < nadded; i++) { + if (!(added[i]->expose_state & HPSA_SCSI_ADD)) + continue; if (scsi_add_device(sh, added[i]->bus, added[i]->target, added[i]->lun) == 0) continue; @@ -1592,6 +1599,23 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) return 0; } +/* configure scsi device based on internal per-device structure */ +static int hpsa_slave_configure(struct scsi_device *sdev) +{ + struct hpsa_scsi_dev_t *sd; + unsigned long flags; + struct ctlr_info *h; + + h = sdev_to_hba(sdev); + spin_lock_irqsave(&h->devlock, flags); + sd = sdev->hostdata; + if (sd && sd->expose_state & HPSA_NO_ULD_ATTACH) + sdev->no_uld_attach = 1; + + spin_unlock_irqrestore(&h->devlock, flags); + return 0; +} + static void hpsa_slave_destroy(struct scsi_device *sdev) { /* nothing to do. */ @@ -3258,10 +3282,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) /* Figure out where the LUN ID info is coming from */ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, i, nphysicals, nlogicals, physdev_list, logdev_list); - /* skip masked physical devices. */ - if (lunaddrbytes[3] & 0xC0 && - i < nphysicals + (raid_ctlr_position == 0)) - continue; + + /* skip masked non-disk devices */ + if (MASKED_DEVICE(lunaddrbytes)) + if (i < nphysicals + (raid_ctlr_position == 0) && + NON_DISK_PHYS_DEV(lunaddrbytes)) + continue; /* Get device type, vendor, model, device id */ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, @@ -3286,6 +3312,17 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) *this_device = *tmpdevice; + /* do not expose masked devices */ + if (MASKED_DEVICE(lunaddrbytes) && + i < nphysicals + (raid_ctlr_position == 0)) { + if (h->hba_mode_enabled) + dev_warn(&h->pdev->dev, + "Masked physical device detected\n"); + this_device->expose_state = HPSA_DO_NOT_EXPOSE; + } else { + this_device->expose_state = HPSA_EXPOSE; + } + switch (this_device->devtype) { case TYPE_ROM: /* We don't *really* support actual CD-ROM devices, @@ -3327,6 +3364,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) case TYPE_MEDIUM_CHANGER: ncurrent++; break; + case TYPE_ENCLOSURE: + if (h->hba_mode_enabled) + ncurrent++; + break; case TYPE_RAID: /* Only present the Smartarray HBA as a RAID controller. * If it's a RAID controller other than the HBA itself diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 978c23fcbcf5fc..e4f51f75bc5019 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -54,6 +54,11 @@ struct hpsa_scsi_dev_t { */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ int supports_aborts; +#define HPSA_NO_ULD_ATTACH 0x1 +#define HPSA_DO_NOT_EXPOSE 0x2 +#define HPSA_EXPOSE 0x4 +#define HPSA_SCSI_ADD (HPSA_NO_ULD_ATTACH | HPSA_EXPOSE) + u8 expose_state; }; struct reply_queue_buffer { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 0ccb35d215a6b2..d5baded2c63e46 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -240,9 +240,12 @@ struct ReportLUNdata { struct ext_report_lun_entry { u8 lunid[8]; +#define MASKED_DEVICE(x) ((x)[3] & 0xC0) u8 wwid[8]; u8 device_type; u8 device_flags; +#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01) +#define PHYS_IOACCEL(x) ((x)[17] & 0x08) u8 lun_count; /* multi-lun device, how many luns */ u8 redundant_paths; u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ From 749726e110d7f30db926c7cfab6b3f34b900d2d1 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:39 -0500 Subject: [PATCH 049/889] hpsa: prevent manually adding masked physical devices Since masked physical devices are now present in h->dev[] array it is perfectly possible to do echo scsi add-single-device 2 2 0 0 > /proc/scsi/scsi and bring them online. This should not be the case for masked physical devices.. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 433e804135fcc2..03c3cc483f5a4d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1593,8 +1593,10 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(&h->devlock, flags); sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); - if (sd != NULL) + if (sd && (sd->expose_state & HPSA_SCSI_ADD)) sdev->hostdata = sd; + else + sdev->hostdata = NULL; spin_unlock_irqrestore(&h->devlock, flags); return 0; } From 385adc86b9d5b763fddb8c894fe13aad05dd4496 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:39 -0500 Subject: [PATCH 050/889] hpsa: fix values for expose status Change the values for the expose_status field of hpsa_scsi_dev_t to make sense. HPSA_DO_NOT_EXPOSE 0x0 HPSA_SG_ATTACH 0x1 HPSA_ULD_ATTACH 0x2 HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +++-- drivers/scsi/hpsa.h | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 03c3cc483f5a4d..38d9a57b4a2b9f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1611,7 +1611,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev) h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); sd = sdev->hostdata; - if (sd && sd->expose_state & HPSA_NO_ULD_ATTACH) + if (sd && !(sd->expose_state & HPSA_ULD_ATTACH)) sdev->no_uld_attach = 1; spin_unlock_irqrestore(&h->devlock, flags); @@ -3322,7 +3322,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) "Masked physical device detected\n"); this_device->expose_state = HPSA_DO_NOT_EXPOSE; } else { - this_device->expose_state = HPSA_EXPOSE; + this_device->expose_state = + HPSA_SG_ATTACH | HPSA_ULD_ATTACH; } switch (this_device->devtype) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index e4f51f75bc5019..fa9caba34ae167 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -54,10 +54,10 @@ struct hpsa_scsi_dev_t { */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ int supports_aborts; -#define HPSA_NO_ULD_ATTACH 0x1 -#define HPSA_DO_NOT_EXPOSE 0x2 -#define HPSA_EXPOSE 0x4 -#define HPSA_SCSI_ADD (HPSA_NO_ULD_ATTACH | HPSA_EXPOSE) +#define HPSA_DO_NOT_EXPOSE 0x0 +#define HPSA_SG_ATTACH 0x1 +#define HPSA_ULD_ATTACH 0x2 +#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) u8 expose_state; }; From ebe12d461887be1cbcce4d58239abbb568b77de3 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:40 -0500 Subject: [PATCH 051/889] hpsa: avoid unnecessary io in hpsa_get_pdisk_of_ioaccel2() THIS PATCH IS PROBLEMATIC - DO NOT SUBMIT UPSTREAM AS IS. The problem is that h->dev[] does not contain data for unexposed disks, which is what we need for getting the physical disk of an io by matching up the ioaccel handle. A later patch gets this data and puts it in h->dev[] so this patch eventually works, but not at this point in the stack. Below is the original commit message. Instead of doing CISS_REPORT_PHYSICAL to get the LUNID for the physical disk in hpsa_get_pdisk_of_ioaccel2(), just get it out of h->dev[] where we already have it cached. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 93 +++++++-------------------------------------- 1 file changed, 14 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 38d9a57b4a2b9f..d55e6377e5d246 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3021,88 +3021,23 @@ static int add_ext_target_dev(struct ctlr_info *h, static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr) { - struct ReportExtendedLUNdata *physicals = NULL; - int responsesize = 24; /* size of physical extended response */ - int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize; - u32 nphysicals = 0; /* number of reported physical devs */ - int found = 0; /* found match (1) or not (0) */ - u32 find; /* handle we need to match */ + struct io_accel2_cmd *c2 = + &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex]; + unsigned long flags; int i; - struct scsi_cmnd *scmd; /* scsi command within request being aborted */ - struct hpsa_scsi_dev_t *d; /* device of request being aborted */ - struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */ - u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */ - u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */ - - if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2) - return 0; /* no match */ - - /* point to the ioaccel2 device handle */ - c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex]; - if (c2a == NULL) - return 0; /* no match */ - - scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd; - if (scmd == NULL) - return 0; /* no match */ - - d = scmd->device->hostdata; - if (d == NULL) - return 0; /* no match */ - - it_nexus = cpu_to_le32((u32) d->ioaccel_handle); - scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus); - find = c2a->scsi_nexus; - - if (h->raid_offload_debug > 0) - dev_info(&h->pdev->dev, - "%s: scsi_nexus:0x%08x device id: 0x%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n", - __func__, scsi_nexus, - d->device_id[0], d->device_id[1], d->device_id[2], - d->device_id[3], d->device_id[4], d->device_id[5], - d->device_id[6], d->device_id[7], d->device_id[8], - d->device_id[9], d->device_id[10], d->device_id[11], - d->device_id[12], d->device_id[13], d->device_id[14], - d->device_id[15]); - - /* Get the list of physical devices */ - physicals = kzalloc(reportsize, GFP_KERNEL); - if (physicals == NULL) - return 0; - if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) { - dev_err(&h->pdev->dev, - "Can't lookup %s device handle: report physical LUNs failed.\n", - "HP SSD Smart Path"); - kfree(physicals); - return 0; - } - nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) / - responsesize; - - /* find ioaccel2 handle in list of physicals: */ - for (i = 0; i < nphysicals; i++) { - struct ext_report_lun_entry *entry = &physicals->LUN[i]; - - /* handle is in bytes 28-31 of each lun */ - if (entry->ioaccel_handle != find) - continue; /* didn't match */ - found = 1; - memcpy(scsi3addr, entry->lunid, 8); - if (h->raid_offload_debug > 0) - dev_info(&h->pdev->dev, - "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%8phN\n", - __func__, find, - entry->ioaccel_handle, scsi3addr); - break; /* found it */ - } - - kfree(physicals); - if (found) - return 1; - else - return 0; + spin_lock_irqsave(&h->devlock, flags); + for (i = 0; i < h->ndevices; i++) + if (h->dev[i]->ioaccel_handle == c2->scsi_nexus) { + memcpy(scsi3addr, h->dev[i]->scsi3addr, + sizeof(h->dev[i]->scsi3addr)); + spin_unlock_irqrestore(&h->devlock, flags); + return 1; + } + spin_unlock_irqrestore(&h->devlock, flags); + return 0; } + /* * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, * logdev. The number of luns in physdev and logdev are returned in From 4b89fad9b9ec4f980efd5d61983d39514d7d06da Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:41 -0500 Subject: [PATCH 052/889] hpsa: handle descriptor format sense data where needed In hba mode, we could get sense data in descriptor format so we need to handle that. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 82 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d55e6377e5d246..3ae0784c95a6d4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -261,13 +261,53 @@ static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh) return (struct ctlr_info *) *priv; } +/* extract sense key, asc, and ascq from sense data. -1 means invalid. */ +static void decode_sense_data(const u8 *sense_data, int sense_data_len, + int *sense_key, int *asc, int *ascq) +{ + if (sense_data_len < 1) { + *sense_key = -1; + *ascq = -1; + *asc = -1; + return; + } + + switch (sense_data[0]) { + case 0x70: /* old format sense data */ + *sense_key = (sense_data_len > 2) ? sense_data[2] & 0x0f : -1; + *ascq = (sense_data_len > 13) ? sense_data[13] : -1; + *asc = (sense_data_len > 12) ? sense_data[12] : -1; + break; + case 0x72: /* descriptor format sense data */ + *sense_key = (sense_data_len > 1) ? sense_data[1] & 0x0f : -1; + *ascq = (sense_data_len > 2) ? sense_data[2] : -1; + *asc = (sense_data_len > 3) ? sense_data[3] : -1; + break; + default: + *sense_key = -1; + *ascq = -1; + *asc = -1; + break; + } +} + static int check_for_unit_attention(struct ctlr_info *h, struct CommandList *c) { - if (c->err_info->SenseInfo[2] != UNIT_ATTENTION) + int sense_key, asc, ascq; + int sense_len; + + if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo)) + sense_len = sizeof(c->err_info->SenseInfo); + else + sense_len = c->err_info->SenseLen; + + decode_sense_data(c->err_info->SenseInfo, sense_len, + &sense_key, &asc, &ascq); + if (sense_key != UNIT_ATTENTION || asc == -1) return 0; - switch (c->err_info->SenseInfo[12]) { + switch (asc) { case STATE_CHANGED: dev_warn(&h->pdev->dev, HPSA "%d: a state change " "detected, command retried\n", h->ctlr); @@ -1844,9 +1884,9 @@ static void complete_scsi_command(struct CommandList *cp) struct ErrorInfo *ei; struct hpsa_scsi_dev_t *dev; - unsigned char sense_key; - unsigned char asc; /* additional sense code */ - unsigned char ascq; /* additional sense code qualifier */ + int sense_key; + int asc; /* additional sense code */ + int ascq; /* additional sense code qualifier */ unsigned long sense_data_size; ei = cp->err_info; @@ -1913,14 +1953,9 @@ static void complete_scsi_command(struct CommandList *cp) switch (ei->CommandStatus) { case CMD_TARGET_STATUS: - if (ei->ScsiStatus) { - /* Get sense key */ - sense_key = 0xf & ei->SenseInfo[2]; - /* Get additional sense code */ - asc = ei->SenseInfo[12]; - /* Get addition sense code qualifier */ - ascq = ei->SenseInfo[13]; - } + if (ei->ScsiStatus) + decode_sense_data(ei->SenseInfo, sense_data_size, + &sense_key, &asc, &ascq); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { if (sense_key == ABORTED_COMMAND) { cmd->result |= DID_SOFT_ERROR << 16; @@ -2184,14 +2219,20 @@ static void hpsa_scsi_interpret_error(struct ctlr_info *h, { const struct ErrorInfo *ei = cp->err_info; struct device *d = &cp->h->pdev->dev; - const u8 *sd = ei->SenseInfo; + int sense_key, asc, ascq, sense_len; switch (ei->CommandStatus) { case CMD_TARGET_STATUS: + if (ei->SenseLen > sizeof(ei->SenseInfo)) + sense_len = sizeof(ei->SenseInfo); + else + sense_len = ei->SenseLen; + decode_sense_data(ei->SenseInfo, sense_len, + &sense_key, &asc, &ascq); hpsa_print_cmd(h, "SCSI status", cp); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) dev_warn(d, "SCSI Status = 02, Sense key = %02x, ASC = %02x, ASCQ = %02x\n", - sd[2] & 0x0f, sd[12], sd[13]); + sense_key, asc, ascq); else dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus); if (ei->ScsiStatus == 0) @@ -2705,7 +2746,8 @@ static int hpsa_volume_offline(struct ctlr_info *h, unsigned char scsi3addr[]) { struct CommandList *c; - unsigned char *sense, sense_key, asc, ascq; + unsigned char *sense; + int sense_key, asc, ascq, sense_len; int rc, ldstat = 0; u16 cmd_status; u8 scsi_status; @@ -2723,9 +2765,11 @@ static int hpsa_volume_offline(struct ctlr_info *h, return 0; } sense = c->err_info->SenseInfo; - sense_key = sense[2]; - asc = sense[12]; - ascq = sense[13]; + if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo)) + sense_len = sizeof(c->err_info->SenseInfo); + else + sense_len = c->err_info->SenseLen; + decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq); cmd_status = c->err_info->CommandStatus; scsi_status = c->err_info->ScsiStatus; cmd_free(h, c); From 5e54c473cace856327fb87d46571d3f1be5ba3b5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:41 -0500 Subject: [PATCH 053/889] hpsa: print CDBs instead of kernel virtual addresses for uncommon errors Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3ae0784c95a6d4..fb931d03ab5cc3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1996,9 +1996,8 @@ static void complete_scsi_command(struct CommandList *cp) case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ break; case CMD_DATA_OVERRUN: - dev_warn(&h->pdev->dev, "cp %p has" - " completed with data overrun " - "reported\n", cp); + dev_warn(&h->pdev->dev, + "CDB %16phN data overrun\n", cp->Request.CDB); break; case CMD_INVALID: { /* print_bytes(cp, sizeof(*cp), 1, 0); @@ -2014,34 +2013,38 @@ static void complete_scsi_command(struct CommandList *cp) break; case CMD_PROTOCOL_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p has " - "protocol error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n", + cp->Request.CDB); break; case CMD_HARDWARE_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n", + cp->Request.CDB); break; case CMD_CONNECTION_LOST: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n", + cp->Request.CDB); break; case CMD_ABORTED: cmd->result = DID_ABORT << 16; - dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n", - cp, ei->ScsiStatus); + dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", + cp->Request.CDB, ei->ScsiStatus); break; case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n", + cp->Request.CDB); break; case CMD_UNSOLICITED_ABORT: cmd->result = DID_SOFT_ERROR << 16; /* retry the command */ - dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited " - "abort\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n", + cp->Request.CDB); break; case CMD_TIMEOUT: cmd->result = DID_TIME_OUT << 16; - dev_warn(&h->pdev->dev, "cp %p timedout\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN timedout\n", + cp->Request.CDB); break; case CMD_UNABORTABLE: cmd->result = DID_ERROR << 16; From 83513f1caedf0af772125bfa6332c655c9bf3a90 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:42 -0500 Subject: [PATCH 054/889] hpsa: handle Command Status TMF function status It's possible for CommandStatus to have value 0x0D "TMF Function Status", which we should handle. We will get this from a P1224 when aborting a non-existent tag, for example. The "ScsiStatus" field of the errinfo field will contain the TMF function status value. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 ++++++++++++++++++++++++++++++++--------- drivers/scsi/hpsa_cmd.h | 9 +++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index fb931d03ab5cc3..7fb7d8bf7b3c39 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1877,6 +1877,33 @@ static void process_ioaccel2_completion(struct ctlr_info *h, queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } +/* Returns 0 on success, < 0 otherwise. */ +static int hpsa_evaluate_tmf_status(struct ctlr_info *h, + struct CommandList *cp) +{ + u8 tmf_status = cp->err_info->ScsiStatus; + + switch (tmf_status) { + case CISS_TMF_COMPLETE: + /* CISS_TMF_COMPLETE never happens, instead, + * ei->CommandStatus == 0 for this case. + */ + case CISS_TMF_SUCCESS: + return 0; + case CISS_TMF_INVALID_FRAME: + case CISS_TMF_NOT_SUPPORTED: + case CISS_TMF_FAILED: + case CISS_TMF_WRONG_LUN: + case CISS_TMF_OVERLAPPED_TAG: + break; + default: + dev_warn(&h->pdev->dev, "Unknown TMF status: %02x\n", + tmf_status); + break; + } + return -tmf_status; +} + static void complete_scsi_command(struct CommandList *cp) { struct scsi_cmnd *cmd; @@ -1905,8 +1932,6 @@ static void complete_scsi_command(struct CommandList *cp) if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); - cmd->result |= ei->ScsiStatus; - scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { cmd_free(h, cp); @@ -1914,16 +1939,6 @@ static void complete_scsi_command(struct CommandList *cp) return; } - /* copy the sense data */ - if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) - sense_data_size = SCSI_SENSE_BUFFERSIZE; - else - sense_data_size = sizeof(ei->SenseInfo); - if (ei->SenseLen < sense_data_size) - sense_data_size = ei->SenseLen; - - memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); - /* For I/O accelerator commands, copy over some fields to the normal * CISS header used below for error handling. */ @@ -1953,6 +1968,15 @@ static void complete_scsi_command(struct CommandList *cp) switch (ei->CommandStatus) { case CMD_TARGET_STATUS: + cmd->result |= ei->ScsiStatus; + /* copy the sense data */ + if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) + sense_data_size = SCSI_SENSE_BUFFERSIZE; + else + sense_data_size = sizeof(ei->SenseInfo); + if (ei->SenseLen < sense_data_size) + sense_data_size = ei->SenseLen; + memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); if (ei->ScsiStatus) decode_sense_data(ei->SenseInfo, sense_data_size, &sense_key, &asc, &ascq); @@ -2050,6 +2074,10 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "Command unabortable\n"); break; + case CMD_TMF_STATUS: + if (hpsa_evaluate_tmf_status(h, cp)) /* TMF failed? */ + cmd->result = DID_ERROR << 16; + break; case CMD_IOACCEL_DISABLED: /* This only handles the direct pass-through case since RAID * offload is handled above. Just attempt a retry. @@ -2847,6 +2875,9 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, case CMD_ABORT_FAILED: rc = 1; break; + case CMD_TMF_STATUS: + rc = hpsa_evaluate_tmf_status(h, c); + break; default: rc = 0; break; @@ -4602,6 +4633,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, switch (ei->CommandStatus) { case CMD_SUCCESS: break; + case CMD_TMF_STATUS: + rc = hpsa_evaluate_tmf_status(h, c); + break; case CMD_UNABORTABLE: /* Very common, don't make noise. */ rc = -1; break; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index d5baded2c63e46..5ec85533a4d76a 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -42,8 +42,17 @@ #define CMD_UNSOLICITED_ABORT 0x000A #define CMD_TIMEOUT 0x000B #define CMD_UNABORTABLE 0x000C +#define CMD_TMF_STATUS 0x000D #define CMD_IOACCEL_DISABLED 0x000E +/* TMF function status values */ +#define CISS_TMF_COMPLETE 0x00 +#define CISS_TMF_INVALID_FRAME 0x02 +#define CISS_TMF_NOT_SUPPORTED 0x04 +#define CISS_TMF_FAILED 0x05 +#define CISS_TMF_SUCCESS 0x08 +#define CISS_TMF_WRONG_LUN 0x09 +#define CISS_TMF_OVERLAPPED_TAG 0x0a /* Unit Attentions ASC's as defined for the MSA2012sa */ #define POWER_OR_RESET 0x29 From 0ef2464c9e42c821cb79b05823b5645d4d734499 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:42 -0500 Subject: [PATCH 055/889] hpsa: do not use a void pointer for scsi_cmd field of struct CommandList There's no reason for it to be a void *, it should be a struct scsi_cmnd * Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- drivers/scsi/hpsa_cmd.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7fb7d8bf7b3c39..dcca6a5817e0dd 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1917,7 +1917,7 @@ static void complete_scsi_command(struct CommandList *cp) unsigned long sense_data_size; ei = cp->err_info; - cmd = (struct scsi_cmnd *) cp->scsi_cmd; + cmd = cp->scsi_cmd; h = cp->h; dev = cmd->device->hostdata; @@ -4670,7 +4670,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, unsigned char *psa = &phys_scsi3addr[0]; /* Get a pointer to the hpsa logical device. */ - scmd = (struct scsi_cmnd *) abort->scsi_cmd; + scmd = abort->scsi_cmd; dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata); if (dev == NULL) { dev_warn(&h->pdev->dev, @@ -4824,7 +4824,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); - as = (struct scsi_cmnd *) abort->scsi_cmd; + as = abort->scsi_cmd; if (as != NULL) ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", as->cmnd[0], as->serial_number); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 5ec85533a4d76a..557c650bd7cc7a 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -415,7 +415,7 @@ struct CommandList { int cmd_type; long cmdindex; struct completion *waiting; - void *scsi_cmd; + struct scsi_cmnd *scsi_cmd; struct work_struct work; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 2cedf18998bd789cafa79702592f770e18e83110 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:43 -0500 Subject: [PATCH 056/889] hpsa: return FAILED from abort handler if controller locked up. If the controller is locked up, sending further commands isn't possible, so report the abort as failed immediately. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index dcca6a5817e0dd..159fa518f8fd56 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4776,6 +4776,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) "ABORT REQUEST FAILED, Controller lookup failed.\n")) return FAILED; + if (lockup_detected(h)) + return FAILED; + /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) From 3b0043cf7cc565a253e15c7c0f294ef07905ceec Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:43 -0500 Subject: [PATCH 057/889] hpsa: if controller locked up return failed from device reset handler Returning failed from the device reset handler will get the device kicked offline, which is fine if the controller is locked up anyhow. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 159fa518f8fd56..5699e49fcd97ac 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4550,6 +4550,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) h = sdev_to_hba(scsicmd->device); if (h == NULL) /* paranoia */ return FAILED; + + if (lockup_detected(h)) + return FAILED; + dev = scsicmd->device->hostdata; if (!dev) { dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: " From b586d5f659d75b87da2b1342eac2188a788b4988 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:44 -0500 Subject: [PATCH 058/889] hpsa: check for ctlr lockup after command allocation in main io path Command allocation is the thing that takes the longest in the main i/o path, so check for controller lockup immediately after this to prevent submitting commands to locked up controller as much as possible. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5699e49fcd97ac..24217f509c34b6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4304,6 +4304,12 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return SCSI_MLQUEUE_HOST_BUSY; } + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd_free(h, c); + cmd->scsi_done(cmd); + return 0; + } /* Call alternate submit routine for I/O accelerated commands. * Retries always go down the normal I/O path. From 3386e396b60e59581209cac69a59ba15943d78d7 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:00:45 -0500 Subject: [PATCH 059/889] hpsa: Clean up host, channel, target, lun prints We had a mix of formats (2300, c2b3t0l0, C2B3T0L0) to to format used by the scsi midlayer and upper layer (2:3:0:0) so you can easily follow the information from hpsa to scsi midlayer to sd upper layer. Also add this information: - product ID - vendor ID - RAID level - SSD Smath Path capable and enabled - exposure level (sg-only) Example: hpsa 0000:04:00.0: added scsi 2:0:0:0: Direct-Access HP LOGICAL VOLUME RAID-0 SSDSmartPathCap+ En+ Exp=4 scsi 2:0:0:0: Direct-Access HP LOGICAL VOLUME 10.0 PQ: 0 ANSI: 5 sd 2:0:0:0: [sdr] 12501713072 512-byte logical blocks: (6.40 TB/5.82 TiB) sd 2:0:0:0: [sdr] 4096-byte physical blocks sd 2:0:0:0: [sdr] Attached SCSI disk sd 2:0:0:0: Attached scsi generic sg20 type 0 Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 110 +++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 24217f509c34b6..9ae294d38cdf07 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1137,14 +1137,17 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, added[*nadded] = device; (*nadded)++; - /* initially, (before registering with scsi layer) we don't - * know our hostno and we don't want to print anything first - * time anyway (the scsi layer's inquiries will show that info) - */ - /* if (hostno != -1) */ - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d added.\n", - scsi_device_type(device->devtype), hostno, - device->bus, device->target, device->lun); + dev_info(&h->pdev->dev, + "added scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, device->bus, device->target, device->lun, + scsi_device_type(device->devtype), + device->vendor, + device->model, + device->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[device->raid_level], + device->offload_config ? '+' : '-', + device->offload_enabled ? '+' : '-', + device->expose_state); return 0; } @@ -1175,9 +1178,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; h->dev[entry]->offload_enabled = new_entry->offload_enabled; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); + dev_info(&h->pdev->dev, + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, new_entry->bus, new_entry->target, new_entry->lun, + scsi_device_type(new_entry->devtype), + new_entry->vendor, + new_entry->model, + new_entry->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[new_entry->raid_level], + new_entry->offload_config ? '+' : '-', + new_entry->offload_enabled ? '+' : '-', + new_entry->expose_state); } /* Replace an entry from h->dev[] array. */ @@ -1203,9 +1214,17 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, h->dev[entry] = new_entry; added[*nadded] = new_entry; (*nadded)++; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); + dev_info(&h->pdev->dev, + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, new_entry->bus, new_entry->target, new_entry->lun, + scsi_device_type(new_entry->devtype), + new_entry->vendor, + new_entry->model, + new_entry->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[new_entry->raid_level], + new_entry->offload_config ? '+' : '-', + new_entry->offload_enabled ? '+' : '-', + new_entry->expose_state); } /* Remove an entry from h->dev[] array. */ @@ -1225,9 +1244,17 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, for (i = entry; i < h->ndevices-1; i++) h->dev[i] = h->dev[i+1]; h->ndevices--; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d removed.\n", - scsi_device_type(sd->devtype), hostno, sd->bus, sd->target, - sd->lun); + dev_info(&h->pdev->dev, + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, sd->bus, sd->target, sd->lun, + scsi_device_type(sd->devtype), + sd->vendor, + sd->model, + sd->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[sd->raid_level], + sd->offload_config ? '+' : '-', + sd->offload_enabled ? '+' : '-', + sd->expose_state); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1516,9 +1543,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, */ if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); - dev_info(&h->pdev->dev, "c%db%dt%dl%d: temporarily offline\n", - h->scsi_host->host_no, - sd[i]->bus, sd[i]->target, sd[i]->lun); + dev_info(&h->pdev->dev, + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, + scsi_device_type(sd[i]->devtype), + sd[i]->vendor, + sd[i]->model, + sd[i]->raid_level > RAID_UNKNOWN ? + "RAID-?" : + raid_label[sd[i]->raid_level], + sd[i]->offload_config ? '+' : '-', + sd[i]->offload_enabled ? '+' : '-', + sd[i]->expose_state); continue; } @@ -1574,7 +1610,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * timeout as if the device was gone. */ dev_warn(&h->pdev->dev, - "didn't find c%db%dt%dl%d for removal.", + "didn't find scsi %d:%d:%d:%d for removal.", hostno, removed[i]->bus, removed[i]->target, removed[i]->lun); } @@ -1590,8 +1626,9 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (scsi_add_device(sh, added[i]->bus, added[i]->target, added[i]->lun) == 0) continue; - dev_warn(&h->pdev->dev, "scsi_add_device c%db%dt%dl%d failed, " - "device not added.\n", hostno, added[i]->bus, + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d addition failed, device not added.\n", + hostno, added[i]->bus, added[i]->target, added[i]->lun); /* now we have to remove it from h->dev, * since it didn't get added to scsi mid layer @@ -4566,14 +4603,26 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) "device lookup failed.\n"); return FAILED; } - dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n", - h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + dev_warn(&h->pdev->dev, + "resetting scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun, + scsi_device_type(dev->devtype), + dev->vendor, + dev->model, + dev->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[dev->raid_level], + dev->offload_config ? '+' : '-', + dev->offload_enabled ? '+' : '-', + dev->expose_state); + /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN); if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) return SUCCESS; - dev_warn(&h->pdev->dev, "resetting device failed.\n"); + dev_warn(&h->pdev->dev, + "resetting scsi %d:%d:%d:%d failed\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun); return FAILED; } @@ -4690,7 +4739,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, if (h->raid_offload_debug > 0) dev_info(&h->pdev->dev, - "Reset as abort: Abort requested on C%d:B%d:T%d:L%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + "Reset as abort: scsi %d:%d:%d:%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun, scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3], scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); @@ -4795,7 +4844,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; memset(msg, 0, sizeof(msg)); - ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%llu ", + ml += sprintf(msg+ml, "Aborting command on scsi %d:%d:%d:%llu ", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun); @@ -4842,7 +4891,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", as->cmnd[0], as->serial_number); dev_dbg(&h->pdev->dev, "%s\n", msg); - dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", + dev_warn(&h->pdev->dev, "Aborting command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); /* * Command is in flight, or possibly already completed @@ -4851,8 +4900,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); if (rc != 0) { - dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); - dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", + dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); cmd_free(h, abort); From 0eeb18f6b2e4be5af56bf7b0af68e5573b1823ed Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:45 -0500 Subject: [PATCH 060/889] hpsa: mark masked devices as masked in output Otherwise it can seems as though there is a discrepancy between the driver's output and the output of lsscsi when the driver claims to have "added" a device but then does not actually call scsi_add_device() for it because it is masked. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9ae294d38cdf07..b1238d499a3e79 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1138,7 +1138,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "added scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), device->vendor, From 73ec25558c778be7e7d9a367905a6f8e34c4c68b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:46 -0500 Subject: [PATCH 061/889] hpsa: limit number of concurrent abort requests If all available commands are outstanding and the abort handler is invoked, the abort handler may not be able to allocate a command and may busy-wait excessivly. Reserve a small number of commands for the abort handler and limit the number of concurrent abort requests to the number of reserved commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++++++++++++++++++++++ drivers/scsi/hpsa.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b1238d499a3e79..c8544680f98496 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4813,6 +4813,18 @@ static int hpsa_extract_reply_queue(struct ctlr_info *h, return c->Header.ReplyQueue; } +/* + * Limit concurrency of abort commands to prevent + * over-subscription of commands + */ +static inline int wait_for_available_abort_cmd(struct ctlr_info *h) +{ +#define ABORT_CMD_WAIT_MSECS 5000 + return !wait_event_timeout(h->abort_cmd_wait_queue, + atomic_dec_if_positive(&h->abort_cmds_available) >= 0, + msecs_to_jiffies(ABORT_CMD_WAIT_MSECS)); +} + /* Send an abort for the specified command. * If the device and controller support it, * send a task abort request. @@ -4899,7 +4911,15 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * by the firmware (but not to the scsi mid layer) but we can't * distinguish which. Send the abort down. */ + if (wait_for_available_abort_cmd(h)) { + dev_warn(&h->pdev->dev, + "Timed out waiting for an abort command to become available.\n"); + cmd_free(h, abort); + return FAILED; + } rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); + atomic_inc(&h->abort_cmds_available); + wake_up_all(&h->abort_cmd_wait_queue); if (rc != 0) { dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, @@ -7064,6 +7084,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); + atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { @@ -7114,6 +7135,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); + init_waitqueue_head(&h->abort_cmd_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index fa9caba34ae167..3a6a2eb3011e29 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -244,6 +244,8 @@ struct ctlr_info { int lockup_detector_enabled; int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; + atomic_t abort_cmds_available; + wait_queue_head_t abort_cmd_wait_queue; }; struct offline_device_entry { From 504c9abd5616bcf75b3b9d71fb67360aed273704 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:46 -0500 Subject: [PATCH 062/889] hpsa: separate lockup detection and device rescanning Piggybacking device rescanning functionality onto the lockup detection thread is not a good idea because if the controller locks up during device rescanning, then the thread could get stuck, then the lockup isn't detected. Use separate work queues for device rescanning and lockup detection. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 +++++++++++++++++++++++++-------- drivers/scsi/hpsa.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c8544680f98496..85ac7b14c52943 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7016,15 +7016,11 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } - -static void hpsa_monitor_ctlr_worker(struct work_struct *work) +static void hpsa_rescan_ctlr_worker(struct work_struct *work) { unsigned long flags; struct ctlr_info *h = container_of(to_delayed_work(work), - struct ctlr_info, monitor_ctlr_work); - detect_controller_lockup(h); - if (lockup_detected(h)) - return; + struct ctlr_info, rescan_ctlr_work); if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { scsi_host_get(h->scsi_host); @@ -7032,13 +7028,30 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); } - spin_lock_irqsave(&h->lock, flags); if (h->remove_in_progress) { spin_unlock_irqrestore(&h->lock, flags); return; } - schedule_delayed_work(&h->monitor_ctlr_work, + schedule_delayed_work(&h->rescan_ctlr_work, + h->heartbeat_sample_interval); + spin_unlock_irqrestore(&h->lock, flags); +} + +static void hpsa_monitor_ctlr_worker(struct work_struct *work) +{ + unsigned long flags; + struct ctlr_info *h = container_of(to_delayed_work(work), + struct ctlr_info, monitor_ctlr_work); + detect_controller_lockup(h); + if (lockup_detected(h)) + return; + + spin_lock_irqsave(&h->lock, flags); + if (h->remove_in_progress) + spin_unlock_irqrestore(&h->lock, flags); + else + schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); spin_unlock_irqrestore(&h->lock, flags); } @@ -7216,6 +7229,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); + INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker); + schedule_delayed_work(&h->rescan_ctlr_work, + h->heartbeat_sample_interval); return 0; clean4: @@ -7304,6 +7320,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) spin_lock_irqsave(&h->lock, flags); h->remove_in_progress = 1; cancel_delayed_work(&h->monitor_ctlr_work); + cancel_delayed_work(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 3a6a2eb3011e29..42ddd998a8584b 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -198,6 +198,7 @@ struct ctlr_info { atomic_t firmware_flash_in_progress; u32 *lockup_detected; struct delayed_work monitor_ctlr_work; + struct delayed_work rescan_ctlr_work; int remove_in_progress; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; From 6149c3630c573d103643d095268d4c8139e80936 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:47 -0500 Subject: [PATCH 063/889] hpsa: factor out hpsa_init_cmd function Factor out hpsa_cmd_init from cmd_alloc(). We also need this for resubmitting commands down the default RAID path when they have returned from the ioaccel paths with errors. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 85ac7b14c52943..47d91bec449b86 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4288,6 +4288,26 @@ static int hpsa_ciss_submit(struct ctlr_info *h, return 0; } +static inline void hpsa_cmd_init(struct ctlr_info *h, int index, + struct CommandList *c) +{ + dma_addr_t cmd_dma_handle, err_dma_handle; + + /* Zero out all of commandlist except the last field, refcount */ + memset(c, 0, offsetof(struct CommandList, refcount)); + c->Header.tag = cpu_to_le64((u64) (index << DIRECT_LOOKUP_SHIFT)); + cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c); + c->err_info = h->errinfo_pool + index; + memset(c->err_info, 0, sizeof(*c->err_info)); + err_dma_handle = h->errinfo_pool_dhandle + + index * sizeof(*c->err_info); + c->cmdindex = index; + c->busaddr = (u32) cmd_dma_handle; + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); + c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); + c->h = h; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -4941,10 +4961,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) static struct CommandList *cmd_alloc(struct ctlr_info *h) { struct CommandList *c; - int i; - union u64bit temp64; - dma_addr_t cmd_dma_handle, err_dma_handle; - int refcount; + int refcount, i; unsigned long offset; /* There is some *extremely* small but non-zero chance that that @@ -4977,24 +4994,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } h->last_allocation = i; /* benignly racy */ - - /* Zero out all of commandlist except the last field, refcount */ - memset(c, 0, offsetof(struct CommandList, refcount)); - c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT)); - cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); - c->err_info = h->errinfo_pool + i; - memset(c->err_info, 0, sizeof(*c->err_info)); - err_dma_handle = h->errinfo_pool_dhandle - + i * sizeof(*c->err_info); - - c->cmdindex = i; - - c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); - c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); - - c->h = h; + hpsa_cmd_init(h, i, c); return c; } From cea7289ad008803aad62961c936aa1aaed9c726f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:47 -0500 Subject: [PATCH 064/889] hpsa: reinitialize commands on resubmitting failed ioaccel commands In particular, reinitialize the cmd_type and busaddr fields as these will not be correct for submitting down the RAID stack path after ioaccel command completion. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 47d91bec449b86..49f9b07fbd4a7b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4322,6 +4322,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } + hpsa_cmd_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* * If we get here, it means dma mapping failed. Try From 730ca90d7718fd4ef90fa15794e59bf47a40d958 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:48 -0500 Subject: [PATCH 065/889] hpsa: fully initialize commands once at driver load not every time This saves time when submitting commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 49f9b07fbd4a7b..18b37393b8e6d7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4237,7 +4237,6 @@ static int hpsa_ciss_submit(struct ctlr_info *h, /* Fill in the request block... */ c->Request.Timeout = 0; - memset(c->Request.CDB, 0, sizeof(c->Request.CDB)); BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB)); c->Request.CDBLen = cmd->cmd_len; memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); @@ -4288,7 +4287,7 @@ static int hpsa_ciss_submit(struct ctlr_info *h, return 0; } -static inline void hpsa_cmd_init(struct ctlr_info *h, int index, +static void hpsa_cmd_init(struct ctlr_info *h, int index, struct CommandList *c) { dma_addr_t cmd_dma_handle, err_dma_handle; @@ -4308,6 +4307,26 @@ static inline void hpsa_cmd_init(struct ctlr_info *h, int index, c->h = h; } +static void hpsa_preinitialize_commands(struct ctlr_info *h) +{ + int i; + + for (i = 0; i < h->nr_cmds; i++) { + struct CommandList *c = h->cmd_pool + i; + hpsa_cmd_init(h, i, c); + } +} + +static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, + struct CommandList *c) +{ + dma_addr_t cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c); + + memset(c->Request.CDB, 0, sizeof(c->Request.CDB)); + memset(c->err_info, 0, sizeof(*c->err_info)); + c->busaddr = (u32) cmd_dma_handle; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -4322,7 +4341,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } - hpsa_cmd_init(c->h, c->cmdindex, c); + hpsa_cmd_partial_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* * If we get here, it means dma mapping failed. Try @@ -4378,10 +4397,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) h->acciopath_status)) { cmd->host_scribble = (unsigned char *) c; - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; if (dev->offload_enabled) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; rc = hpsa_scsi_ioaccel_raid_map(h, c); if (rc == 0) return 0; /* Sent on ioaccel path */ @@ -4390,6 +4410,9 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; rc = hpsa_scsi_ioaccel_direct_map(h, c); if (rc == 0) return 0; /* Sent on direct map path */ @@ -4995,7 +5018,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } h->last_allocation = i; /* benignly racy */ - hpsa_cmd_init(h, i, c); + hpsa_cmd_partial_init(h, i, c); return c; } @@ -6676,6 +6699,7 @@ static int hpsa_allocate_cmd_pool(struct ctlr_info *h) dev_err(&h->pdev->dev, "out of memory in %s", __func__); return -ENOMEM; } + hpsa_preinitialize_commands(h); return 0; } From 318241e0955830003b3c87a19a4ab4ce0d513cfc Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:49 -0500 Subject: [PATCH 066/889] hpsa: change driver version to 3.4.6 Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 18b37393b8e6d7..a43d3a480f90ef 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.4-1" +#define HPSA_DRIVER_VERSION "3.4.6-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" From 642167ccc5c9150206cbfc528d7b2e9f5b6374f2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:49 -0500 Subject: [PATCH 067/889] hpsa: allow lockup detected to be viewed via sysfs --- drivers/scsi/hpsa.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a43d3a480f90ef..a3a14a1ed6f8f1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -382,6 +382,30 @@ static ssize_t host_show_lockup_detector(struct device *dev, return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); } +static u32 lockup_detected(struct ctlr_info *h); +static ssize_t host_show_lockup_detected(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, ld, c, cpu; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + ld = lockup_detected(h); + + c = sprintf(buf, "ld=%d: ", ld); + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < num_online_cpus(); i++) { + u32 *lockup_detected; + lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); + ld = *lockup_detected; + cpu = cpumask_next(cpu, cpu_online_mask); + c += sprintf(buf + c, "%d,", ld); + } + c += sprintf(buf + c, "\n"); + return c; +} + static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -811,6 +835,8 @@ static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, host_show_lockup_detector, host_store_lockup_detector); +static DEVICE_ATTR(lockup_detected, S_IRUGO, + host_show_lockup_detected, NULL); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -831,6 +857,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, &dev_attr_lockup_detector, + &dev_attr_lockup_detected, NULL, }; From 8b9cb9995b8399d071f11f69d65c45b296c99610 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:50 -0500 Subject: [PATCH 068/889] hpsa: do not ignore return value of hpsa_register_scsi Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a3a14a1ed6f8f1..8f715f32f84979 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7274,7 +7274,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ + if (hpsa_register_scsi(h)) /* hook ourselves into SCSI subsystem */ + goto clean4; /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; From 4a7c58ee75f43591985b7a761bc5b8eefc86d5da Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:50 -0500 Subject: [PATCH 069/889] hpsa: try resubmitting down raid path on task set full Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8f715f32f84979..c7b4cc85b20baa 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1856,8 +1856,7 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL: - /* Make scsi midlayer do unlimited retries */ - cmd->result = DID_IMM_RETRY << 16; + retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED: dev_warn(&h->pdev->dev, From 97ce2f4742739d1a53ed99c2122a543ddbd748ce Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:51 -0500 Subject: [PATCH 070/889] hpsa: factor out hpsa_ioaccel_submit function Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c7b4cc85b20baa..58680c96cd1add 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4353,6 +4353,41 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, c->busaddr = (u32) cmd_dma_handle; } +static int hpsa_ioaccel_submit(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd, + unsigned char *scsi3addr) +{ + struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; + int rc = IO_ACCEL_INELIGIBLE; + + cmd->host_scribble = (unsigned char *) c; + + if (dev->offload_enabled) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + rc = hpsa_scsi_ioaccel_raid_map(h, c); + if (rc == 0) + return 0; /* Sent on ioaccel path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } else if (dev->ioaccel_handle) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + rc = hpsa_scsi_ioaccel_direct_map(h, c); + if (rc == 0) + return 0; /* Sent on direct map path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + return rc; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -4421,32 +4456,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (likely(cmd->retries == 0 && cmd->request->cmd_type == REQ_TYPE_FS && h->acciopath_status)) { - - cmd->host_scribble = (unsigned char *) c; - - if (dev->offload_enabled) { - hpsa_cmd_init(h, c->cmdindex, c); - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; - rc = hpsa_scsi_ioaccel_raid_map(h, c); - if (rc == 0) - return 0; /* Sent on ioaccel path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } else if (dev->ioaccel_handle) { - hpsa_cmd_init(h, c->cmdindex, c); - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; - rc = hpsa_scsi_ioaccel_direct_map(h, c); - if (rc == 0) - return 0; /* Sent on direct map path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } + rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); + if (rc == 0) + return 0; + if (rc < 0) + return SCSI_MLQUEUE_HOST_BUSY; } return hpsa_ciss_submit(h, c, cmd, scsi3addr); } From 2b7e68621cbac50ba9ab4a829cf270d12d9428b9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:52 -0500 Subject: [PATCH 071/889] hpsa: try resubmitting down ioaccelerated path on task set full Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 58680c96cd1add..6c00886d413ffb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4402,6 +4402,28 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } + if (c->cmd_type == CMD_IOACCEL2) { + struct ctlr_info *h = c->h; + struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + int rc; + + if (c2->error_data.serv_response == + IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) { + rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); + if (rc == 0) + return; + if (rc < 0) { + /* + * If we get here, it means dma mapping failed. + * Try again via scsi mid layer, which will + * then get SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } + /* if rc > 0, fall thru and resubmit down CISS path */ + } + } hpsa_cmd_partial_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* From 068a9912d450f22e29b3f80d54fd98501a086971 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:00:52 -0500 Subject: [PATCH 072/889] hpsa: add hpsa_bmic_id_physical_device function We need to get the queue depths from physical drives Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 39 ++++++++++++ drivers/scsi/hpsa_cmd.h | 133 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6c00886d413ffb..45f14004c27872 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2625,6 +2625,35 @@ static int hpsa_get_raid_map(struct ctlr_info *h, return rc; } +static int hpsa_bmic_id_physical_device(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_identify_physical_device *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + rc = fill_cmd(c, BMIC_IDENTIFY_PHYSICAL_DEVICE, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, + NO_TIMEOUT); + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -5635,6 +5664,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; break; + case BMIC_IDENTIFY_PHYSICAL_DEVICE: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_IDENTIFY_PHYSICAL_DEVICE; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 557c650bd7cc7a..84f0e5395c0158 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -280,6 +280,7 @@ struct SenseSubsystem_info { #define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ #define BMIC_FLASH_FIRMWARE 0xF7 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 +#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 /* Command List Structure */ union SCSI3Addr { @@ -654,5 +655,137 @@ struct hpsa_pci_info { u32 board_id; }; +struct bmic_identify_physical_device { + u8 scsi_bus; /* SCSI Bus number on controller */ + u8 scsi_id; /* SCSI ID on this bus */ + u16 block_size; /* sector size in bytes */ + u32 total_blocks; /* number for sectors on drive */ + u32 reserved_blocks; /* controller reserved (RIS) */ + u8 model[40]; /* Physical Drive Model */ + u8 serial_number[40]; /* Drive Serial Number */ + u8 firmware_revision[8]; /* drive firmware revision */ + u8 scsi_inquiry_bits; /* inquiry byte 7 bits */ + u8 compaq_drive_stamp; /* 0 means drive not stamped */ + u8 last_failure_reason; +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_LOAD_CONFIG 0x01 +#define BMIC_LAST_FAILURE_ERROR_ERASING_RIS 0x02 +#define BMIC_LAST_FAILURE_ERROR_SAVING_RIS 0x03 +#define BMIC_LAST_FAILURE_FAIL_DRIVE_COMMAND 0x04 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED 0x05 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED_IN_FINISH_REMAP 0x06 +#define BMIC_LAST_FAILURE_TIMEOUT 0x07 +#define BMIC_LAST_FAILURE_AUTOSENSE_FAILED 0x08 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_1 0x09 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_2 0x0a +#define BMIC_LAST_FAILURE_NOT_READY_BAD_SENSE 0x0b +#define BMIC_LAST_FAILURE_NOT_READY 0x0c +#define BMIC_LAST_FAILURE_HARDWARE_ERROR 0x0d +#define BMIC_LAST_FAILURE_ABORTED_COMMAND 0x0e +#define BMIC_LAST_FAILURE_WRITE_PROTECTED 0x0f +#define BMIC_LAST_FAILURE_SPIN_UP_FAILURE_IN_RECOVER 0x10 +#define BMIC_LAST_FAILURE_REBUILD_WRITE_ERROR 0x11 +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_HOT_PLUG 0x12 +#define BMIC_LAST_FAILURE_BUS_RESET_RECOVERY_ABORTED 0x13 +#define BMIC_LAST_FAILURE_REMOVED_IN_HOT_PLUG 0x14 +#define BMIC_LAST_FAILURE_INIT_REQUEST_SENSE_FAILED 0x15 +#define BMIC_LAST_FAILURE_INIT_START_UNIT_FAILED 0x16 +#define BMIC_LAST_FAILURE_INQUIRY_FAILED 0x17 +#define BMIC_LAST_FAILURE_NON_DISK_DEVICE 0x18 +#define BMIC_LAST_FAILURE_READ_CAPACITY_FAILED 0x19 +#define BMIC_LAST_FAILURE_INVALID_BLOCK_SIZE 0x1a +#define BMIC_LAST_FAILURE_HOT_PLUG_REQUEST_SENSE_FAILED 0x1b +#define BMIC_LAST_FAILURE_HOT_PLUG_START_UNIT_FAILED 0x1c +#define BMIC_LAST_FAILURE_WRITE_ERROR_AFTER_REMAP 0x1d +#define BMIC_LAST_FAILURE_INIT_RESET_RECOVERY_ABORTED 0x1e +#define BMIC_LAST_FAILURE_DEFERRED_WRITE_ERROR 0x1f +#define BMIC_LAST_FAILURE_MISSING_IN_SAVE_RIS 0x20 +#define BMIC_LAST_FAILURE_WRONG_REPLACE 0x21 +#define BMIC_LAST_FAILURE_GDP_VPD_INQUIRY_FAILED 0x22 +#define BMIC_LAST_FAILURE_GDP_MODE_SENSE_FAILED 0x23 +#define BMIC_LAST_FAILURE_DRIVE_NOT_IN_48BIT_MODE 0x24 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_HOT_PLUG 0x25 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_LOAD_CFG 0x26 +#define BMIC_LAST_FAILURE_PROTOCOL_ADAPTER_FAILED 0x27 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_EMPTY 0x28 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_OCCUPIED 0x29 +#define BMIC_LAST_FAILURE_FAULTY_ID_INVALID_BAY 0x2a +#define BMIC_LAST_FAILURE_WRITE_RETRIES_FAILED 0x2b + +#define BMIC_LAST_FAILURE_SMART_ERROR_REPORTED 0x37 +#define BMIC_LAST_FAILURE_PHY_RESET_FAILED 0x38 +#define BMIC_LAST_FAILURE_ONLY_ONE_CTLR_CAN_SEE_DRIVE 0x40 +#define BMIC_LAST_FAILURE_KC_VOLUME_FAILED 0x41 +#define BMIC_LAST_FAILURE_UNEXPECTED_REPLACEMENT 0x42 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE 0x80 +#define BMIC_LAST_FAILURE_OFFLINE_TOO_SMALL 0x81 +#define BMIC_LAST_FAILURE_OFFLINE_DRIVE_TYPE_MIX 0x82 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE_COMPLETE 0x83 + + u8 flags; + u8 more_flags; + u8 scsi_lun; /* SCSI LUN for phys drive */ + u8 yet_more_flags; + u8 even_more_flags; + u32 spi_speed_rules;/* SPI Speed data:Ultra disable diagnose */ + u8 phys_connector[2]; /* connector number on controller */ + u8 phys_box_on_bus; /* phys enclosure this drive resides */ + u8 phys_bay_in_box; /* phys drv bay this drive resides */ + u32 rpm; /* Drive rotational speed in rpm */ + u8 device_type; /* type of drive */ + u8 sata_version; /* only valid when drive_type is SATA */ + u64 big_total_block_count; + u64 ris_starting_lba; + u32 ris_size; + u8 wwid[20]; + u8 controller_phy_map[32]; + u16 phy_count; + u8 phy_connected_dev_type[256]; + u8 phy_to_drive_bay_num[256]; + u16 phy_to_attached_dev_index[256]; + u8 box_index; + u8 reserved; + u16 extra_physical_drive_flags; +#define BMIC_PHYS_DRIVE_SUPPORTS_GAS_GAUGE(idphydrv) \ + (idphydrv->extra_physical_drive_flags & (1 << 10)) + u8 negotiated_link_rate[256]; + u8 phy_to_phy_map[256]; + u8 redundant_path_present_map; + u8 redundant_path_failure_map; + u8 active_path_number; + u16 alternate_paths_phys_connector[8]; + u8 alternate_paths_phys_box_on_port[8]; + u8 multi_lun_device_lun_count; + u8 minimum_good_fw_revision[8]; + u8 unique_inquiry_bytes[20]; + u8 current_temperature_degreesC; + u8 temperature_threshold_degreesC; + u8 max_temperature_degreesC; + u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512 * 2^exp */ + u16 current_queue_depth_limit; + u8 switch_name[10]; + u16 switch_port; + u8 alternate_paths_switch_name[40]; + u8 alternate_paths_switch_port[8]; + u16 power_on_hours; /* valid only if gas gauge supported */ + u16 percent_endurance_used; /* valid only if gas gauge supported. */ +#define BMIC_PHYS_DRIVE_SSD_WEAROUT(idphydrv) \ + ((idphydrv->percent_endurance_used & 0x80) || \ + (idphydrv->percent_endurance_used > 10000)) + u8 drive_authentication; +#define BMIC_PHYS_DRIVE_AUTHENTICATED(idphydrv) \ + (idphydrv->drive_authentication == 0x80) + u8 smart_carrier_authentication; +#define BMIC_SMART_CARRIER_AUTHENTICATION_SUPPORTED(idphydrv) \ + (idphydrv->smart_carrier_authentication != 0x0) +#define BMIC_SMART_CARRIER_AUTHENTICATED(idphydrv) \ + (idphydrv->smart_carrier_authentication == 0x01) + u8 smart_carrier_app_fw_version; + u8 smart_carrier_bootloader_fw_version; + u8 encryption_key_name[64]; + u32 misc_drive_flags; + u16 dek_index; + u8 padding[112]; +}; + #pragma pack() #endif /* HPSA_CMD_H */ From 9bbcda67bd38027ca5a860df6e101a7723692ac2 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:00:53 -0500 Subject: [PATCH 073/889] hpsa: get queue depth for physical devices Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 41 ++++++++++++++++++++++++++++++++++------- drivers/scsi/hpsa.h | 1 + 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 45f14004c27872..b57c10195895c6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1698,10 +1698,14 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(&h->devlock, flags); sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); - if (sd && (sd->expose_state & HPSA_SCSI_ADD)) + if (sd && (sd->expose_state & HPSA_SCSI_ADD)) { sdev->hostdata = sd; - else + if (sd->queue_depth) + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), + sd->queue_depth); + } else { sdev->hostdata = NULL; + } spin_unlock_irqrestore(&h->devlock, flags); return 0; } @@ -3317,6 +3321,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) */ struct ReportExtendedLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; + struct bmic_identify_physical_device *id_phys = NULL; u32 nphysicals = 0; u32 nlogicals = 0; u32 ndev_allocated = 0; @@ -3324,6 +3329,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) int ncurrent = 0; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; + u8 bmic_bus; + u8 bmic_lev_two_tgt; + u16 bmic_drive_number; int rescan_hba_mode; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); @@ -3331,8 +3339,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); + id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); - if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { + if (!currentsd || !physdev_list || !logdev_list || + !tmpdevice || !id_phys) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } @@ -3463,9 +3473,28 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) } if (h->transMethod & CFGTBL_Trans_io_accel1 || h->transMethod & CFGTBL_Trans_io_accel2) { + int rc; + memcpy(&this_device->ioaccel_handle, &lunaddrbytes[20], sizeof(this_device->ioaccel_handle)); + bmic_bus = lunaddrbytes[7] & 0x3F; + bmic_lev_two_tgt = lunaddrbytes[6]; + bmic_drive_number = ((bmic_bus - 1) << 8) + + bmic_lev_two_tgt; + + memset(id_phys, 0, sizeof(*id_phys)); + rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, + bmic_drive_number, id_phys, + sizeof(*id_phys)); + if (!rc) + /* Reserve space for FW operations */ +#define DRIVE_CMDS_RESERVED_FOR_FW 2 + this_device->queue_depth = + le16_to_cpu(id_phys->current_queue_depth_limit) - + DRIVE_CMDS_RESERVED_FOR_FW; + else + this_device->queue_depth = 7; /* conservative */ ncurrent++; } break; @@ -3501,6 +3530,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) kfree(currentsd); kfree(physdev_list); kfree(logdev_list); + kfree(id_phys); } /* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci @@ -4630,10 +4660,7 @@ static int hpsa_register_scsi(struct ctlr_info *h) HPSA_CMDS_RESERVED_FOR_ABORTS - HPSA_CMDS_RESERVED_FOR_DRIVER - HPSA_MAX_CONCURRENT_PASSTHRUS; - if (h->hba_mode_enabled) - sh->cmd_per_lun = 7; - else - sh->cmd_per_lun = sh->can_queue; + sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 42ddd998a8584b..e9e6954fe188e4 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -46,6 +46,7 @@ struct hpsa_scsi_dev_t { unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ + u16 queue_depth; u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ From 684179423666894aeebda09eb77d89ec5cc5a009 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:53 -0500 Subject: [PATCH 074/889] hpsa: honor queue depth of physical devices When using the ioaccel submission methods, requests destined for RAID volumes are sometimes diverted to physical devices. The OS has no or limited knowledge of these physical devices, so it is up to the driver to avoid pushing the device too hard. It is better to honor the physical device queue limit rather than making the device spew zillions of TASK SET FULL responses. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 ++++++++++++++ drivers/scsi/hpsa.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b57c10195895c6..9925fe3c26a9e6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1703,6 +1703,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) if (sd->queue_depth) scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), sd->queue_depth); + atomic_set(&sd->ioaccel_cmds_out, 0); } else { sdev->hostdata = NULL; } @@ -1912,6 +1913,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + atomic_dec(&dev->ioaccel_cmds_out); + /* check for good status */ if (likely(c2->error_data.serv_response == 0 && c2->error_data.status == 0)) { @@ -2012,6 +2015,7 @@ static void complete_scsi_command(struct CommandList *cp) */ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; + atomic_dec(&dev->ioaccel_cmds_out); cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; cp->Header.tag = c->tag; @@ -4421,6 +4425,13 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd->host_scribble = (unsigned char *) c; + /* Try to honor the device's queue depth */ + atomic_inc(&dev->ioaccel_cmds_out); + if (atomic_read(&dev->ioaccel_cmds_out) > dev->queue_depth) { + atomic_dec(&dev->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + if (dev->offload_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; @@ -4430,6 +4441,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); + atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { @@ -4441,9 +4453,11 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); + atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } + atomic_dec(&dev->ioaccel_cmds_out); return rc; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index e9e6954fe188e4..deb0944e7096bd 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -47,6 +47,10 @@ struct hpsa_scsi_dev_t { unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ u16 queue_depth; + atomic_t ioaccel_cmds_out; /* Only used for physical devices + * counts commands sent to physical + * device via "ioaccel" path. + */ u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ From 34d895a7e7cf68a1edb224fc315ddd4283628c38 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:54 -0500 Subject: [PATCH 075/889] hpsa: use cancel_delayed_work_sync where needed Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9925fe3c26a9e6..5e239f6c1039b4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7487,8 +7487,8 @@ static void hpsa_remove_one(struct pci_dev *pdev) /* Get rid of any controller monitoring work items */ spin_lock_irqsave(&h->lock, flags); h->remove_in_progress = 1; - cancel_delayed_work(&h->monitor_ctlr_work); - cancel_delayed_work(&h->rescan_ctlr_work); + cancel_delayed_work_sync(&h->monitor_ctlr_work); + cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); From 8134a109bf2ef646431d79f2df6cc493c1dba166 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:54 -0500 Subject: [PATCH 076/889] hpsa: clean up queue depth getting code This patch should be squashed with previous patch before sending upstream --- drivers/scsi/hpsa.c | 52 +++++++++++++++++++++-------------------- drivers/scsi/hpsa_cmd.h | 4 ++++ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5e239f6c1039b4..900883200781c6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3311,6 +3311,31 @@ static int hpsa_hba_mode_enabled(struct ctlr_info *h) return hba_mode_enabled; } +/* get physical drive ioaccel handle and queue depth */ +void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev, + u8 *lunaddrbytes, + struct bmic_identify_physical_device *id_phys) +{ + int rc; + struct ext_report_lun_entry *rle = + (struct ext_report_lun_entry *) lunaddrbytes; + + dev->ioaccel_handle = rle->ioaccel_handle; + memset(id_phys, 0, sizeof(*id_phys)); + rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, + GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, + sizeof(*id_phys)); + if (!rc) + /* Reserve space for FW operations */ +#define DRIVE_CMDS_RESERVED_FOR_FW 2 + dev->queue_depth = + le16_to_cpu(id_phys->current_queue_depth_limit) - + DRIVE_CMDS_RESERVED_FOR_FW; + else + dev->queue_depth = 7; /* conservative */ +} + static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) { /* the idea here is we could get notified @@ -3333,9 +3358,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) int ncurrent = 0; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; - u8 bmic_bus; - u8 bmic_lev_two_tgt; - u16 bmic_drive_number; int rescan_hba_mode; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); @@ -3477,28 +3499,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) } if (h->transMethod & CFGTBL_Trans_io_accel1 || h->transMethod & CFGTBL_Trans_io_accel2) { - int rc; - - memcpy(&this_device->ioaccel_handle, - &lunaddrbytes[20], - sizeof(this_device->ioaccel_handle)); - bmic_bus = lunaddrbytes[7] & 0x3F; - bmic_lev_two_tgt = lunaddrbytes[6]; - bmic_drive_number = ((bmic_bus - 1) << 8) + - bmic_lev_two_tgt; - - memset(id_phys, 0, sizeof(*id_phys)); - rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, - bmic_drive_number, id_phys, - sizeof(*id_phys)); - if (!rc) - /* Reserve space for FW operations */ -#define DRIVE_CMDS_RESERVED_FOR_FW 2 - this_device->queue_depth = - le16_to_cpu(id_phys->current_queue_depth_limit) - - DRIVE_CMDS_RESERVED_FOR_FW; - else - this_device->queue_depth = 7; /* conservative */ + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); ncurrent++; } break; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 84f0e5395c0158..7df234649ce5a8 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -250,6 +250,10 @@ struct ReportLUNdata { struct ext_report_lun_entry { u8 lunid[8]; #define MASKED_DEVICE(x) ((x)[3] & 0xC0) +#define GET_BMIC_BUS(lunid) ((lunid)[7] & 0x3F) +#define GET_BMIC_LEVEL_TWO_TARGET(lunid) ((lunid)[6]) +#define GET_BMIC_DRIVE_NUMBER(lunid) (((GET_BMIC_BUS((lunid)) - 1) << 8) + \ + GET_BMIC_LEVEL_TWO_TARGET((lunid))) u8 wwid[8]; u8 device_type; u8 device_flags; From 7ad122847e4a032a2abe703ae4f0e5933b72b04e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:55 -0500 Subject: [PATCH 077/889] hpsa: try to fix ioaccel command accounting code Need to count ioaccel commands to physical disks for RAID volumes not for logical disks. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 112 ++++++++++++++++++++++++++++++++-------- drivers/scsi/hpsa.h | 10 ++++ drivers/scsi/hpsa_cmd.h | 10 ++++ 3 files changed, 110 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 900883200781c6..1b5c8c7da0e5ae 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -245,7 +245,7 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h); static void hpsa_flush_cache(struct ctlr_info *h); static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr); + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk); static void hpsa_command_resubmit_worker(struct work_struct *work); static void print_cfg_table(struct device *dev, struct CfgTable *tb); @@ -1499,6 +1499,60 @@ static void hpsa_show_volume_status(struct ctlr_info *h, } } +/* Figure the list of physical drive pointers for a logical drive with + * raid offload configured. + */ +static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices, + struct hpsa_scsi_dev_t *logical_drive) +{ + struct raid_map_data *map = &logical_drive->raid_map; + struct raid_map_disk_data *dd = &map->data[0]; + int i, j; + int nraid_map_entries = logical_drive->raid_map.data_disks_per_row + + logical_drive->raid_map.metadata_disks_per_row; + + for (i = 0; i < nraid_map_entries; i++) { + logical_drive->phys_disk[i] = NULL; + if (!logical_drive->offload_config) + continue; + for (j = 0; j < ndevices; j++) { + if (dev[j]->devtype != TYPE_DISK) + continue; + if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) + continue; + if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { + logical_drive->phys_disk[i] = dev[j]; + break; + } + } + + /* + * This can happen if a physical drive is removed and + * the logical drive is degraded. In that case, the RAID + * map data will refer to a physical disk which isn't actually + * present. And in that case offload_enabled should already + * be 0, but we'll turn it off here just in case + */ + if (!logical_drive->phys_disk[i]) + logical_drive->offload_enabled = 0; + } +} + +static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices) +{ + int i; + + for (i = 0; i < ndevices; i++) { + if (dev[i]->devtype != TYPE_DISK) + continue; + if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) + continue; + hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]); + } +} + static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, struct hpsa_scsi_dev_t *sd[], int nsds) { @@ -1913,7 +1967,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - atomic_dec(&dev->ioaccel_cmds_out); + atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ if (likely(c2->error_data.serv_response == 0 && @@ -2015,7 +2069,7 @@ static void complete_scsi_command(struct CommandList *cp) */ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; - atomic_dec(&dev->ioaccel_cmds_out); + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; cp->Header.tag = c->tag; @@ -3528,6 +3582,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } + hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent); adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); @@ -3651,7 +3706,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex]; @@ -3679,9 +3734,18 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, (c->cmdindex * sizeof(*cp)); BUG_ON(c->busaddr & 0x0000007F); + /* Try to honor the device's queue depth */ + atomic_inc(&phys_disk->ioaccel_cmds_out); + if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { last_sg = scsi_sg_count(cmd) - 1; @@ -3742,7 +3806,7 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, - cmd->cmnd, cmd->cmd_len, dev->scsi3addr); + cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } /* @@ -3869,7 +3933,7 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -3894,9 +3958,18 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, memset(cp, 0, sizeof(*cp)); cp->IU_type = IOACCEL2_IU_TYPE; + /* Try to honor the device's queue depth */ + atomic_inc(&phys_disk->ioaccel_cmds_out); + if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES); @@ -3962,14 +4035,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, */ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { if (h->transMethod & CFGTBL_Trans_io_accel1) return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); else return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); } static void raid_map_helper(struct raid_map_data *map, @@ -4265,6 +4340,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; } + c->phys_disk = dev->phys_disk[map_index]; + disk_handle = dd[map_index].ioaccel_handle; disk_block = map->disk_starting_blk + (first_row * map->strip_size) + (first_row_offset - (first_column * map->strip_size)); @@ -4310,7 +4387,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, cdb_len = 10; } return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len, - dev->scsi3addr); + dev->scsi3addr, + dev->phys_disk[map_index]); } /* Submit commands down the "normal" RAID stack path */ @@ -4427,13 +4505,6 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd->host_scribble = (unsigned char *) c; - /* Try to honor the device's queue depth */ - atomic_inc(&dev->ioaccel_cmds_out); - if (atomic_read(&dev->ioaccel_cmds_out) > dev->queue_depth) { - atomic_dec(&dev->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } - if (dev->offload_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; @@ -4443,7 +4514,6 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); - atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { @@ -4455,11 +4525,9 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); - atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } - atomic_dec(&dev->ioaccel_cmds_out); return rc; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index deb0944e7096bd..cff0aaf48229ba 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -64,6 +64,16 @@ struct hpsa_scsi_dev_t { #define HPSA_ULD_ATTACH 0x2 #define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) u8 expose_state; + + /* Pointers from logical drive map indices to the phys drives that + * make those logical drives. Note, multiple logical drives may + * share physical drives. You can have for instance 5 physical + * drives with 3 logical drives each using those same 5 physical + * disks. We need these pointers for counting i/o's out to physical + * devices in order to honor physical device queue depth limits. + */ + struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; + int nphysical_disks; }; struct reply_queue_buffer { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 7df234649ce5a8..0bbe7c1acb44b1 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -422,6 +422,16 @@ struct CommandList { struct completion *waiting; struct scsi_cmnd *scsi_cmd; struct work_struct work; + + /* For commands using either of the two "ioaccel" paths to + * bypass the RAID stack and go directly to the physical disk + * phys_disk is a pointer to the hpsa_scsi_dev_t to which the + * i/o is destined. We need to store that here because the command + * may potentially encounter TASK SET FULL and need to be resubmitted + * For "normal" i/o's not using the "ioaccel" paths, phys_disk is + * not used. + */ + struct hpsa_scsi_dev_t *phys_disk; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 6f3947b8721cd98ea867cb6159c547f953cdd6a5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:56 -0500 Subject: [PATCH 078/889] hpsa: fix hpsa_figure_phys_disk_ptrs to handle layout_map_count other than 1 Squash this patch with hpsa-try-to-fix-ioaccel-cmd-accounting-code at some point Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1b5c8c7da0e5ae..f213a10d656855 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1509,8 +1509,11 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, struct raid_map_data *map = &logical_drive->raid_map; struct raid_map_disk_data *dd = &map->data[0]; int i, j; - int nraid_map_entries = logical_drive->raid_map.data_disks_per_row + - logical_drive->raid_map.metadata_disks_per_row; + int nraid_map_entries = map->row_cnt * map->layout_map_count * + (map->data_disks_per_row + map->metadata_disks_per_row); + + if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) + nraid_map_entries = RAID_MAP_MAX_ENTRIES; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; From c3b56c377dda672110b5aebf942f9f23a3b6ff8c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:56 -0500 Subject: [PATCH 079/889] hpsa: close race in ioaccel_cmds_out accounting Squash this patch into hpsa-try-to-fix-ioaccel-cmd-accounting-code eventually. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f213a10d656855..9cd6c69aca97ca 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3391,6 +3391,7 @@ void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, DRIVE_CMDS_RESERVED_FOR_FW; else dev->queue_depth = 7; /* conservative */ + atomic_set(&dev->ioaccel_cmds_out, 0); } static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) @@ -3738,8 +3739,8 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, BUG_ON(c->busaddr & 0x0000007F); /* Try to honor the device's queue depth */ - atomic_inc(&phys_disk->ioaccel_cmds_out); - if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; } @@ -3962,8 +3963,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, cp->IU_type = IOACCEL2_IU_TYPE; /* Try to honor the device's queue depth */ - atomic_inc(&phys_disk->ioaccel_cmds_out); - if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; } From 47ca4cc9bb61813054cd3122b6c5d0a9a058ea0c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:57 -0500 Subject: [PATCH 080/889] hpsa: guard against overflowing raid map array In the code that translates logical drive LBAs to physical drive LBAs if we overflow the raid map disk data array we will get the wrong answers. We do not expect that to happen, but best to be on the safe side and guard against it anyway. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9cd6c69aca97ca..307e9fecafd1eb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4344,6 +4344,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; } + if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES)) + return IO_ACCEL_INELIGIBLE; + c->phys_disk = dev->phys_disk[map_index]; disk_handle = dd[map_index].ioaccel_handle; From 783f4f18ee1d363e26563b1f61c53d5d8cfd2bb0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:57 -0500 Subject: [PATCH 081/889] hpsa: test ioaccel_cmds_out vs. queue depth earlier to avoid wasting time Squash this patch with hpsa-try-to-fix-ioaccel-cmd-accounting-code at some point Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 307e9fecafd1eb..5610aeaa52196b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3723,13 +3723,17 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE; /* TODO: implement chaining support */ - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX); - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } c->cmd_type = CMD_IOACCEL1; @@ -3738,13 +3742,6 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, (c->cmdindex * sizeof(*cp)); BUG_ON(c->busaddr & 0x0000007F); - /* Try to honor the device's queue depth */ - if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > - phys_disk->queue_depth) { - atomic_dec(&phys_disk->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } - use_sg = scsi_dma_map(cmd); if (use_sg < 0) { atomic_dec(&phys_disk->ioaccel_cmds_out); @@ -3948,11 +3945,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, u32 len; u32 total_len = 0; - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } + c->cmd_type = CMD_IOACCEL2; /* Adjust the DMA address to point to the accelerated command buffer */ c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle + @@ -3962,13 +3964,6 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, memset(cp, 0, sizeof(*cp)); cp->IU_type = IOACCEL2_IU_TYPE; - /* Try to honor the device's queue depth */ - if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > - phys_disk->queue_depth) { - atomic_dec(&phys_disk->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } - use_sg = scsi_dma_map(cmd); if (use_sg < 0) { atomic_dec(&phys_disk->ioaccel_cmds_out); @@ -4041,6 +4036,12 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { + /* Try to honor the device's queue depth */ + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } if (h->transMethod & CFGTBL_Trans_io_accel1) return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle, cdb, cdb_len, scsi3addr, From 0eadbc8e23826832252b571e0f21a584dcbbed37 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:58 -0500 Subject: [PATCH 082/889] hpsa: fix missing atomic_dec of dev->ioaccel_cmds_out Merge with earlier patches before submitting Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5610aeaa52196b..a91907da069962 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2062,6 +2062,8 @@ static void complete_scsi_command(struct CommandList *cp) scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { + if (cp->cmd_type == CMD_IOACCEL1) + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); cmd_free(h, cp); cmd->scsi_done(cmd); return; From dfa78853fbda0fc06f2cab881aa357b44473800c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:58 -0500 Subject: [PATCH 083/889] hpsa: do not ack controller events on controllers that do not support it Doing so can cause such controllers to lock up. Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a91907da069962..4a388e2e82cdac 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7185,6 +7185,9 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) int i; char *event_type; + if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) + return; + /* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) && From 53d7ee83c34873d0e80dabf47eff4d4baa7eed87 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:00:59 -0500 Subject: [PATCH 084/889] hpsa: fix code that updates h->dev[]->phys_disk[] h->dev[]->phys_disk[] contains a map of the physical disks that make up each logical drive. When a RAID migration occurs, this map can change for a logical drive. We need to make sure it gets updated in a consistent way and that this mapping is not used until after it is finished being updated. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 26 +++++++++++++++++++++++--- drivers/scsi/hpsa.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4a388e2e82cdac..deaf66239f6ec7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1161,6 +1161,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, h->dev[n] = device; h->ndevices++; + device->offload_to_be_enabled = device->offload_enabled; + device->offload_enabled = 0; added[*nadded] = device; (*nadded)++; @@ -1200,11 +1202,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, */ h->dev[entry]->raid_map = new_entry->raid_map; h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; - wmb(); /* ensure raid map updated prior to ->offload_enabled */ } h->dev[entry]->offload_config = new_entry->offload_config; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; - h->dev[entry]->offload_enabled = new_entry->offload_enabled; + + /* We can turn off ioaccel offload now, but need to delay turning + * it on until we can update h->dev[entry]->phys_disk[], but we + * can't do that until all the devices are updated. + */ + h->dev[entry]->offload_to_be_enabled = new_entry->offload_enabled; + if (!new_entry->offload_enabled) + h->dev[entry]->offload_enabled = 0; dev_info(&h->pdev->dev, "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", @@ -1239,6 +1247,8 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, new_entry->lun = h->dev[entry]->lun; } + new_entry->offload_to_be_enabled = new_entry->offload_enabled; + new_entry->offload_enabled = 0; h->dev[entry] = new_entry; added[*nadded] = new_entry; (*nadded)++; @@ -1659,6 +1669,14 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* but if it does happen, we just ignore that device */ } } + hpsa_update_log_drive_phys_drive_ptrs(h, h->dev, h->ndevices); + + /* Now that h->dev[]->phys_disk[] is coherent, we can enable + * any logical drives that need it enabled. + */ + for (i = 0; i < h->ndevices; i++) + h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled; + spin_unlock_irqrestore(&h->devlock, flags); /* Monitor devices which are in one of several NOT READY states to be @@ -2773,6 +2791,7 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h, this_device->offload_config = 0; this_device->offload_enabled = 0; + this_device->offload_to_be_enabled = 0; buf = kzalloc(64, GFP_KERNEL); if (!buf) @@ -2796,6 +2815,7 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h, if (hpsa_get_raid_map(h, scsi3addr, this_device)) this_device->offload_enabled = 0; } + this_device->offload_to_be_enabled = this_device->offload_enabled; out: kfree(buf); return; @@ -3100,6 +3120,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->raid_level = RAID_UNKNOWN; this_device->offload_config = 0; this_device->offload_enabled = 0; + this_device->offload_to_be_enabled = 0; this_device->volume_offline = 0; } @@ -3588,7 +3609,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } - hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent); adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index cff0aaf48229ba..4feb728d7ce404 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -54,6 +54,7 @@ struct hpsa_scsi_dev_t { u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ + int offload_to_be_enabled; int offload_to_mirror; /* Send next I/O accelerator RAID * offload request to mirror drive */ From 608e49039e594a9735b6e977bd712bdfac0a6e84 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:00 -0500 Subject: [PATCH 085/889] hpsa: use ioaccel2 path to submit IOs to physical drives in HBA mode. Signed-off-by: Joe Handzik --- drivers/scsi/hpsa.c | 10 +++++++++- drivers/scsi/hpsa.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index deaf66239f6ec7..7695e50c98fc74 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1203,6 +1203,11 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->raid_map = new_entry->raid_map; h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; } + if (new_entry->hba_ioaccel_enabled) { + h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; + wmb(); /* set ioaccel_handle *before* hba_ioaccel_eanbled */ + } + h->dev[entry]->hba_ioaccel_enabled = new_entry->hba_ioaccel_enabled; h->dev[entry]->offload_config = new_entry->offload_config; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; @@ -3121,6 +3126,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->offload_config = 0; this_device->offload_enabled = 0; this_device->offload_to_be_enabled = 0; + this_device->hba_ioaccel_enabled = 0; this_device->volume_offline = 0; } @@ -3402,6 +3408,8 @@ void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, (struct ext_report_lun_entry *) lunaddrbytes; dev->ioaccel_handle = rle->ioaccel_handle; + if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle) + dev->hba_ioaccel_enabled = 1; memset(id_phys, 0, sizeof(*id_phys)); rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, @@ -4546,7 +4554,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } - } else if (dev->ioaccel_handle) { + } else if (dev->hba_ioaccel_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 4feb728d7ce404..50523dbb9f71f7 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -55,6 +55,7 @@ struct hpsa_scsi_dev_t { int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ int offload_to_be_enabled; + int hba_ioaccel_enabled; int offload_to_mirror; /* Send next I/O accelerator RAID * offload request to mirror drive */ From baccc636c1d32ecf9087b659cd947b1221a4327a Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:00 -0500 Subject: [PATCH 086/889] hpsa: remove incorrect BUG_ONs checking for raid offload enable In set_encrypt_ioaccel2() and in hpsa_scsi_ioaccel_raid_map there were BUG_ONs that looked like this: BUG_ON(!(dev->offload_config && dev->offload_enabled)); But, In hpsa_ack_ctlr_events() we have this, /* Stop sending new RAID offload reqs via the IO accelerator */ scsi_block_requests(h->scsi_host); for (i = 0; i < h->ndevices; i++) h->dev[i]->offload_enabled = 0; hpsa_drain_accel_commands(h); So, we set offload_enabled = 0 for all drives, then do this drain_accel_commands, so that means accel commands could still be in flight, ie. perhaps having just been submitted into hpsa_scsi_ioaccel_raid_map concurrent with ->offload_enabled having just been set to zero. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7695e50c98fc74..2d7ef0a6f21772 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3851,8 +3851,6 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, struct raid_map_data *map = &dev->raid_map; u64 first_block; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* Are we doing encryption on this device */ if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON)) return; @@ -4144,8 +4142,6 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, #endif int offload_to_mirror; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* check for valid opcode, get LBA and block count */ switch (cmd->cmnd[0]) { case WRITE_6: From 23c47399566d77e810d18409d4e7eece16f49a7c Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:01 -0500 Subject: [PATCH 087/889] hpsa: Get queue depth from identify physical bmic for physical disks. Signed-off-by: Joe Handzik --- drivers/scsi/hpsa.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2d7ef0a6f21772..d00459acb2d3f7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3570,28 +3570,21 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; case TYPE_DISK: - if (h->hba_mode_enabled) { - /* never use raid mapper in HBA mode */ - this_device->offload_enabled = 0; + if (i >= nphysicals) { ncurrent++; break; - } else if (h->acciopath_status) { - if (i >= nphysicals) { - ncurrent++; - break; - } - } else { - if (i < nphysicals) - break; - ncurrent++; - break; - } - if (h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2) { - hpsa_get_ioaccel_drive_info(h, this_device, - lunaddrbytes, id_phys); - ncurrent++; } + + if (h->hba_mode_enabled) + /* never use raid mapper in HBA mode */ + this_device->offload_enabled = 0; + else if (!(h->transMethod & CFGTBL_Trans_io_accel1 || + h->transMethod & CFGTBL_Trans_io_accel2)) + break; + + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); + ncurrent++; break; case TYPE_TAPE: case TYPE_MEDIUM_CHANGER: From 61626ff666958fc12b86b79354ac8ed26667e209 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:01 -0500 Subject: [PATCH 088/889] hpsa: add ioaccel sg chaining for the ioaccel2 path Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 113 ++++++++++++++++++++++++++++++++++++++++---- drivers/scsi/hpsa.h | 1 + 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d00459acb2d3f7..ced3b959c0845e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1813,6 +1813,46 @@ static void hpsa_slave_destroy(struct scsi_device *sdev) /* nothing to do. */ } +static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h) +{ + int i; + + if (!h->ioaccel2_cmd_sg_list) + return; + for (i = 0; i < h->nr_cmds; i++) { + kfree(h->ioaccel2_cmd_sg_list[i]); + h->ioaccel2_cmd_sg_list[i] = NULL; + } + kfree(h->ioaccel2_cmd_sg_list); + h->ioaccel2_cmd_sg_list = NULL; +} + +static int hpsa_allocate_ioaccel2_sg_chain_blocks(struct ctlr_info *h) +{ + int i; + + if (h->chainsize <= 0) + return 0; + + h->ioaccel2_cmd_sg_list = + kzalloc(sizeof(*h->ioaccel2_cmd_sg_list) * h->nr_cmds, + GFP_KERNEL); + if (!h->ioaccel2_cmd_sg_list) + return -ENOMEM; + for (i = 0; i < h->nr_cmds; i++) { + h->ioaccel2_cmd_sg_list[i] = + kmalloc(sizeof(*h->ioaccel2_cmd_sg_list[i]) * + h->maxsgentries, GFP_KERNEL); + if (!h->ioaccel2_cmd_sg_list[i]) + goto clean; + } + return 0; + +clean: + hpsa_free_ioaccel2_sg_chain_blocks(h); + return -ENOMEM; +} + static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -1851,6 +1891,39 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) return -ENOMEM; } +static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h, + struct io_accel2_cmd *cp, struct CommandList *c) +{ + struct ioaccel2_sg_element *chain_block; + u64 temp64; + u32 chain_size; + + chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex]; + chain_size = le32_to_cpu(cp->data_len); + temp64 = pci_map_single(h->pdev, chain_block, chain_size, + PCI_DMA_TODEVICE); + if (dma_mapping_error(&h->pdev->dev, temp64)) { + /* prevent subsequent unmapping */ + cp->sg->address = 0; + return -1; + } + cp->sg->address = (u64) cpu_to_le64(temp64); + return 0; +} + +static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h, + struct io_accel2_cmd *cp) +{ + struct ioaccel2_sg_element *chain_sg; + u64 temp64; + u32 chain_size; + + chain_sg = cp->sg; + temp64 = le64_to_cpu(chain_sg->address); + chain_size = le32_to_cpu(cp->data_len); + pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE); +} + static int hpsa_map_sg_chain_block(struct ctlr_info *h, struct CommandList *c) { @@ -1993,6 +2066,9 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + if (c2->sg[0].chain_indicator == IOACCEL2_CHAIN) + hpsa_unmap_ioaccel2_sg_chain_block(h, c2); + atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ @@ -3966,10 +4042,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, u32 len; u32 total_len = 0; - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { - atomic_dec(&phys_disk->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } + BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); if (fixup_ioaccel_cdb(cdb, &cdb_len)) { atomic_dec(&phys_disk->ioaccel_cmds_out); @@ -3992,8 +4065,18 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } if (use_sg) { - BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES); curr_sg = cp->sg; + if (use_sg > h->ioaccel_maxsg) { + addr64 = h->ioaccel2_cmd_sg_list[c->cmdindex]->address; + curr_sg->address = cpu_to_le64(addr64); + curr_sg->length = 0; + curr_sg->reserved[0] = 0; + curr_sg->reserved[1] = 0; + curr_sg->reserved[2] = 0; + curr_sg->chain_indicator = 0x80; + + curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex]; + } scsi_for_each_sg(cmd, sg, use_sg, i) { addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); @@ -4038,14 +4121,23 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; memcpy(cp->cdb, cdb, sizeof(cp->cdb)); - /* fill in sg elements */ - cp->sg_count = (u8) use_sg; - cp->data_len = cpu_to_le32(total_len); cp->err_ptr = cpu_to_le64(c->busaddr + offsetof(struct io_accel2_cmd, error_data)); cp->err_len = cpu_to_le32((u32) sizeof(cp->error_data)); + /* fill in sg elements */ + if (use_sg > h->ioaccel_maxsg) { + cp->sg_count = 1; + if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + scsi_dma_unmap(cmd); + return -1; + } + } else { + cp->sg_count = (u8) use_sg; + } + enqueue_cmd_and_start_io(h, c); return 0; } @@ -7089,6 +7181,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_irqs_and_disable_msix(h); hpsa_free_sg_chain_blocks(h); + hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); kfree(h->ioaccel1_blockFetchTable); kfree(h->blockFetchTable); @@ -7598,6 +7691,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) iounmap(h->cfgtable); hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); + hpsa_free_ioaccel2_sg_chain_blocks(h); pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct CommandList), h->cmd_pool, h->cmd_pool_dhandle); @@ -7906,6 +8000,9 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) (h->ioaccel2_blockFetchTable == NULL)) goto clean_up; + if (hpsa_allocate_ioaccel2_sg_chain_blocks(h)) + goto clean_up; + memset(h->ioaccel2_cmd_pool, 0, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool)); return 0; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 50523dbb9f71f7..109e6e70ea5be0 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -162,6 +162,7 @@ struct ctlr_info { u8 max_cmd_sg_entries; int chainsize; struct SGDescriptor **cmd_sg_list; + struct ioaccel2_sg_element **ioaccel2_cmd_sg_list; /* pointers to command and error info pool */ struct CommandList *cmd_pool; From fee3f278ad533ccab3bc90dedde16aaba4da913b Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:02 -0500 Subject: [PATCH 089/889] Set the phys_disk value for a CommandList structure that is submitted. Squash this with an appropriate earlier patch when sent upstream. --- drivers/scsi/hpsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ced3b959c0845e..86886f231b3c71 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3905,6 +3905,8 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, struct scsi_cmnd *cmd = c->scsi_cmd; struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; + c->phys_disk = dev; + return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } From 6445c7a72d3ae1054056a02e6478d5c20e3263ac Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:03 -0500 Subject: [PATCH 090/889] hpsa: unmap ioaccel2 commands before, not after adding to resubmit workqueue The command could get thrown onto a work queue before we'd hit the unmap. Squash with the appropriate earlier patch (likely the larger scatter gather command support patch). Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 86886f231b3c71..38d9b72a6feea5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2066,9 +2066,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - if (c2->sg[0].chain_indicator == IOACCEL2_CHAIN) - hpsa_unmap_ioaccel2_sg_chain_block(h, c2); - atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ @@ -2137,6 +2134,7 @@ static void complete_scsi_command(struct CommandList *cp) struct ctlr_info *h; struct ErrorInfo *ei; struct hpsa_scsi_dev_t *dev; + struct io_accel2_cmd *c2; int sense_key; int asc; /* additional sense code */ @@ -2147,12 +2145,17 @@ static void complete_scsi_command(struct CommandList *cp) cmd = cp->scsi_cmd; h = cp->h; dev = cmd->device->hostdata; + c2 = &h->ioaccel2_cmd_pool[cp->cmdindex]; scsi_dma_unmap(cmd); /* undo the DMA mappings */ if ((cp->cmd_type == CMD_SCSI) && (cp->Header.SGTotal > h->max_cmd_sg_entries)) hpsa_unmap_sg_chain_block(h, cp); + if ((cp->cmd_type == CMD_IOACCEL2) && + (c2->sg[0].chain_indicator == IOACCEL2_CHAIN)) + hpsa_unmap_ioaccel2_sg_chain_block(h, c2); + cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ From ba29606b29deb4df1d2491272d0ad786e283f1cc Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:03 -0500 Subject: [PATCH 091/889] hpsa: add more ioaccel2 error handling, including underrun statuses. Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 ++++++++++++++++++++++++++++----- drivers/scsi/hpsa_cmd.h | 6 ++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 38d9b72a6feea5..78bb409cb3d8e7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1973,6 +1973,7 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, { int data_len; int retry = 0; + u32 ioaccel2_resid = 0; switch (c2->error_data.serv_response) { case IOACCEL2_SERV_RESPONSE_COMPLETE: @@ -2031,11 +2032,33 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, } break; case IOACCEL2_SERV_RESPONSE_FAILURE: - /* don't expect to get here. */ - dev_warn(&h->pdev->dev, - "unexpected delivery or target failure, status = 0x%02x\n", - c2->error_data.status); - retry = 1; + switch (c2->error_data.status) { + case IOACCEL2_STATUS_SR_IO_ERROR: + case IOACCEL2_STATUS_SR_IO_ABORTED: + case IOACCEL2_STATUS_SR_OVERRUN: + retry = 1; + break; + case IOACCEL2_STATUS_SR_UNDERRUN: + cmd->result = (DID_OK << 16); /* host byte */ + cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + ioaccel2_resid = c2->error_data.resid_cnt[3] << 24; + ioaccel2_resid |= c2->error_data.resid_cnt[2] << 16; + ioaccel2_resid |= c2->error_data.resid_cnt[1] << 8; + ioaccel2_resid |= c2->error_data.resid_cnt[0]; + scsi_set_resid(cmd, ioaccel2_resid); + break; + case IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE: + case IOACCEL2_STATUS_SR_INVALID_DEVICE: + case IOACCEL2_STATUS_SR_IOACCEL_DISABLED: + /* We will get an event from ctlr to trigger rescan */ + retry = 1; + break; + default: + retry = 1; + dev_warn(&h->pdev->dev, + "unexpected delivery or target failure, status = 0x%02x\n", + c2->error_data.status); + } break; case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: break; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 0bbe7c1acb44b1..2984d236fb888f 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -526,6 +526,12 @@ struct io_accel2_scsi_response { #define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28 #define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40 #define IOACCEL2_STATUS_SR_IOACCEL_DISABLED 0x0E +#define IOACCEL2_STATUS_SR_IO_ERROR 0x01 +#define IOACCEL2_STATUS_SR_IO_ABORTED 0x02 +#define IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE 0x03 +#define IOACCEL2_STATUS_SR_INVALID_DEVICE 0x04 +#define IOACCEL2_STATUS_SR_UNDERRUN 0x51 +#define IOACCEL2_STATUS_SR_OVERRUN 0x75 u8 data_present; /* low 2 bits */ #define IOACCEL2_NO_DATAPRESENT 0x000 #define IOACCEL2_RESPONSE_DATAPRESENT 0x001 From 6ee1a411cb1fdbd931bdaad5c53c81337cc3a5de Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:04 -0500 Subject: [PATCH 092/889] hpsa bump driver version again --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 78bb409cb3d8e7..543a7a97825a2f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.6-0" +#define HPSA_DRIVER_VERSION "3.4.8-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" From 076548df69b0948746a71dee682130902f2d0ed9 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:04 -0500 Subject: [PATCH 093/889] hpsa: do not check cmd_alloc return value - it cannnot return NULL cmd_alloc can no longer return NULL, so don't check for NULL any more (which is unreachable code). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 77 +++++++++------------------------------------ 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 543a7a97825a2f..bb4239ce556c1f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2582,11 +2582,6 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } - if (fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD)) { rc = -1; @@ -2616,11 +2611,6 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } - if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize, page, scsi3addr, TYPE_CMD)) { rc = -1; @@ -2638,7 +2628,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, out: cmd_free(h, c); return rc; - } +} static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, u8 reset_type) @@ -2648,10 +2638,6 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } /* fill_cmd can't fail here, no data buffer to map. */ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, @@ -2781,10 +2767,7 @@ static int hpsa_get_raid_map(struct ctlr_info *h, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } + if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { @@ -2957,10 +2940,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -1; - } + /* address the controller */ memset(scsi3addr, 0, sizeof(scsi3addr)); if (fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h, @@ -3074,8 +3054,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, #define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02 c = cmd_alloc(h); - if (!c) - return 0; + (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (rc) { @@ -3148,8 +3127,7 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, return 1; c = cmd_alloc(h); - if (!c) - return -ENOMEM; + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); /* no unmap needed here because no data xfer. */ @@ -4751,10 +4729,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } + if (unlikely(lockup_detected(h))) { cmd->result = DID_ERROR << 16; cmd_free(h, c); @@ -4923,11 +4898,6 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, struct CommandList *c; c = cmd_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "out of memory in " - "wait_for_device_to_become_ready.\n"); - return IO_ERROR; - } /* Send test unit ready until device ready, or give up. */ while (count < HPSA_TUR_RETRY_LIMIT) { @@ -5066,10 +5036,6 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, u32 tagupper, taglower; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } /* fill_cmd can't fail here, no buffer to map */ (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, @@ -5330,6 +5296,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track * which ones are free or in use. Lock must be held when calling this. * cmd_free() is the complement. + * This function never gives up and returns NULL. If it hangs, + * another thread must call cmd_free() to free some tags. */ static struct CommandList *cmd_alloc(struct ctlr_info *h) { @@ -5560,10 +5528,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) } } c = cmd_alloc(h); - if (c == NULL) { - rc = -ENOMEM; - goto out_kfree; - } + /* Fill in the command type */ c->cmd_type = CMD_IOCTL_PEND; /* Fill in Command Header */ @@ -5698,10 +5663,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) sg_used++; } c = cmd_alloc(h); - if (c == NULL) { - status = -ENOMEM; - goto cleanup1; - } + c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; c->Header.SGList = (u8) sg_used; @@ -5813,14 +5775,13 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) } } -static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, +static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, u8 reset_type) { struct CommandList *c; c = cmd_alloc(h); - if (!c) - return -ENOMEM; + /* fill_cmd can't fail here, no data buffer to map */ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, RAID_CTLR_LUNID, TYPE_MSG); @@ -5831,7 +5792,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, * the command either. This is the last command we will send before * re-initializing everything, so it doesn't matter and won't leak. */ - return 0; + return; } static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, @@ -7137,11 +7098,7 @@ static int hpsa_request_irq(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { - if (hpsa_send_host_reset(h, RAID_CTLR_LUNID, - HPSA_RESET_TYPE_CONTROLLER)) { - dev_warn(&h->pdev->dev, "Resetting array controller failed.\n"); - return -EIO; - } + hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { @@ -7651,10 +7608,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) return; c = cmd_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - goto out_of_memory; - } + if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, RAID_CTLR_LUNID, TYPE_CMD)) { goto out; @@ -7668,7 +7622,6 @@ static void hpsa_flush_cache(struct ctlr_info *h) dev_warn(&h->pdev->dev, "error flushing cache on controller\n"); cmd_free(h, c); -out_of_memory: kfree(flush_buf); } From c6aaee0f755ade7b60436e46e815a3e5843fd589 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:05 -0500 Subject: [PATCH 094/889] hpsa: return -1 rather than -ENOMEM in hpsa_get_raid_map if fill_cmd fails fill_cmd can only fail if pci_map_single fails. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bb4239ce556c1f..0fc4e1fd3ae9fd 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2771,9 +2771,9 @@ static int hpsa_get_raid_map(struct ctlr_info *h, if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { - dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - rc = -ENOMEM; - goto out; + dev_warn(&h->pdev->dev, "hpsa_get_raid_map fill_cmd failed\n"); + cmd_free(h, c); + return -1; } rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, NO_TIMEOUT); From 73b2576fd684d5fc40f1756002b8f15a4ea4719f Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:05 -0500 Subject: [PATCH 095/889] hpsa: return -ENOMEM not 1 from ioaccel2_alloc_cmds_and_bft on allocation failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0fc4e1fd3ae9fd..3592f1a5086d1e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7994,7 +7994,7 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); kfree(h->ioaccel2_blockFetchTable); - return 1; + return -ENOMEM; } static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) From 757810f0b125528c6e5acaab0056d523d01eceb3 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:06 -0500 Subject: [PATCH 096/889] hpsa: return -ENOMEM not 1 from hpsa_alloc_ioaccel_cmd_and_bft on allocation failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3592f1a5086d1e..60e07619fb5a60 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7954,7 +7954,7 @@ static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); kfree(h->ioaccel1_blockFetchTable); - return 1; + return -ENOMEM; } static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) From 39ac05b050d88cfe62be6ff746ed23864d5424c9 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:07 -0500 Subject: [PATCH 097/889] hpsa: return -ENOMEM not -EFAULT from hpsa_passthru_ioctl on kmalloc failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 60e07619fb5a60..660ebc720f11bc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5515,7 +5515,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) if (iocommand.buf_size > 0) { buff = kmalloc(iocommand.buf_size, GFP_KERNEL); if (buff == NULL) - return -EFAULT; + return -ENOMEM; if (iocommand.Request.Type.Direction & XFER_WRITE) { /* Copy the data into the buffer we created */ if (copy_from_user(buff, iocommand.buf, From a3371618b7fefa59d58bef50fd7a0b7b9d5c33e1 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:07 -0500 Subject: [PATCH 098/889] hpsa: pass error from pci_set_consistent_dma_mask intact from hpsa_message Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 660ebc720f11bc..48f63339212233 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6176,7 +6176,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { iounmap(vaddr); - return -ENOMEM; + return err; } cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64); From 3eb6e9b3ad2d9c1afe3c8b6e5aa5d9fe4e259595 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:08 -0500 Subject: [PATCH 099/889] hpsa: trivial message and comment clean ups Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 48f63339212233..f42077080e109f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6453,7 +6453,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become ready " + "Failed waiting for board to become ready " "after hard reset\n"); goto unmap_cfgtable; } @@ -6551,7 +6551,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) } /* If MSI/MSI-X is supported by the kernel we will try to enable it on - * controllers that are capable. If not, we use IO-APIC mode. + * controllers that are capable. If not, we use legacy INTx mode. */ static void hpsa_interrupt_mode(struct ctlr_info *h) @@ -6570,7 +6570,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - dev_info(&h->pdev->dev, "MSIX\n"); + dev_info(&h->pdev->dev, "MSI-X capable controller\n"); h->msix_vector = MAX_REPLY_QUEUES; if (h->msix_vector > num_online_cpus()) h->msix_vector = num_online_cpus(); @@ -6591,7 +6591,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) } single_msi_mode: if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { - dev_info(&h->pdev->dev, "MSI\n"); + dev_info(&h->pdev->dev, "MSI capable controller\n"); if (!pci_enable_msi(h->pdev)) h->msi_vector = 1; else @@ -6765,7 +6765,7 @@ static void hpsa_find_board_params(struct ctlr_info *h) static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) { if (!check_signature(h->cfgtable->Signature, "CISS", 4)) { - dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); + dev_err(&h->pdev->dev, "not a valid CISS config table\n"); return false; } return true; @@ -6857,7 +6857,7 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) h->transMethod = CFGTBL_Trans_Simple; return 0; error: - dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + dev_err(&h->pdev->dev, "failed to enter simple mode\n"); return -ENODEV; } @@ -7842,8 +7842,8 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { - dev_warn(&h->pdev->dev, "unable to get board into" - " performant mode\n"); + dev_err(&h->pdev->dev, + "performant mode problem - transport not active\n"); return; } /* Change the access methods to the performant access methods */ From d8b84fbc213c71efb9c1a80b390d58be543f846a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:08 -0500 Subject: [PATCH 100/889] hpsa: detect and report failures changing controller transport modes Detect failues when attempting to change controller to use simple or performant transport modes (mode change ack) rather than just proceeding ahead after timeouts. Return values are added to: hpsa_put_ctlr_into_performant_mode hpsa_wait_for_mode_change_ack and all their callers check/propagate the result. More consistency in printing errors and whether dev_err is used. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f42077080e109f..3168c36837cf08 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -238,7 +238,7 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr, int wait_for_ready); static inline void finish_cmd(struct CommandList *c); -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h); +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h); #define BOARD_NOT_READY 0 #define BOARD_READY 1 static void hpsa_drain_accel_commands(struct ctlr_info *h); @@ -488,7 +488,7 @@ static ssize_t host_store_hpsa_intcoal_delay(struct device *dev, writel(value, &h->cfgtable->HostWrite.CoalIntDelay); print_cfg_table(&h->pdev->dev, h->cfgtable); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + (void) hpsa_wait_for_mode_change_ack(h); print_cfg_table(&h->pdev->dev, h->cfgtable); return count; } @@ -515,7 +515,7 @@ static ssize_t host_store_hpsa_intcoal_count(struct device *dev, writel(value, &h->cfgtable->HostWrite.CoalIntCount); print_cfg_table(&h->pdev->dev, h->cfgtable); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + (void) hpsa_wait_for_mode_change_ack(h); print_cfg_table(&h->pdev->dev, h->cfgtable); return count; } @@ -6798,7 +6798,7 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } -static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) +static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6809,13 +6809,16 @@ static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) - break; + goto done; /* delay and try again */ msleep(20); } + return -ENODEV; +done: + return 0; } -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6830,12 +6833,16 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) - break; + goto done; /* delay and try again */ usleep_range(10000, 20000); } + return -ENODEV; +done: + return 0; } +/* return -ENODEV or other reason on error, 0 on success */ static int hpsa_enter_simple_mode(struct ctlr_info *h) { u32 trans_support; @@ -6850,7 +6857,8 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) + goto error; print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) goto error; @@ -7746,7 +7754,8 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) +/* return -ENODEV or other reason on error, 0 on success */ +static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) { int i; unsigned long register_value; @@ -7838,13 +7847,17 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - doorbell timeout\n"); + return -ENODEV; + } print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_err(&h->pdev->dev, "performant mode problem - transport not active\n"); - return; + return -ENODEV; } /* Change the access methods to the performant access methods */ h->access = access; @@ -7852,7 +7865,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) if (!((trans_support & CFGTBL_Trans_io_accel1) || (trans_support & CFGTBL_Trans_io_accel2))) - return; + return 0; if (trans_support & CFGTBL_Trans_io_accel1) { /* Set up I/O accelerator mode */ @@ -7914,8 +7927,13 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) writel(bft2[i], &h->ioaccel2_bft2_regs[i]); } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - enabling ioaccel mode\n"); + return -ENODEV; + } print_cfg_table(&h->pdev->dev, h->cfgtable); + return 0; } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) From 4c8e8b2b39f7fc58c9d94c7f270b27b118bd9577 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:09 -0500 Subject: [PATCH 101/889] hpsa: add hpsa_disable_interrupt_mode In preparation for cleaning up in case of irq allocation failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3168c36837cf08..996a342ed35439 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6550,10 +6550,22 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) return -1; } +static void hpsa_disable_interrupt_mode(struct ctlr_info *h) +{ +#ifdef CONFIG_PCI_MSI + if (h->msix_vector) { + if (h->pdev->msix_enabled) + pci_disable_msix(h->pdev); + } else if (h->msi_vector) { + if (h->pdev->msi_enabled) + pci_disable_msi(h->pdev); + } +#endif /* CONFIG_PCI_MSI */ +} + /* If MSI/MSI-X is supported by the kernel we will try to enable it on * controllers that are capable. If not, we use legacy INTx mode. */ - static void hpsa_interrupt_mode(struct ctlr_info *h) { #ifdef CONFIG_PCI_MSI From 8eaf72eb0718b9c3588371cdefb72a33ab123877 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:09 -0500 Subject: [PATCH 102/889] hpsa: rename free_irqs to hpsa_free_irqs and move before hpsa_request_irq Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 996a342ed35439..b394b4e7772de9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7076,6 +7076,25 @@ static void hpsa_irq_affinity_hints(struct ctlr_info *h) } } +/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */ +static void hpsa_free_irqs(struct ctlr_info *h) +{ + int i; + + if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { + /* Single reply queue, only one irq to free */ + i = h->intr_mode; + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + return; + } + + for (i = 0; i < h->msix_vector; i++) { + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + } +} + static int hpsa_request_irq(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) @@ -7136,27 +7155,9 @@ static int hpsa_kdump_soft_reset(struct ctlr_info *h) return 0; } -static void free_irqs(struct ctlr_info *h) -{ - int i; - - if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { - /* Single reply queue, only one irq to free */ - i = h->intr_mode; - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - return; - } - - for (i = 0; i < h->msix_vector; i++) { - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - } -} - static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) { - free_irqs(h); + hpsa_free_irqs(h); #ifdef CONFIG_PCI_MSI if (h->msix_vector) { if (h->pdev->msix_enabled) @@ -7539,7 +7540,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irqs(h); + hpsa_free_irqs(h); rc = hpsa_request_irq(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { @@ -7603,7 +7604,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - free_irqs(h); + hpsa_free_irqs(h); clean2: clean1: if (h->resubmit_wq) From 06b9dc45960e53bc3de8194403a1aff351e2e3db Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:10 -0500 Subject: [PATCH 103/889] hpsa: rename hpsa_request_irq to hpsa_request_irqs Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b394b4e7772de9..5d7d09cf52a9a0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7095,7 +7095,8 @@ static void hpsa_free_irqs(struct ctlr_info *h) } } -static int hpsa_request_irq(struct ctlr_info *h, +/* returns 0 on success; cleans up and returns -Enn on error */ +static int hpsa_request_irqs(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) { @@ -7504,7 +7505,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) + if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) goto clean2; dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, @@ -7541,7 +7542,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); hpsa_free_irqs(h); - rc = hpsa_request_irq(h, hpsa_msix_discard_completions, + rc = hpsa_request_irqs(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { dev_warn(&h->pdev->dev, From b34a2f01c1164642d6f674f8222300770f149b8d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:11 -0500 Subject: [PATCH 104/889] hpsa break hpsa_free_irqs_and_disable_msix into two functions replace calls to hpsa_free_irqs_and_disable_msix with two calls to hpsa_free_irqs and hpsa_disable_interrupt_mode Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5d7d09cf52a9a0..61fd342874cc41 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7156,20 +7156,6 @@ static int hpsa_kdump_soft_reset(struct ctlr_info *h) return 0; } -static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) -{ - hpsa_free_irqs(h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) { - if (h->pdev->msix_enabled) - pci_disable_msix(h->pdev); - } else if (h->msi_vector) { - if (h->pdev->msi_enabled) - pci_disable_msi(h->pdev); - } -#endif /* CONFIG_PCI_MSI */ -} - static void hpsa_free_reply_queues(struct ctlr_info *h) { int i; @@ -7186,7 +7172,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { - hpsa_free_irqs_and_disable_msix(h); + hpsa_free_irqs(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); @@ -7199,6 +7185,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) iounmap(h->transtable); if (h->cfgtable) iounmap(h->cfgtable); + hpsa_disable_interrupt_mode(h); pci_disable_device(h->pdev); pci_release_regions(h->pdev); kfree(h); @@ -7658,7 +7645,8 @@ static void hpsa_shutdown(struct pci_dev *pdev) */ hpsa_flush_cache(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); - hpsa_free_irqs_and_disable_msix(h); + hpsa_free_irqs(h); + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } static void hpsa_free_device_info(struct ctlr_info *h) @@ -7687,7 +7675,10 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ + + /* includes hpsa_free_irqs and hpsa_disable_interrupt_mode */ hpsa_shutdown(pdev); + destroy_workqueue(h->resubmit_wq); iounmap(h->vaddr); iounmap(h->transtable); From d2862635cd4fe212974fe85e59f12dabc665d4e1 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:11 -0500 Subject: [PATCH 105/889] hpsa: on failure of request_irq, free the irqs that we did get Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 61fd342874cc41..8fbefc1ad6ed45 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7129,8 +7129,9 @@ static int hpsa_request_irqs(struct ctlr_info *h, } } if (rc) { - dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", + dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", h->intr[h->intr_mode], h->devname); + hpsa_free_irqs(h); return -ENODEV; } return 0; From ef61147f977c3decf2a84ac0e05e4159673488bf Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:12 -0500 Subject: [PATCH 106/889] hpsa: make hpsa_pci_init disable interrupts and pci_disable_device on critical failures Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8fbefc1ad6ed45..88665d5bb86daf 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6909,17 +6909,18 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_request_regions(h->pdev, HPSA); if (err) { dev_err(&h->pdev->dev, - "cannot obtain PCI resources, aborting\n"); - return err; + "failed to obtain PCI resources\n"); + goto clean1; /* pci */ } hpsa_interrupt_mode(h); err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); if (err) - goto err_out_free_res; + goto clean2; /* intmode+region, pci */ h->vaddr = remap_pci_mem(h->paddr, 0x250); if (!h->vaddr) { + dev_err(&h->pdev->dev, "failed to remap PCI mem\n"); err = -ENOMEM; - goto err_out_free_res; + goto clean2; /* intmode+region, pci */ } err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); if (err) @@ -6947,8 +6948,11 @@ static int hpsa_pci_init(struct ctlr_info *h) iounmap(h->cfgtable); if (h->vaddr) iounmap(h->vaddr); - pci_disable_device(h->pdev); +clean2: + hpsa_disable_interrupt_mode(h); pci_release_regions(h->pdev); +clean1: + pci_disable_device(h->pdev); return err; } From c77cab6523ce08cd0926887d89d3c192f3890a7f Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:12 -0500 Subject: [PATCH 107/889] hpsa: avoid unneccesary calls to resource freeing functions in hpsa_init_one If hpsa_allocate_cmd_pool failed, we were calling two functions unnecessarily: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); This didn't cause any problem, as those functions can tolerate being called when what they free hasn't been allocated (relevant pointers would be NULL) but it is potentially confusing. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 88665d5bb86daf..f1eab7011d5a56 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7502,8 +7502,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - if (hpsa_allocate_cmd_pool(h)) - goto clean4; + rc = hpsa_allocate_cmd_pool(h); + if (rc) + goto clean2_and_free_irqs; if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); @@ -7597,6 +7598,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); +clean2_and_free_irqs: hpsa_free_irqs(h); clean2: clean1: From f19180625b8f641464658c0d2fb858230a3bf6d2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:13 -0500 Subject: [PATCH 108/889] hpsa: add hpsa_free_cfgtables function to undo what hpsa_find_cfgtables does Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f1eab7011d5a56..f4ad67f0cbbbd6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6696,6 +6696,15 @@ static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, return 0; } +static void hpsa_free_cfgtables(struct ctlr_info *h) +{ + iounmap(h->transtable); + iounmap(h->cfgtable); +} + +/* Find and map CISS config table and transfer table ++ * several items must be unmapped (freed) later ++ * */ static int hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; @@ -6720,8 +6729,11 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) h->transtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index)+cfg_offset+trans_offset, sizeof(*h->transtable)); - if (!h->transtable) + if (!h->transtable) { + dev_err(&h->pdev->dev, "Failed mapping transfer table\n"); + hpsa_free_cfgtables(h); return -ENOMEM; + } return 0; } @@ -7184,15 +7196,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) kfree(h->ioaccel1_blockFetchTable); kfree(h->blockFetchTable); hpsa_free_reply_queues(h); - if (h->vaddr) - iounmap(h->vaddr); - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - hpsa_disable_interrupt_mode(h); + hpsa_free_cfgtables(h); /* pci_init 4 */ + iounmap(h->vaddr); /* pci_init 3 */ + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ pci_disable_device(h->pdev); - pci_release_regions(h->pdev); + pci_release_regions(h->pdev); /* pci_init 2 */ kfree(h); } From d5e02173fd1d06cdcdb125ca567407689112c516 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:13 -0500 Subject: [PATCH 109/889] hpsa: report failure to ioremap config table Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f4ad67f0cbbbd6..7a85c1648efb20 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6719,8 +6719,10 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); - if (!h->cfgtable) + if (!h->cfgtable) { + dev_err(&h->pdev->dev, "Failed mapping cfgtable\n"); return -ENOMEM; + } rc = write_driver_ver_to_cfgtable(h->cfgtable); if (rc) return rc; From a3977b6070a75ad038d798d481ffe047d2fbaceb Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:14 -0500 Subject: [PATCH 110/889] hpsa: add hpsa_free_pci_init function In preparation for cleanup of error handling in hpsa_pci_init Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7a85c1648efb20..7a7d23d812e21d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6895,6 +6895,17 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) return -ENODEV; } +/* free items allocated or mapped by hpsa_pci_init */ +static void hpsa_free_pci_init(struct ctlr_info *h) +{ + hpsa_free_cfgtables(h); /* pci_init 4 */ + iounmap(h->vaddr); /* pci_init 3 */ + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ + pci_release_regions(h->pdev); /* pci_init 2 */ + pci_disable_device(h->pdev); /* pci_init 1 */ +} + +/* several items must be freed later */ static int hpsa_pci_init(struct ctlr_info *h) { int prod_index, err; From a916c3ee832613dcbb6fdb7022cde92f161c0f53 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:15 -0500 Subject: [PATCH 111/889] hpsa: clean up error handling in hpsa_pci_init Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7a7d23d812e21d..e89b7e618d4430 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6924,7 +6924,7 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_enable_device(h->pdev); if (err) { - dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); + dev_err(&h->pdev->dev, "failed to enable PCI device\n"); return err; } @@ -6949,34 +6949,31 @@ static int hpsa_pci_init(struct ctlr_info *h) } err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); if (err) - goto err_out_free_res; + goto clean3; /* vaddr, intmode+region, pci */ err = hpsa_find_cfgtables(h); if (err) - goto err_out_free_res; + goto clean3; /* vaddr, intmode+region, pci */ hpsa_find_board_params(h); if (!hpsa_CISS_signature_present(h)) { err = -ENODEV; - goto err_out_free_res; + goto clean4; /* cfgtables, vaddr, intmode+region, pci */ } hpsa_set_driver_support_bits(h); hpsa_p600_dma_prefetch_quirk(h); err = hpsa_enter_simple_mode(h); if (err) - goto err_out_free_res; + goto clean4; /* cfgtables, vaddr, intmode+region, pci */ return 0; -err_out_free_res: - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - if (h->vaddr) - iounmap(h->vaddr); -clean2: +clean4: /* cfgtables, vaddr, intmode+region, pci */ + hpsa_free_cfgtables(h); +clean3: /* vaddr, intmode+region, pci */ + iounmap(h->vaddr); +clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); pci_release_regions(h->pdev); -clean1: +clean1: /* pci */ pci_disable_device(h->pdev); return err; } @@ -7511,7 +7508,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean1; + goto clean2; } } @@ -7622,6 +7619,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean2_and_free_irqs: hpsa_free_irqs(h); clean2: + hpsa_free_pci_init(h); clean1: if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); From 0d35c517880f0be838fc9b12360f4646ab3b0211 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:15 -0500 Subject: [PATCH 112/889] hpsa: make hpsa_remove_one use hpsa_pci_free_init instead of individually releasing various things Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e89b7e618d4430..6bf30a80cb1e62 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7702,13 +7702,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ - /* includes hpsa_free_irqs and hpsa_disable_interrupt_mode */ + /* includes hpsa_free_irqs */ + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ hpsa_shutdown(pdev); destroy_workqueue(h->resubmit_wq); - iounmap(h->vaddr); - iounmap(h->transtable); - iounmap(h->cfgtable); hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); @@ -7724,8 +7722,10 @@ static void hpsa_remove_one(struct pci_dev *pdev) kfree(h->ioaccel1_blockFetchTable); kfree(h->ioaccel2_blockFetchTable); kfree(h->hba_inquiry_data); - pci_disable_device(pdev); - pci_release_regions(pdev); + + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ + hpsa_free_pci_init(h); + free_percpu(h->lockup_detected); kfree(h); } From 6261f51b8e8120959711e57f3aa56833d0fc2a1a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:16 -0500 Subject: [PATCH 113/889] hpsa: rename hpsa_alloc_ioaccel_cmd_and_bft to hpsa_alloc_ioaccel1_cmd_and_bft in order to differentiate it from hpsa_alloc_ioaccel2_cmd_and_bft Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6bf30a80cb1e62..48fd5b7ed0d87d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7967,7 +7967,8 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) return 0; } -static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) +/* Allocate ioaccel1 mode command blocks and block fetch table */ +static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) { h->ioaccel_maxsg = readl(&(h->cfgtable->io_accel_max_embedded_sg_count)); @@ -8064,7 +8065,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (trans_support & CFGTBL_Trans_io_accel1) { transMethod |= CFGTBL_Trans_io_accel1 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel_cmd_and_bft(h)) + if (hpsa_alloc_ioaccel1_cmd_and_bft(h)) goto clean_up; } else { if (trans_support & CFGTBL_Trans_io_accel2) { From 66bccd4e2fc293ad6cdb365ef53165b1ea9d9c07 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:16 -0500 Subject: [PATCH 114/889] hpsa: rename hpsa_allocate_cmd_pool to hpsa_alloc_cmd_pool Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 48fd5b7ed0d87d..a1ad05d5456cbe 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7048,7 +7048,7 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) return rc; } -static int hpsa_allocate_cmd_pool(struct ctlr_info *h) +static int hpsa_alloc_cmd_pool(struct ctlr_info *h) { h->cmd_pool_bits = kzalloc( DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * @@ -7520,7 +7520,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - rc = hpsa_allocate_cmd_pool(h); + rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean2_and_free_irqs; if (hpsa_allocate_sg_chain_blocks(h)) From 60a21d4c2a57c07bab392a02a85461a30bb70725 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:17 -0500 Subject: [PATCH 115/889] hpsa: rename ioaccel2_alloc_cmds_and_bft to hpsa_alloc_ioaccel2_cmd_and_bft Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a1ad05d5456cbe..90661a085322b2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8007,7 +8007,8 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } -static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) +/* Allocate ioaccel2 mode command blocks and block fetch table */ +static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { /* Allocate ioaccel2 mode command blocks and block fetch table */ @@ -8071,7 +8072,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (trans_support & CFGTBL_Trans_io_accel2) { transMethod |= CFGTBL_Trans_io_accel2 | CFGTBL_Trans_enable_directed_msix; - if (ioaccel2_alloc_cmds_and_bft(h)) + if (hpsa_alloc_ioaccel2_cmd_and_bft(h)) goto clean_up; } } From aafe3e50fab9e6e357d0a5b63f5c0b24fa718ba2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:18 -0500 Subject: [PATCH 116/889] hpsa: separate hpsa_free_cmd_pool into three separate function hpsa_free_cmd_pool to free the cmd_pool_bits and cmd_pool hpsa_free_ioaccel1_cmd_and_bft for the ioaccel1 stuff hpsa_free_ioaccel2_cmd_and_bft for the ioaccel2 stuff Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 95 +++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 90661a085322b2..0cea6f405aedd3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -228,6 +228,8 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); +static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, @@ -7048,6 +7050,20 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) return rc; } +static void hpsa_free_cmd_pool(struct ctlr_info *h) +{ + kfree(h->cmd_pool_bits); + if (h->cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct CommandList), + h->cmd_pool, h->cmd_pool_dhandle); + if (h->errinfo_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct ErrorInfo), + h->errinfo_pool, + h->errinfo_pool_dhandle); +} + static int hpsa_alloc_cmd_pool(struct ctlr_info *h) { h->cmd_pool_bits = kzalloc( @@ -7069,28 +7085,6 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h) return 0; } -static void hpsa_free_cmd_pool(struct ctlr_info *h) -{ - kfree(h->cmd_pool_bits); - if (h->cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - if (h->ioaccel2_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), - h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); - if (h->errinfo_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, - h->errinfo_pool_dhandle); - if (h->ioaccel_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct io_accel1_cmd), - h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); -} - static void hpsa_irq_affinity_hints(struct ctlr_info *h) { int i, cpu, rc; @@ -7203,9 +7197,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - kfree(h->ioaccel1_blockFetchTable); - kfree(h->blockFetchTable); - hpsa_free_reply_queues(h); + kfree(h->blockFetchTable); /* perf 2 */ + hpsa_free_reply_queues(h); /* perf 1 */ + hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ + hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ @@ -7616,6 +7611,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); clean2_and_free_irqs: hpsa_free_irqs(h); clean2: @@ -7710,17 +7707,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, h->errinfo_pool_dhandle); - hpsa_free_reply_queues(h); - kfree(h->cmd_pool_bits); - kfree(h->blockFetchTable); - kfree(h->ioaccel1_blockFetchTable); - kfree(h->ioaccel2_blockFetchTable); + kfree(h->blockFetchTable); /* perf 2 */ + hpsa_free_reply_queues(h); /* perf 1 */ + hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ + hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ kfree(h->hba_inquiry_data); /* includes hpsa_disable_interrupt_mode - pci_init 2 */ @@ -7967,6 +7958,16 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) return 0; } +/* Free ioaccel1 mode command blocks and block fetch table */ +static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h) +{ + if (h->ioaccel_cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), + h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); + kfree(h->ioaccel1_blockFetchTable); +} + /* Allocate ioaccel1 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) { @@ -7999,14 +8000,20 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) return 0; clean_up: - if (h->ioaccel_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), - h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); - kfree(h->ioaccel1_blockFetchTable); + hpsa_free_ioaccel1_cmd_and_bft(h); return -ENOMEM; } +/* Free ioaccel2 mode command blocks and block fetch table */ +static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) +{ + if (h->ioaccel2_cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), + h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); + kfree(h->ioaccel2_blockFetchTable); +} + /* Allocate ioaccel2 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { @@ -8040,11 +8047,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return 0; clean_up: - if (h->ioaccel2_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), - h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); - kfree(h->ioaccel2_blockFetchTable); + hpsa_free_ioaccel2_cmd_and_bft(h); return -ENOMEM; } From 79bf9411c54879721a4ea348894d9444274fc2bf Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:18 -0500 Subject: [PATCH 117/889] hpsa: fix memory leak in hpsa_alloc_cmd_pool Partial allocation failure wasn't handled correctly Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0cea6f405aedd3..cb4a5f23cee8c9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7079,10 +7079,13 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h) || (h->cmd_pool == NULL) || (h->errinfo_pool == NULL)) { dev_err(&h->pdev->dev, "out of memory in %s", __func__); - return -ENOMEM; + goto clean_up; } hpsa_preinitialize_commands(h); return 0; +clean_up: + hpsa_free_cmd_pool(h); + return -ENOMEM; } static void hpsa_irq_affinity_hints(struct ctlr_info *h) From dd6fee65d4a245a7b2dfe77e1c83c028028685a2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:19 -0500 Subject: [PATCH 118/889] hpsa: return status not void from hpsa_put_ctlr_into_performant_mode Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 55 ++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cb4a5f23cee8c9..f63925ab3ee5cb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -227,7 +227,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); @@ -8054,33 +8054,36 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) +/* return -ENODEV on error, 0 on success (or no action) + * allocates numerous items that must be freed later + */ +static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) { u32 trans_support; unsigned long transMethod = CFGTBL_Trans_Performant | CFGTBL_Trans_use_short_tags; - int i; + int i, rc; if (hpsa_simple_mode) - return; + return 0; trans_support = readl(&(h->cfgtable->TransportSupport)); if (!(trans_support & PERFORMANT_MODE)) - return; + return 0; /* Check for I/O accelerator mode support */ if (trans_support & CFGTBL_Trans_io_accel1) { transMethod |= CFGTBL_Trans_io_accel1 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel1_cmd_and_bft(h)) - goto clean_up; - } else { - if (trans_support & CFGTBL_Trans_io_accel2) { - transMethod |= CFGTBL_Trans_io_accel2 | + rc = hpsa_alloc_ioaccel1_cmd_and_bft(h); + if (rc) + return rc; + } else if (trans_support & CFGTBL_Trans_io_accel2) { + transMethod |= CFGTBL_Trans_io_accel2 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel2_cmd_and_bft(h)) - goto clean_up; - } + rc = hpsa_alloc_ioaccel2_cmd_and_bft(h); + if (rc) + return rc; } h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1; @@ -8092,8 +8095,10 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) h->reply_queue[i].head = pci_alloc_consistent(h->pdev, h->reply_queue_size, &(h->reply_queue[i].busaddr)); - if (!h->reply_queue[i].head) - goto clean_up; + if (!h->reply_queue[i].head) { + rc = -ENOMEM; + goto clean1; /* rq, ioaccel */ + } h->reply_queue[i].size = h->max_commands; h->reply_queue[i].wraparound = 1; /* spec: init to 1 */ h->reply_queue[i].current_entry = 0; @@ -8102,15 +8107,23 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) /* Need a block fetch table for performant mode */ h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * sizeof(u32)), GFP_KERNEL); - if (!h->blockFetchTable) - goto clean_up; + if (!h->blockFetchTable) { + rc = -ENOMEM; + goto clean1; /* rq, ioaccel */ + } - hpsa_enter_performant_mode(h, trans_support); - return; + rc = hpsa_enter_performant_mode(h, trans_support); + if (rc) + goto clean2; /* bft, rq, ioaccel */ + return 0; -clean_up: - hpsa_free_reply_queues(h); +clean2: /* bft, rq, ioaccel */ kfree(h->blockFetchTable); +clean1: /* rq, ioaccel */ + hpsa_free_reply_queues(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); + return rc; } static int is_accelerated_cmd(struct CommandList *c) From 067b964d63254425d76eabfebb60ff7633581e86 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:19 -0500 Subject: [PATCH 119/889] hpsa: clean up error handling in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f63925ab3ee5cb..06d943422fca8d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7478,19 +7478,19 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!h->resubmit_wq) { dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; - goto clean1; + goto clean1; /* aer/h */ } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { rc = -ENOMEM; - goto clean1; + goto clean1; /* wq/aer/h */ } set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); if (rc != 0) - goto clean1; + goto clean2; /* lockup, wq/aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); h->ctlr = number_of_controllers; @@ -7506,23 +7506,25 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean2; + goto clean3; /* pci, lockup, wq/aer/h */ } } /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) - goto clean2; + rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); + if (rc) + goto clean3; /* pci, lockup, wq/aer/h */ dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean2_and_free_irqs; - if (hpsa_allocate_sg_chain_blocks(h)) - goto clean4; + goto clean4; /* irq, pci, lockup, wq/aer/h */ + rc = hpsa_allocate_sg_chain_blocks(h); + if (rc) + goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ @@ -7532,7 +7534,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->hba_mode_enabled = 0; h->scsi_host = NULL; spin_lock_init(&h->devlock); - hpsa_put_ctlr_into_performant_mode(h); + rc = hpsa_put_ctlr_into_performant_mode(h); + if (rc) + goto clean6; /* sg, cmd, irq, pci, lockup, wq/aer/h */ /* At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -7611,20 +7615,20 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean4: - hpsa_free_sg_chain_blocks(h); +clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_cmd_pool(h); - hpsa_free_ioaccel1_cmd_and_bft(h); - hpsa_free_ioaccel2_cmd_and_bft(h); -clean2_and_free_irqs: +clean4: /* irq, pci, lockup, wq/aer/h */ hpsa_free_irqs(h); -clean2: +clean3: /* pci, lockup, wq/aer/h */ hpsa_free_pci_init(h); -clean1: - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); +clean2: /* lockup, wq/aer/h */ if (h->lockup_detected) free_percpu(h->lockup_detected); +clean1: /* wq/aer/h */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); + /* pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; } From ef745eca79501b3fccb1323fa75ae0add2c67fe2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:20 -0500 Subject: [PATCH 120/889] hpsa: report allocation failures while allocating SG chain blocks Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 06d943422fca8d..87707b990303bc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1878,13 +1878,17 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, GFP_KERNEL); - if (!h->cmd_sg_list) + if (!h->cmd_sg_list) { + dev_err(&h->pdev->dev, "Failed to allocate SG list\n"); return -ENOMEM; + } for (i = 0; i < h->nr_cmds; i++) { h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * h->chainsize, GFP_KERNEL); - if (!h->cmd_sg_list[i]) + if (!h->cmd_sg_list[i]) { + dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n"); goto clean; + } } return 0; From 607692e1e48907cbd4291abdde5df8c1293c6531 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:20 -0500 Subject: [PATCH 121/889] hpsa: rename hpsa_allocate_sg_chain_blocks to hpsa_alloc_sg_chain_blocks Just to match naming of corresponding free functions Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 87707b990303bc..1a2cfcbdce972f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1869,7 +1869,7 @@ static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = NULL; } -static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) +static int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -7201,7 +7201,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_irqs(h); - hpsa_free_sg_chain_blocks(h); + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); kfree(h->blockFetchTable); /* perf 2 */ @@ -7526,7 +7526,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean4; /* irq, pci, lockup, wq/aer/h */ - rc = hpsa_allocate_sg_chain_blocks(h); + rc = hpsa_alloc_sg_chain_blocks(h); if (rc) goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); @@ -7716,7 +7716,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) destroy_workqueue(h->resubmit_wq); hpsa_free_device_info(h); - hpsa_free_sg_chain_blocks(h); + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_ioaccel2_sg_chain_blocks(h); kfree(h->blockFetchTable); /* perf 2 */ hpsa_free_reply_queues(h); /* perf 1 */ From 035415b8aa95f9f8e5d249935db00361a7e46109 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:21 -0500 Subject: [PATCH 122/889] hpsa: improve allocation failure messages from hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1a2cfcbdce972f..a267fd011a4fb0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7466,10 +7466,13 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); h = kzalloc(sizeof(*h), GFP_KERNEL); - if (!h) + if (!h) { + dev_err(&pdev->dev, "Failed to allocate controller head\n"); return -ENOMEM; + } h->pdev = pdev; + h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->offline_device_list); spin_lock_init(&h->lock); @@ -7480,13 +7483,14 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { - dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); + dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; goto clean1; /* aer/h */ } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { + dev_err(&h->pdev->dev, "Failed to allocate lockup detector\n"); rc = -ENOMEM; goto clean1; /* wq/aer/h */ } From 0065d83c2c9ae5e0052900a178b2a2e00e4fd72c Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:22 -0500 Subject: [PATCH 123/889] hpsa: fix minor if-statement style issue in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a267fd011a4fb0..1f741dd261fe26 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7497,7 +7497,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); - if (rc != 0) + if (rc) goto clean2; /* lockup, wq/aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); From fc666ec1c3f0e508402646076469f9d94c7a4807 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:22 -0500 Subject: [PATCH 124/889] hpsa: fix wrong indent level in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1f741dd261fe26..11aeea4c85094d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7601,8 +7601,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto reinit_after_soft_reset; } - /* Enable Accelerated IO path at driver layer */ - h->acciopath_status = 1; + /* Enable Accelerated IO path at driver layer */ + h->acciopath_status = 1; h->lockup_detector_enabled = 1; From ca9c4a3c0a9cfe7fcf8ee3e84f28783e68739e67 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:23 -0500 Subject: [PATCH 125/889] Add hpsa_free_performant_mode and call it from hpsa_init_one in the proper order (after hpsa_unregister_scsi, which call scsi_remove_host) Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 11aeea4c85094d..36502a993f5cfe 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -227,9 +227,8 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); +static void hpsa_free_performant_mode(struct ctlr_info *h); static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); -static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); -static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, @@ -7200,20 +7199,17 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { - hpsa_free_irqs(h); - hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_ioaccel2_sg_chain_blocks(h); - hpsa_free_cmd_pool(h); - kfree(h->blockFetchTable); /* perf 2 */ - hpsa_free_reply_queues(h); /* perf 1 */ - hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ - hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ + hpsa_free_irqs(h); /* init_one 4 */ hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); /* pci_init 2 */ - kfree(h); + kfree(h); /* init_one 1 */ } /* Called when controller lockup detected. */ @@ -7610,8 +7606,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - if (hpsa_register_scsi(h)) /* hook ourselves into SCSI subsystem */ - goto clean4; + rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ + if (rc) + goto clean7; /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -7623,6 +7620,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; +clean7: /* perf, sg, cmd, irq, pci, lockup, wq/aer/h */ + hpsa_free_performant_mode(h); clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); clean5: /* cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_cmd_pool(h); @@ -7636,7 +7635,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean1: /* wq/aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); - /* pci_disable_pcie_error_reporting(pdev); */ + /* (void) pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; } @@ -7683,7 +7682,7 @@ static void hpsa_shutdown(struct pci_dev *pdev) */ hpsa_flush_cache(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); - hpsa_free_irqs(h); + hpsa_free_irqs(h); /* init_one 4 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } @@ -7712,28 +7711,30 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->monitor_ctlr_work); cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); - hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ - /* includes hpsa_free_irqs */ + /* includes hpsa_free_irqs - init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ hpsa_shutdown(pdev); - destroy_workqueue(h->resubmit_wq); - hpsa_free_device_info(h); - hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_device_info(h); /* scan */ + + hpsa_unregister_scsi(h); /* init_one "8" */ hpsa_free_ioaccel2_sg_chain_blocks(h); - kfree(h->blockFetchTable); /* perf 2 */ - hpsa_free_reply_queues(h); /* perf 1 */ - hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ - hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ - hpsa_free_cmd_pool(h); /* init_one 5 */ - kfree(h->hba_inquiry_data); + kfree(h->hba_inquiry_data); /* init_one "8" */ + hpsa_free_performant_mode(h); /* init_one 7 */ + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ + + /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ - hpsa_free_pci_init(h); + hpsa_free_pci_init(h); /* init_one 3 */ - free_percpu(h->lockup_detected); - kfree(h); + free_percpu(h->lockup_detected); /* init_one 2 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 1 */ + /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ + kfree(h); /* init_one 1 */ } static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev, @@ -8066,6 +8067,15 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } +/* Free items allocated by hpsa_put_ctlr_into_performant_mode */ +static void hpsa_free_performant_mode(struct ctlr_info *h) +{ + kfree(h->blockFetchTable); + hpsa_free_reply_queues(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); +} + /* return -ENODEV on error, 0 on success (or no action) * allocates numerous items that must be freed later */ From b68a8e8c4f1e3963008e487d27d1a3801f785697 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:23 -0500 Subject: [PATCH 126/889] hpsa: shorten the wait for the CISS doorbell mode change acknowledgement Shorten the wait for the CISS configuration table doorbell mode change acknowledgement from 300-600 s to 1 s, which is the value specified in the CISS specification that should be honored by all controllers. Wait using interruptible msleep() rather than uninterruptible usleep_range(), which triggers rt_sched timeout errors if the wait is long. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 36502a993f5cfe..1865db733c46f3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -58,8 +58,11 @@ #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" -/* How long to wait (in milliseconds) for board to go into simple mode */ -#define MAX_CONFIG_WAIT 30000 +/* How long to wait for CISS doorbell communication */ +#define CLEAR_EVENT_WAIT_INTERVAL 20 /* ms for each msleep() call */ +#define MODE_CHANGE_WAIT_INTERVAL 10 /* ms for each msleep() call */ +#define MAX_CLEAR_EVENT_WAIT 30000 /* times 20 ms = 600 s */ +#define MAX_MODE_CHANGE_WAIT 100 /* times 10 ms = 1 s */ #define MAX_IOCTL_CONFIG_WAIT 1000 /*define how many times we will try a command because of bus resets */ @@ -6835,14 +6838,14 @@ static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) u32 doorbell_value; unsigned long flags; /* wait until the clear_event_notify bit 6 is cleared by controller. */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) goto done; /* delay and try again */ - msleep(20); + msleep(CLEAR_EVENT_WAIT_INTERVAL); } return -ENODEV; done: @@ -6859,14 +6862,14 @@ static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right * as we enter this code.) */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) goto done; /* delay and try again */ - usleep_range(10000, 20000); + msleep(MODE_CHANGE_WAIT_INTERVAL); } return -ENODEV; done: From 2e9a46c38379030c6f6a2af42d2e76015caf3588 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:24 -0500 Subject: [PATCH 127/889] hpsa: clean up some error reporting output in abort handler Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1865db733c46f3..0354127257118e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5212,11 +5212,18 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); if (WARN(h == NULL, - "ABORT REQUEST FAILED, Controller lookup failed.\n")) + "scsi ?:?:?:? scmd %p ABORT FAILED, Controller lookup failed.\n", + sc)) return FAILED; - if (lockup_detected(h)) + /* if controller locked up, we can guarantee command won't complete */ + if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + h->scsi_host->host_no, sc->device->channel, + sc->device->id, sc->device->lun, sc); return FAILED; + } /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && @@ -5224,9 +5231,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; memset(msg, 0, sizeof(msg)); - ml += sprintf(msg+ml, "Aborting command on scsi %d:%d:%d:%llu ", + ml += sprintf(msg+ml, "scsi %d:%d:%d:%llu scmd %p ABORT ", h->scsi_host->host_no, sc->device->channel, - sc->device->id, sc->device->lun); + sc->device->id, sc->device->lun, sc); /* Find the device of the command to be aborted */ dev = sc->device->hostdata; @@ -5268,11 +5275,12 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); as = abort->scsi_cmd; if (as != NULL) - ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", - as->cmnd[0], as->serial_number); - dev_dbg(&h->pdev->dev, "%s\n", msg); - dev_warn(&h->pdev->dev, "Aborting command on scsi %d:%d:%d:%d\n", - h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + ml += sprintf(msg+ml, + "CDBLen: %d CDB: 0x%02x%02x... SN: 0x%lx ", + as->cmd_len, as->cmnd[0], as->cmnd[1], + as->serial_number); + dev_warn(&h->pdev->dev, "%s BEING SENT\n", msg); + /* * Command is in flight, or possibly already completed * by the firmware (but not to the scsi mid layer) but we can't @@ -5280,7 +5288,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ if (wait_for_available_abort_cmd(h)) { dev_warn(&h->pdev->dev, - "Timed out waiting for an abort command to become available.\n"); + "%s FAILED, timeout waiting for an abort command to become available.\n", + msg); cmd_free(h, abort); return FAILED; } @@ -5288,13 +5297,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) atomic_inc(&h->abort_cmds_available); wake_up_all(&h->abort_cmd_wait_queue); if (rc != 0) { - dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", - h->scsi_host->host_no, - dev->bus, dev->target, dev->lun); + dev_warn(&h->pdev->dev, "%s SENT, FAILED\n", msg); cmd_free(h, abort); return FAILED; } - dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); + dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); cmd_free(h, abort); return SUCCESS; } From 2a1c2fe18db6cfc6afe89c9d987271eb9c3aaf8f Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:24 -0500 Subject: [PATCH 128/889] hpsa: try to detect controller lockup in abort handler Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0354127257118e..6ece7be0675f21 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -252,6 +252,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk); static void hpsa_command_resubmit_worker(struct work_struct *work); static void print_cfg_table(struct device *dev, struct CfgTable *tb); +static void detect_controller_lockup(struct ctlr_info *h); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -5223,6 +5224,21 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; + } else { + /* good time to check if controller lockup has occurred */ + /* FIXME eh_timeout_handler would be even better. + * for testing, abort is just being used for timeouts, + * so is equivalent */ + detect_controller_lockup(h); + + /* check again in case one just occurred */ + if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + h->scsi_host->host_no, sc->device->channel, + sc->device->id, sc->device->lun, sc); + return FAILED; + } } /* Check that controller supports some kind of task abort */ From 2e8299e2f44845ee3f9c6f7bca1af624a3b1de8c Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:25 -0500 Subject: [PATCH 129/889] hpsa: Return DID_NO_CONNECT rather than DID_ERR on lockup After a lockup is detected, return DO_NO_CONNECT which results in immediate termination of commands rather than DID_ERR which results in retries Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 35 +++++++++++++++++++++++++++-------- drivers/scsi/hpsa_cmd.h | 5 +++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6ece7be0675f21..fe4724f4f2ad89 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2191,6 +2191,18 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + /* We check for lockup status here as it may be set for + * CMD_SCSI, CMD_IOACCEL1 and CMD_IOACCEL2 commands by + * fail_all_oustanding_cmds() + */ + if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) { + /* DID_NO_CONNECT will prevent a retry */ + cmd->result = DID_NO_CONNECT << 16; + cmd_free(h, cp); + cmd->scsi_done(cmd); + return; + } + if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); @@ -2459,9 +2471,8 @@ static u32 lockup_detected(struct ctlr_info *h) static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, struct CommandList *c, unsigned long timeout_msecs) { - /* If controller lockup detected, fake a hardware error. */ if (unlikely(lockup_detected(h))) { - c->err_info->CommandStatus = CMD_HARDWARE_ERR; + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; return 0; } return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); @@ -4733,14 +4744,14 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; + cmd->result = DID_NO_CONNECT << 16; cmd->scsi_done(cmd); return 0; } c = cmd_alloc(h); if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; + cmd->result = DID_NO_CONNECT << 16; cmd_free(h, c); cmd->scsi_done(cmd); return 0; @@ -7243,18 +7254,25 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) { int i, refcount; struct CommandList *c; + int failcount = 0; flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); if (refcount > 1) { - c->err_info->CommandStatus = CMD_HARDWARE_ERR; + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; + /* CMD_CTLR_LOCKUP gets finish_cmd to return + * DID_NO_CONNECT which doesn't get retried + */ finish_cmd(c); atomic_dec(&h->commands_outstanding); + failcount++; } cmd_free(h, c); } + dev_warn(&h->pdev->dev, + "failed %d commands in fail_all\n", failcount); } static void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value) @@ -7282,13 +7300,14 @@ static void controller_lockup_detected(struct ctlr_info *h) if (!lockup_detected) { /* no heartbeat, but controller gave us a zero. */ dev_warn(&h->pdev->dev, - "lockup detected but scratchpad register is zero\n"); + "lockup detected after %d but scratchpad register is zero\n", + h->heartbeat_sample_interval / HZ); lockup_detected = 0xffffffff; } set_lockup_detected_for_all_cpus(h, lockup_detected); spin_unlock_irqrestore(&h->lock, flags); - dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", - lockup_detected); + dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x after %d\n", + lockup_detected, h->heartbeat_sample_interval / HZ); pci_disable_device(h->pdev); fail_all_outstanding_cmds(h); } diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 2984d236fb888f..84eb6de9e69c34 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -44,6 +44,11 @@ #define CMD_UNABORTABLE 0x000C #define CMD_TMF_STATUS 0x000D #define CMD_IOACCEL_DISABLED 0x000E +#define CMD_CTLR_LOCKUP 0xffff +/* Note: CMD_CTLR_LOCKUP is not a value defined by the CISS spec + * it is a value defined by the driver that commands can be marked + * with when a controller lockup has been detected by the driver + */ /* TMF function status values */ #define CISS_TMF_COMPLETE 0x00 From 13802cd1dc6a0df384492f7b55d22f4af2fa3ff2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:26 -0500 Subject: [PATCH 130/889] hpsa: check for lockup on all simple_cmd submissions Submitting a command to a locked up controller always results in a timeout, so don't do that Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index fe4724f4f2ad89..8f57e3cf4c13bf 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2452,6 +2452,10 @@ static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, struct CommandList *c, unsigned long timeout_msecs) { + if (unlikely(lockup_detected(h))) { + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; + return 0; + } return __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE, timeout_msecs); } @@ -2468,16 +2472,6 @@ static u32 lockup_detected(struct ctlr_info *h) return rc; } -static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, - struct CommandList *c, unsigned long timeout_msecs) -{ - if (unlikely(lockup_detected(h))) { - c->err_info->CommandStatus = CMD_CTLR_LOCKUP; - return 0; - } - return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); -} - #define MAX_DRIVER_CMD_RETRIES 25 static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, struct CommandList *c, int data_direction, unsigned long timeout_msecs) @@ -2585,6 +2579,9 @@ static void hpsa_scsi_interpret_error(struct ctlr_info *h, case CMD_UNABORTABLE: hpsa_print_cmd(h, "unabortable", cp); break; + case CMD_CTLR_LOCKUP: + hpsa_print_cmd(h, "controller lockup detected", cp); + break; default: hpsa_print_cmd(h, "unknown status", cp); dev_warn(d, "Unknown command status %x\n", @@ -4537,6 +4534,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, } /* Submit commands down the "normal" RAID stack path */ +/* All callers to hpsa_ciss_submit must check lockup_detected + * beforehand, before (opt.) and after calling cmd_alloc + */ static int hpsa_ciss_submit(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, unsigned char scsi3addr[]) @@ -4752,7 +4752,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, c); + cmd_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ cmd->scsi_done(cmd); return 0; } @@ -5602,7 +5602,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - rc = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (rc) rc = -EIO; if (iocommand.buf_size > 0) @@ -5732,7 +5732,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - status = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + status = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (status) { status = -EIO; goto cleanup0; @@ -7692,6 +7692,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) int rc; /* Don't bother trying to flush the cache if locked up */ + /* FIXME not necessary if do_simple_cmd does the check */ if (unlikely(lockup_detected(h))) return; flush_buf = kzalloc(4, GFP_KERNEL); From a4b66a3c80d83b3efa6f5ab80fe0eb88308ff2c7 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:26 -0500 Subject: [PATCH 131/889] hpsa: Support 64-bit lun values in printks The scsi-mq.2 tree includes 64-bit LUN support in some SCSI structures, causing the compiler to complain that %d is not big enough in some of the hpsa controller:bus:target:lun prints Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8f57e3cf4c13bf..148cad1a68b28d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5231,7 +5231,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) { dev_warn(&h->pdev->dev, - "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; @@ -5245,7 +5245,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* check again in case one just occurred */ if (lockup_detected(h)) { dev_warn(&h->pdev->dev, - "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; From e1e6658160a9604072670452417e259b61b55d7c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:27 -0500 Subject: [PATCH 132/889] hpsa: fix missing return in hpsa_command_resubmit_worker Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 148cad1a68b28d..d56ee4eafc6c43 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4708,6 +4708,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); + return; } /* if rc > 0, fall thru and resubmit down CISS path */ } From 670be0b123b81d620f825a1b8a77ae2b08597240 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:27 -0500 Subject: [PATCH 133/889] hpsa: fix command leaks in hpsa_resubmit_command_worker Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d56ee4eafc6c43..b0a5a19c33b783 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4687,6 +4687,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; + cmd_free(c->h, c); cmd->scsi_done(cmd); return; } @@ -4705,6 +4706,9 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) * If we get here, it means dma mapping failed. * Try again via scsi mid layer, which will * then get SCSI_MLQUEUE_HOST_BUSY. + * + * hpsa_ioaccel_submit will have already freed c + * if it encountered a dma mapping failure. */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); @@ -4719,6 +4723,9 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) * If we get here, it means dma mapping failed. Try * again via scsi mid layer, which will then get * SCSI_MLQUEUE_HOST_BUSY. + * + * hpsa_ciss_submit will have already freed c + * if it encountered a dma mapping failure. */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); From 6752cc07afb7d40c7c156151a994d6f2e4f8d2db Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:28 -0500 Subject: [PATCH 134/889] hpsa: fix bad interpretations of hpsa_ioaccel_submit return value Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b0a5a19c33b783..04d63789fd4fb6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4701,7 +4701,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); if (rc == 0) return; - if (rc < 0) { + if (rc == SCSI_MLQUEUE_HOST_BUSY) { /* * If we get here, it means dma mapping failed. * Try again via scsi mid layer, which will @@ -4714,7 +4714,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } - /* if rc > 0, fall thru and resubmit down CISS path */ + /* else, fall thru and resubmit down CISS path */ } } hpsa_cmd_partial_init(c->h, c->cmdindex, c); @@ -4774,7 +4774,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); if (rc == 0) return 0; - if (rc < 0) + if (rc == SCSI_MLQUEUE_HOST_BUSY) return SCSI_MLQUEUE_HOST_BUSY; } return hpsa_ciss_submit(h, c, cmd, scsi3addr); From bf0be62fdb669988a5b4fc09bc7215fd3b7ec4ed Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:29 -0500 Subject: [PATCH 135/889] hpsa: do not touch phys_disk[] for ioaccel enabled logical drives during rescan The code to update h->dev[]->phys_disk[] was temporarily NULLing out h->dev[]->phys_disk[] even if io's using it might be in flight within queuecommand, causing potential NULL pointer dereference in hpsa_raid_map(). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 04d63789fd4fb6..e96af5abf882dd 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1572,6 +1572,15 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, continue; if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) continue; + + /* If offload is currently enabled, the RAID map and + * phys_disk[] assignment *better* not be changing + * and since it isn't changing, we do not need to + * update it. + */ + if (dev[i]->offload_enabled) + continue; + hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]); } } From f3bbc2c59efbd1c39dc0d91f638f4bc422f9c4c7 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:29 -0500 Subject: [PATCH 136/889] hpsa: add change_queue_type function This is so that hpsa based devices support /sys/block/sdNN/device/queue_type of simple, which lets the SCSI midlayer automatically adjust the queue_depth based on TASK SET FULL and GOOD status. This patch does not change the default to simple, however; that is left as a user choice. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e96af5abf882dd..16cd208fa79f45 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -215,6 +215,7 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); +static int hpsa_change_queue_type(struct scsi_device *sdev, int type); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); @@ -874,6 +875,7 @@ static struct scsi_host_template hpsa_driver_template = { .scan_start = hpsa_scan_start, .scan_finished = hpsa_scan_finished, .change_queue_depth = hpsa_change_queue_depth, + .change_queue_type = hpsa_change_queue_type, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .eh_abort_handler = hpsa_eh_abort_handler, @@ -4875,6 +4877,20 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, return sdev->queue_depth; } +static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + static void hpsa_unregister_scsi(struct ctlr_info *h) { /* we are being forcibly unloaded, and may not refuse. */ From 84d6b623f76755501c8df0d04fe9801c32774e0a Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:30 -0500 Subject: [PATCH 137/889] hpsa: make hpsa_change_queue_depth handle reason SCSI_QDEPTH_QFULL and call the .change_queue_depth function in the host template, call scsi_track_queue_full if it gets a reason of SCSI_QDEPTH_QFULL (a TASK SET FULL status), which lets the SCSI midlayer reduce the queue depth. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 16cd208fa79f45..9d716877a379e4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4860,20 +4860,27 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, return finished; } +/* scsi host template change_queue_depth function */ static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { struct ctlr_info *h = sdev_to_hba(sdev); - if (reason != SCSI_QDEPTH_DEFAULT) - return -ENOTSUPP; + if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { + if (qdepth < 1) + qdepth = 1; + else if (qdepth > h->nr_cmds) + qdepth = h->nr_cmds - HPSA_CMDS_RESERVED_FOR_ABORTS - + HPSA_CMDS_RESERVED_FOR_DRIVER - + HPSA_MAX_CONCURRENT_PASSTHRUS; + - if (qdepth < 1) - qdepth = 1; + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + } else if (reason == SCSI_QDEPTH_QFULL) + scsi_track_queue_full(sdev, qdepth); else - if (qdepth > h->nr_cmds) - qdepth = h->nr_cmds; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + return -ENOTSUPP; + return sdev->queue_depth; } From 5fec3416fd253d5c3d3607199eba3277b79be17a Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:30 -0500 Subject: [PATCH 138/889] hpsa: initialize queue depth of logical drives reasonably Adjust the queue depth for a new device after it is created based on the maximum queue depths of the physical devices that constitute the device. This drops the maximum queue depth from .can_queue of 1024 to something like 174 for single-drive RAID-0, 348 for two-drive RAID-1, etc. It also adjusts for the ratio of data to parity drives. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 64 ++++++++++++++++++++++++++++++++------------- drivers/scsi/hpsa.h | 2 +- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9d716877a379e4..61c8d971db19bb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1174,7 +1174,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), @@ -1184,7 +1184,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[device->raid_level], device->offload_config ? '+' : '-', device->offload_enabled ? '+' : '-', - device->expose_state); + device->expose_state, + device->queue_depth); return 0; } @@ -1225,9 +1226,10 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->offload_to_be_enabled = new_entry->offload_enabled; if (!new_entry->offload_enabled) h->dev[entry]->offload_enabled = 0; + h->dev[entry]->queue_depth = new_entry->queue_depth; dev_info(&h->pdev->dev, - "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1236,7 +1238,8 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state); + new_entry->expose_state, + new_entry->queue_depth); } /* Replace an entry from h->dev[] array. */ @@ -1265,7 +1268,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, added[*nadded] = new_entry; (*nadded)++; dev_info(&h->pdev->dev, - "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1274,7 +1277,8 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state); + new_entry->expose_state, + new_entry->queue_depth); } /* Remove an entry from h->dev[] array. */ @@ -1295,7 +1299,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, h->dev[i] = h->dev[i+1]; h->ndevices--; dev_info(&h->pdev->dev, - "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, sd->bus, sd->target, sd->lun, scsi_device_type(sd->devtype), sd->vendor, @@ -1304,7 +1308,8 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, "RAID-?" : raid_label[sd->raid_level], sd->offload_config ? '+' : '-', sd->offload_enabled ? '+' : '-', - sd->expose_state); + sd->expose_state, + sd->queue_depth); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1376,6 +1381,8 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1, return 1; if (dev1->offload_enabled != dev2->offload_enabled) return 1; + if (dev1->queue_depth != dev2->queue_depth) + return 1; return 0; } @@ -1537,6 +1544,7 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) nraid_map_entries = RAID_MAP_MAX_ENTRIES; + logical_drive->queue_depth = 0; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; if (!logical_drive->offload_config) @@ -1548,6 +1556,13 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { logical_drive->phys_disk[i] = dev[j]; + logical_drive->queue_depth = min(h->nr_cmds, + logical_drive->queue_depth + + logical_drive->phys_disk[i]->queue_depth); + dev_info(&h->pdev->dev, + "setting phys_disk[%d] to dev[%d]=%p, qd=%d\n", + i, j, dev[j], + logical_drive->queue_depth); /* ROBROB development only - remove this print */ break; } } @@ -1559,9 +1574,20 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, * present. And in that case offload_enabled should already * be 0, but we'll turn it off here just in case */ - if (!logical_drive->phys_disk[i]) + if (!logical_drive->phys_disk[i]) { logical_drive->offload_enabled = 0; + logical_drive->offload_to_be_enabled = 0; + logical_drive->queue_depth = h->nr_cmds; + } } + if (nraid_map_entries) + /* exclude parity drives from calculation */ + logical_drive->queue_depth = min(h->nr_cmds, + logical_drive->queue_depth * + logical_drive->raid_map.data_disks_per_row / + nraid_map_entries); + else + logical_drive->queue_depth = h->nr_cmds; } static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, @@ -1660,7 +1686,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); dev_info(&h->pdev->dev, - "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, scsi_device_type(sd[i]->devtype), sd[i]->vendor, @@ -1670,7 +1696,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, raid_label[sd[i]->raid_level], sd[i]->offload_config ? '+' : '-', sd[i]->offload_enabled ? '+' : '-', - sd[i]->expose_state); + sd[i]->expose_state, + sd[i]->queue_depth); continue; } @@ -3236,6 +3263,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->offload_to_be_enabled = 0; this_device->hba_ioaccel_enabled = 0; this_device->volume_offline = 0; + this_device->queue_depth = h->nr_cmds; } if (is_OBDR_device) { @@ -4864,16 +4892,16 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { - struct ctlr_info *h = sdev_to_hba(sdev); - if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { + struct hpsa_scsi_dev_t *logical_drive = sdev->hostdata; + + if (!logical_drive) + return -ENODEV; + if (qdepth < 1) qdepth = 1; - else if (qdepth > h->nr_cmds) - qdepth = h->nr_cmds - HPSA_CMDS_RESERVED_FOR_ABORTS - - HPSA_CMDS_RESERVED_FOR_DRIVER - - HPSA_MAX_CONCURRENT_PASSTHRUS; - + else if (qdepth > logical_drive->queue_depth) + qdepth = logical_drive->queue_depth; scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); } else if (reason == SCSI_QDEPTH_QFULL) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 109e6e70ea5be0..a7bb84039f3ce8 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -46,7 +46,7 @@ struct hpsa_scsi_dev_t { unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ - u16 queue_depth; + u16 queue_depth; /* max queue_depth for this device */ atomic_t ioaccel_cmds_out; /* Only used for physical devices * counts commands sent to physical * device via "ioaccel" path. From 5466c7e3c88c6e930fab0a250f3ec43b952729ed Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:31 -0500 Subject: [PATCH 139/889] hpsa: attempt to fix queue depth calculations for logical drives Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 61c8d971db19bb..b2d5c6fd089ec5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1540,11 +1540,12 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, int i, j; int nraid_map_entries = map->row_cnt * map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row); + int qdepth; if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) nraid_map_entries = RAID_MAP_MAX_ENTRIES; - logical_drive->queue_depth = 0; + qdepth = 0; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; if (!logical_drive->offload_config) @@ -1554,17 +1555,13 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) continue; - if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { - logical_drive->phys_disk[i] = dev[j]; - logical_drive->queue_depth = min(h->nr_cmds, - logical_drive->queue_depth + - logical_drive->phys_disk[i]->queue_depth); - dev_info(&h->pdev->dev, - "setting phys_disk[%d] to dev[%d]=%p, qd=%d\n", - i, j, dev[j], - logical_drive->queue_depth); /* ROBROB development only - remove this print */ - break; - } + if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) + continue; + + logical_drive->phys_disk[i] = dev[j]; + qdepth = min(h->nr_cmds, qdepth + + logical_drive->phys_disk[i]->queue_depth); + break; } /* @@ -1580,12 +1577,12 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, logical_drive->queue_depth = h->nr_cmds; } } - if (nraid_map_entries) - /* exclude parity drives from calculation */ - logical_drive->queue_depth = min(h->nr_cmds, - logical_drive->queue_depth * - logical_drive->raid_map.data_disks_per_row / - nraid_map_entries); + if (nraid_map_entries) + /* + * This is correct for reads, too high for full stripe writes, + * way too high for partial stripe writes + */ + logical_drive->queue_depth = qdepth; else logical_drive->queue_depth = h->nr_cmds; } From 8b81b549ec877e1ceff827708c6075b94352d51c Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:31 -0500 Subject: [PATCH 140/889] hpsa: do not print ioaccel2 warning messages about unusual completions. The SCSI midlayer already prints more detail about completions, and has logging level options to filter them if not wanted. These just slow down the system if a lot of errors occur, stressing error handling even more. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b2d5c6fd089ec5..972d557ffb7110 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2025,9 +2025,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, case IOACCEL2_STATUS_SR_TASK_COMP_GOOD: break; case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND: - dev_warn(&h->pdev->dev, - "%s: task complete with check condition.\n", - "HP SSD Smart Path"); cmd->result |= SAM_STAT_CHECK_CONDITION; if (c2->error_data.data_present != IOACCEL2_SENSE_DATA_PRESENT) { @@ -2047,30 +2044,18 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_BUSY: - dev_warn(&h->pdev->dev, - "%s: task complete with BUSY status.\n", - "HP SSD Smart Path"); retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_RES_CON: - dev_warn(&h->pdev->dev, - "%s: task complete with reservation conflict.\n", - "HP SSD Smart Path"); retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL: retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED: - dev_warn(&h->pdev->dev, - "%s: task complete with aborted status.\n", - "HP SSD Smart Path"); retry = 1; break; default: - dev_warn(&h->pdev->dev, - "%s: task complete with unrecognized status: 0x%02x\n", - "HP SSD Smart Path", c2->error_data.status); retry = 1; break; } @@ -2099,9 +2084,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, break; default: retry = 1; - dev_warn(&h->pdev->dev, - "unexpected delivery or target failure, status = 0x%02x\n", - c2->error_data.status); } break; case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: @@ -2109,17 +2091,11 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS: break; case IOACCEL2_SERV_RESPONSE_TMF_REJECTED: - dev_warn(&h->pdev->dev, "task management function rejected.\n"); retry = 1; break; case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN: - dev_warn(&h->pdev->dev, "task management function invalid LUN\n"); break; default: - dev_warn(&h->pdev->dev, - "%s: Unrecognized server response: 0x%02x\n", - "HP SSD Smart Path", - c2->error_data.serv_response); retry = 1; break; } From d3645094d49be9a604f268aad663d49535c5cb9c Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:32 -0500 Subject: [PATCH 141/889] hpsa: zero the command reference counts on initial allocation Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 972d557ffb7110..269eb3e699a296 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4640,6 +4640,7 @@ static void hpsa_preinitialize_commands(struct ctlr_info *h) for (i = 0; i < h->nr_cmds; i++) { struct CommandList *c = h->cmd_pool + i; hpsa_cmd_init(h, i, c); + atomic_set(&c->refcount, 0); } } From 79edc7c77a4b30d1b02146a0b7437d66ad94734d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:33 -0500 Subject: [PATCH 142/889] hpsa: add support sending aborts to physical devices via the ioaccel2 path Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 133 ++++++++++++++++++++++++++++++++++++++-- drivers/scsi/hpsa.h | 1 + drivers/scsi/hpsa_cmd.h | 4 +- 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 269eb3e699a296..7c5aa0ba847167 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -987,6 +987,28 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h, IOACCEL1_BUSADDR_CMDTYPE; } +static void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h, + struct CommandList *c, + int reply_queue) +{ + struct hpsa_tmf_struct *cp = (struct hpsa_tmf_struct *) + &h->ioaccel2_cmd_pool[c->cmdindex]; + + /* Tell the controller to post the reply to the queue for this + * processor. This seems to give the best I/O throughput. + */ + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->reply_queue = smp_processor_id() % h->nreply_queues; + else + cp->reply_queue = reply_queue % h->nreply_queues; + /* Set the bits in the address sent down to include: + * - performant mode bit not used in ioaccel mode 2 + * - pull count (bits 0-3) + * - command type isn't needed for ioaccel2 + */ + c->busaddr |= (h->ioaccel2_blockFetchTable[0]); +} + static void set_ioaccel2_performant_mode(struct ctlr_info *h, struct CommandList *c, int reply_queue) @@ -1051,6 +1073,10 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, set_ioaccel2_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; + case IOACCEL2_TMF: + set_ioaccel2_tmf_performant_mode(h, c, reply_queue); + writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); + break; default: set_performant_mode(h, c, reply_queue); h->access.submit_command(h, c); @@ -5133,6 +5159,47 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, return rc; } +static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h, + struct CommandList *command_to_abort, int reply_queue) +{ + struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *) c2; + struct io_accel2_cmd *c2a = + &h->ioaccel2_cmd_pool[command_to_abort->cmdindex]; + struct scsi_cmnd *scmd = + (struct scsi_cmnd *) command_to_abort->scsi_cmd; + struct hpsa_scsi_dev_t *dev = scmd->device->hostdata; + + /* + * We're overlaying struct hpsa_tmf_struct on top of something which + * was allocated as a struct io_accel2_cmd, so we better be sure it + * actually fits, and doesn't overrun the error info space. + */ + BUILD_BUG_ON(sizeof(struct hpsa_tmf_struct) > + sizeof(struct io_accel2_cmd)); + BUG_ON(offsetof(struct io_accel2_cmd, error_data) < + offsetof(struct hpsa_tmf_struct, error_len) + + sizeof(ac->error_len)); + + c->cmd_type = IOACCEL2_TMF; + /* Adjust the DMA address to point to the accelerated command buffer */ + c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle + + (c->cmdindex * sizeof(struct io_accel2_cmd)); + BUG_ON(c->busaddr & 0x0000007F); + + memset(ac, 0, sizeof(*c2)); /* yes this is correct */ + ac->iu_type = IOACCEL2_IU_TMF_TYPE; + ac->reply_queue = reply_queue; + ac->tmf = IOACCEL2_TMF_ABORT; + ac->it_nexus = cpu_to_le32((u32) dev->ioaccel_handle); + memset(ac->lun_id, 0, sizeof(ac->lun_id)); + ac->tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; + ac->abort_tag = c2a->Tag; + ac->error_ptr = cpu_to_le64((u64) c->busaddr + + offsetof(struct io_accel2_cmd, error_data)); + ac->error_len = cpu_to_le32((u32) sizeof(c2->error_data)); +} + /* ioaccel2 path firmware cannot handle abort task requests. * Change abort requests to physical target reset, and send to the * address of the physical disk used for the ioaccel 2 command. @@ -5211,17 +5278,71 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, return rc; /* success */ } +static int hpsa_send_abort_ioaccel2(struct ctlr_info *h, + struct CommandList *abort, int reply_queue) +{ + int rc = IO_OK; + struct CommandList *c; + u32 taglower, tagupper; + struct hpsa_scsi_dev_t *dev; + struct io_accel2_cmd *c2; + + dev = abort->scsi_cmd->device->hostdata; + if (!dev->offload_enabled && !dev->hba_ioaccel_enabled) + return -1; + + c = cmd_alloc(h); + setup_ioaccel2_abort_cmd(c, h, abort, reply_queue); + c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + hpsa_get_tag(h, abort, &taglower, &tagupper); + dev_dbg(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + __func__, tagupper, taglower); + /* no unmap needed here because no data xfer. */ + + dev_dbg(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: abort service response = 0x%02x.\n", + __func__, tagupper, taglower, c2->error_data.serv_response); + switch (c2->error_data.serv_response) { + case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: + case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS: + rc = 0; + break; + case IOACCEL2_SERV_RESPONSE_TMF_REJECTED: + case IOACCEL2_SERV_RESPONSE_FAILURE: + case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN: + rc = -1; + break; + default: + dev_warn(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: unknown abort service response x0%02x\n", + __func__, tagupper, taglower, + c2->error_data.serv_response); + rc = -1; + } + cmd_free(h, c); + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, + tagupper, taglower); + return rc; +} + static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, - * but underlying firmware can't handle abort TMF. - * Change abort to physical device reset. + * but not all underlying firmware can handle abort TMF. + * Change abort to physical device reset when abort TMF is unsupported. */ - if (abort->cmd_type == CMD_IOACCEL2) - return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, + if (abort->cmd_type == CMD_IOACCEL2) { + if (HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags) + return hpsa_send_abort_ioaccel2(h, abort, + reply_queue); + else + return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort, reply_queue); + } return hpsa_send_abort(h, scsi3addr, abort, reply_queue); } @@ -6102,7 +6223,7 @@ static inline void finish_cmd(struct CommandList *c) if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI || c->cmd_type == CMD_IOACCEL2)) complete_scsi_command(c); - else if (c->cmd_type == CMD_IOCTL_PEND) + else if (c->cmd_type == CMD_IOCTL_PEND || c->cmd_type == IOACCEL2_TMF) complete(c->waiting); } @@ -6870,6 +6991,8 @@ static void hpsa_find_board_params(struct ctlr_info *h) dev_warn(&h->pdev->dev, "Physical aborts not supported\n"); if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) dev_warn(&h->pdev->dev, "Logical aborts not supported\n"); + if (!(HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags)) + dev_warn(&h->pdev->dev, "HP SSD Smart Path aborts supported\n"); } static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index a7bb84039f3ce8..d3a7b5299ec789 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -231,6 +231,7 @@ struct ctlr_info { #define HPSATMF_PHYS_QRY_TASK (1 << 7) #define HPSATMF_PHYS_QRY_TSET (1 << 8) #define HPSATMF_PHYS_QRY_ASYNC (1 << 9) +#define HPSATMF_IOACCEL_ENABLED (1 << 15) #define HPSATMF_MASK_SUPPORTED (1 << 16) #define HPSATMF_LOG_LUN_RESET (1 << 17) #define HPSATMF_LOG_NEX_RESET (1 << 18) diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 84eb6de9e69c34..cf3093dccd9f87 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -396,6 +396,7 @@ struct ErrorInfo { #define CMD_SCSI 0x03 #define CMD_IOACCEL1 0x04 #define CMD_IOACCEL2 0x05 +#define IOACCEL2_TMF 0x06 #define DIRECT_LOOKUP_SHIFT 4 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) @@ -589,6 +590,7 @@ struct io_accel2_cmd { #define IOACCEL2_DIR_NO_DATA 0x00 #define IOACCEL2_DIR_DATA_IN 0x01 #define IOACCEL2_DIR_DATA_OUT 0x02 +#define IOACCEL2_TMF_ABORT 0x01 /* * SCSI Task Management Request format for Accelerator Mode 2 */ @@ -603,7 +605,7 @@ struct hpsa_tmf_struct { u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */ u64 error_ptr; /* Error Pointer */ u32 error_len; /* Error Length */ -}; +} __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT); /* Configuration Table Structure */ struct HostWrite { From fdad925ef7e7ce849a12fd1fc6e387930ca142a9 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:33 -0500 Subject: [PATCH 143/889] hpsa: make hpsa_send_reset_as_abort_ioaccel2() use the specified reply queue. We are sending a reset in order to get rid of a command we want to abort. If we make it return on the same reply queue as the command we want to abort, the completion of the aborted command will not race with the completion of the reset command. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7c5aa0ba847167..7d8cd4f4627c69 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2685,7 +2685,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, } static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, - u8 reset_type) + u8 reset_type, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -2697,7 +2697,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); goto out; @@ -5068,7 +5068,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) dev->expose_state); /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN); + rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, + DEFAULT_REPLY_QUEUE); if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) return SUCCESS; @@ -5208,8 +5209,7 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h, */ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort, - __attribute__((unused)) int reply_queue) + unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { int rc = IO_OK; struct scsi_cmnd *scmd; /* scsi command within request being aborted */ @@ -5251,7 +5251,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, "Reset as abort: Resetting physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", psa[0], psa[1], psa[2], psa[3], psa[4], psa[5], psa[6], psa[7]); - rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET); + rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET, reply_queue); if (rc != 0) { dev_warn(&h->pdev->dev, "Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", From d0a53fbe554e3022ed21c7f0b8eeb80c56266d47 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:34 -0500 Subject: [PATCH 144/889] hpsa: fix problem with abort support checking happening too early The code that checks whether aborts are supported is supposed to see if a logical drive is already known first, but this check happens too early before the necessary data is available. Check it later when the data is available. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7d8cd4f4627c69..ddb6bc8e7a192f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3217,8 +3217,6 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; - unsigned long flags; - int rc, entry; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) @@ -3275,30 +3273,36 @@ static int hpsa_update_device_info(struct ctlr_info *h, OBDR_SIG_LEN) == 0); } kfree(inq_buff); + return 0; + +bail_out: + kfree(inq_buff); + return 1; +} +static void hpsa_update_device_supports_aborts(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev, u8 *scsi3addr) +{ + unsigned long flags; + int rc, entry; /* * See if this device supports aborts. If we already know * the device, we already know if it supports aborts, otherwise * we have to find out if it supports aborts by trying one. */ spin_lock_irqsave(&h->devlock, flags); - rc = hpsa_scsi_find_entry(this_device, h->dev, h->ndevices, &entry); + rc = hpsa_scsi_find_entry(dev, h->dev, h->ndevices, &entry); if ((rc == DEVICE_SAME || rc == DEVICE_UPDATED) && entry >= 0 && entry < h->ndevices) { - this_device->supports_aborts = h->dev[entry]->supports_aborts; + dev->supports_aborts = h->dev[entry]->supports_aborts; spin_unlock_irqrestore(&h->devlock, flags); } else { spin_unlock_irqrestore(&h->devlock, flags); - this_device->supports_aborts = + dev->supports_aborts = hpsa_device_supports_aborts(h, scsi3addr); - if (this_device->supports_aborts < 0) - this_device->supports_aborts = 0; + if (dev->supports_aborts < 0) + dev->supports_aborts = 0; } - return 0; - -bail_out: - kfree(inq_buff); - return 1; } static unsigned char *ext_target_model[] = { @@ -3406,6 +3410,7 @@ static int add_ext_target_dev(struct ctlr_info *h, (*n_ext_target_devs)++; hpsa_set_bus_target_lun(this_device, tmpdevice->bus, tmpdevice->target, 0); + hpsa_update_device_supports_aborts(h, this_device, scsi3addr); set_bit(tmpdevice->target, lunzerobits); return 1; } @@ -3662,6 +3667,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) &is_OBDR)) continue; /* skip it if we can't talk to it. */ figure_bus_target_lun(h, lunaddrbytes, tmpdevice); + hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes); this_device = currentsd[ncurrent]; /* From 6e5ada7328d1c6b18898d9652bdd51a5880908b4 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:34 -0500 Subject: [PATCH 145/889] hpsa: use helper routines for finishing commands Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ddb6bc8e7a192f..873b90e5a912c5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2129,6 +2129,21 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, return retry; /* retry on raid path? */ } +static void hpsa_cmd_free_and_done(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd) +{ + /* FIXME: should we clear c->scsi_cmd here? + * E.g., instead of doing it in complete_scsi_command() */ + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd->scsi_done(cmd); +} + +static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c) +{ + INIT_WORK(&c->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2139,11 +2154,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, /* check for good status */ if (likely(c2->error_data.serv_response == 0 && - c2->error_data.status == 0)) { - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - } + c2->error_data.status == 0)) + return hpsa_cmd_free_and_done(h, c, cmd); /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's @@ -2155,19 +2167,14 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (c2->error_data.status == IOACCEL2_STATUS_SR_IOACCEL_DISABLED) dev->offload_enabled = 0; - goto retry_cmd; + + return hpsa_retry_cmd(h, c); } if (handle_ioaccel_mode2_error(h, c, cmd, c2)) - goto retry_cmd; + return hpsa_retry_cmd(h, c); - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - -retry_cmd: - INIT_WORK(&c->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); + return hpsa_cmd_free_and_done(h, c, cmd); } /* Returns 0 on success, < 0 otherwise. */ @@ -2235,9 +2242,7 @@ static void complete_scsi_command(struct CommandList *cp) if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) { /* DID_NO_CONNECT will prevent a retry */ cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, cp); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(h, cp, cmd); } if (cp->cmd_type == CMD_IOACCEL2) @@ -2247,9 +2252,7 @@ static void complete_scsi_command(struct CommandList *cp) if (ei->CommandStatus == 0) { if (cp->cmd_type == CMD_IOACCEL1) atomic_dec(&cp->phys_disk->ioaccel_cmds_out); - cmd_free(h, cp); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(h, cp, cmd); } /* For I/O accelerator commands, copy over some fields to the normal @@ -2271,10 +2274,7 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - INIT_WORK(&cp->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), - h->resubmit_wq, &cp->work); - return; + return hpsa_retry_cmd(h, cp); } } @@ -2420,8 +2420,7 @@ static void complete_scsi_command(struct CommandList *cp) */ cp->scsi_cmd = NULL; - cmd_free(h, cp); - cmd->scsi_done(cmd); + return hpsa_cmd_free_and_done(h, cp, cmd); } static void hpsa_pci_unmap(struct pci_dev *pdev, @@ -4725,16 +4724,13 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; struct hpsa_scsi_dev_t *dev; - struct CommandList *c = - container_of(work, struct CommandList, work); + struct CommandList *c = container_of(work, struct CommandList, work); cmd = c->scsi_cmd; dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(c->h, c); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(c->h, c, cmd); } if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; From 7336614f4f1905c6dc9a0aa630d2dd0e714555ab Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:35 -0500 Subject: [PATCH 146/889] hpsa: add pending abort flag to commands Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 40 ++++++++++++++++++++++++++++++++++++---- drivers/scsi/hpsa_cmd.h | 2 ++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 873b90e5a912c5..09c56869b518ec 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1083,9 +1083,21 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, } } -static void enqueue_cmd_and_start_io(struct ctlr_info *h, - struct CommandList *c) +static void hpsa_mark_as_aborted(struct CommandList *c) +{ + struct ErrorInfo *ei = c->err_info; + + ei->CommandStatus = CMD_ABORTED; +} + +static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { + if (unlikely(c->abort_pending)) { + hpsa_mark_as_aborted(c); + finish_cmd(c); + return; + } + __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -2144,6 +2156,11 @@ static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c) queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } +static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd) +{ + cmd->result = DID_ABORT << 16; +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2157,6 +2174,12 @@ static void process_ioaccel2_completion(struct ctlr_info *h, c2->error_data.status == 0)) return hpsa_cmd_free_and_done(h, c, cmd); + /* don't requeue a command which is being aborted */ + if (unlikely(c->abort_pending)) { + hpsa_set_scsi_cmd_aborted(cmd); + return hpsa_cmd_free_and_done(h, c, cmd); + } + /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's * wrong. @@ -2274,10 +2297,14 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - return hpsa_retry_cmd(h, cp); + if (!cp->abort_pending) + return hpsa_retry_cmd(h, cp); } } + if (cp->abort_pending) + hpsa_mark_as_aborted(cp); + /* an error has occurred */ switch (ei->CommandStatus) { @@ -2365,7 +2392,7 @@ static void complete_scsi_command(struct CommandList *cp) cp->Request.CDB); break; case CMD_ABORTED: - cmd->result = DID_ABORT << 16; + hpsa_set_scsi_cmd_aborted(cmd); dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", cp->Request.CDB, ei->ScsiStatus); break; @@ -4732,6 +4759,10 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } + if (c->abort_pending) { + hpsa_set_scsi_cmd_aborted(cmd); + return hpsa_cmd_free_and_done(c->h, c, cmd); + } if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -5462,6 +5493,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } + abort->abort_pending = true; hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index cf3093dccd9f87..74f200e0256267 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -438,6 +438,8 @@ struct CommandList { * not used. */ struct hpsa_scsi_dev_t *phys_disk; + + int abort_pending; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From faaad9b9759729f39832d93de9a15df72acd0e94 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:36 -0500 Subject: [PATCH 147/889] hpsa: remove hpsa_mark_as_aborted() helper function Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 09c56869b518ec..78d066c38738b8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1083,20 +1083,10 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, } } -static void hpsa_mark_as_aborted(struct CommandList *c) -{ - struct ErrorInfo *ei = c->err_info; - - ei->CommandStatus = CMD_ABORTED; -} - static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - if (unlikely(c->abort_pending)) { - hpsa_mark_as_aborted(c); - finish_cmd(c); - return; - } + if (unlikely(c->abort_pending)) + return finish_cmd(c); __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -2303,7 +2293,7 @@ static void complete_scsi_command(struct CommandList *cp) } if (cp->abort_pending) - hpsa_mark_as_aborted(cp); + ei->CommandStatus = CMD_ABORTED; /* an error has occurred */ switch (ei->CommandStatus) { From 258f317dfdc34c7abec7c063e2ee31ce748e36bc Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:36 -0500 Subject: [PATCH 148/889] hpsa: move clearing of scsi_cmd to helper function Move the clearing of scsi_cmd from complete_scsi_command() to hpsa_cmd_free_and_done() to ensure that it is done in all cases. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 78d066c38738b8..fc773285d9640b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2134,8 +2134,21 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, static void hpsa_cmd_free_and_done(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd) { - /* FIXME: should we clear c->scsi_cmd here? - * E.g., instead of doing it in complete_scsi_command() */ + /* Prevent the following race in the abort handler: + * + * 1. LLD is requested to abort a SCSI command + * 2. The SCSI command completes + * 3. The struct CommandList associated with step 2 is made available + * 4. New I/O request to LLD to another LUN re-uses struct CommandList + * 5. Abort handler follows scsi_cmnd->host_scribble and + * finds struct CommandList and tries to aborts it + * Now we have aborted the wrong command. + * + * Clear c->scsi_cmd here so that if this command gets re-used, the + * abort handler will know it's a different scsi_cmnd. + */ + c->scsi_cmd = NULL; + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ cmd->scsi_done(cmd); } @@ -2423,20 +2436,6 @@ static void complete_scsi_command(struct CommandList *cp) cp, ei->CommandStatus); } - /* Prevent the following race in the abort handler: - * - * 1. LLD is requested to abort a scsi command - * 2. scsi command completes - * 3. The struct CommandList associated with 2 is made available. - * 4. new io request to LLD to another LUN re-uses struct CommandList - * 5. abort handler follows scsi_cmnd->host_scribble and - * finds struct CommandList and tries to aborts it. - * Now we have aborted the wrong command. - * Clear cp->scsi_cmd here so that if this get re-used, the abort - * handler will know it's a different scsi_cmnd. - */ - cp->scsi_cmd = NULL; - return hpsa_cmd_free_and_done(h, cp, cmd); } From a30de498e35b4fac1f6737275cf9171b6e88c13c Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:37 -0500 Subject: [PATCH 149/889] hpsa: if the current command has been aborted, do not call scsi_done() If the current command has been aborted, do not call the SCSI command completion routine from the I/O path: when the abort returns successfully, the SCSI mid-layer will handle the completion implicitly. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index fc773285d9640b..e8b115ad950c24 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2164,6 +2164,16 @@ static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd) cmd->result = DID_ABORT << 16; } +static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, + struct scsi_cmnd *cmd) +{ + hpsa_set_scsi_cmd_aborted(cmd); + dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", + c->Request.CDB, c->err_info->ScsiStatus); + c->scsi_cmd = NULL; + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2178,10 +2188,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, return hpsa_cmd_free_and_done(h, c, cmd); /* don't requeue a command which is being aborted */ - if (unlikely(c->abort_pending)) { - hpsa_set_scsi_cmd_aborted(cmd); - return hpsa_cmd_free_and_done(h, c, cmd); - } + if (unlikely(c->abort_pending)) + return hpsa_cmd_abort_and_free(h, c, cmd); /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's @@ -2395,10 +2403,8 @@ static void complete_scsi_command(struct CommandList *cp) cp->Request.CDB); break; case CMD_ABORTED: - hpsa_set_scsi_cmd_aborted(cmd); - dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", - cp->Request.CDB, ei->ScsiStatus); - break; + /* Return now to avoid calling scsi_done(). */ + return hpsa_cmd_abort_and_free(h, cp, cmd); case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n", @@ -4748,10 +4754,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } - if (c->abort_pending) { - hpsa_set_scsi_cmd_aborted(cmd); - return hpsa_cmd_free_and_done(c->h, c, cmd); - } + if (c->abort_pending) + return hpsa_cmd_abort_and_free(c->h, c, cmd); if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; From 098d9017109c8a70f5fe2b69b19a126c9e2cef27 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:37 -0500 Subject: [PATCH 150/889] hpsa: don't return abort request until target is complete Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 3 +++ drivers/scsi/hpsa.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e8b115ad950c24..f160a8e2cce691 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2172,6 +2172,7 @@ static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, c->Request.CDB, c->err_info->ScsiStatus); c->scsi_cmd = NULL; cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + wake_up_all(&h->abort_sync_wait_queue); } static void process_ioaccel2_completion(struct ctlr_info *h, @@ -5519,6 +5520,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); + wait_event(h->abort_sync_wait_queue, atomic_read(&abort->refcount) == 1); cmd_free(h, abort); return SUCCESS; } @@ -7768,6 +7770,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); + init_waitqueue_head(&h->abort_sync_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index d3a7b5299ec789..db450bd0964888 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -266,6 +266,7 @@ struct ctlr_info { struct workqueue_struct *resubmit_wq; atomic_t abort_cmds_available; wait_queue_head_t abort_cmd_wait_queue; + wait_queue_head_t abort_sync_wait_queue; }; struct offline_device_entry { From 5edd8cced3731416081ccca4c27fa78dc40dd9db Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:38 -0500 Subject: [PATCH 151/889] hpsa: factor out hpsa_send_test_unit_ready function Factor out the code which sends the TEST_UNIT_READY from wait_for_device_to_become_ready() into its own function Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 51 +++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f160a8e2cce691..432516f84de65e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5004,6 +5004,38 @@ static int hpsa_register_scsi(struct ctlr_info *h) return -ENOMEM; } +/* Send a TEST_UNIT_READY command to the specified LUN using the specified + * reply queue; returns zero if the unit is ready, and non-zero otherwise. */ +static int hpsa_send_test_unit_ready(struct ctlr_info *h, + struct CommandList *c, unsigned char lunaddr[], + int reply_queue) +{ + int rc; + + /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ + (void) fill_cmd(c, TEST_UNIT_READY, h, + NULL, 0, 0, lunaddr, TYPE_CMD); + rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + if (rc) + return rc; + /* no unmap needed here because no data xfer. */ + + /* Check if the unit is already ready. */ + if (c->err_info->CommandStatus == CMD_SUCCESS) + return 0; + + /* The first command sent after reset will receive "unit attention" to + * indicate that the LUN has been reset...this is actually what we're + * looking for (but, success is good too). */ + if (c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && + (c->err_info->SenseInfo[2] == NO_SENSE || + c->err_info->SenseInfo[2] == UNIT_ATTENTION)) + return 0; + + return 1; +} + static int wait_for_device_to_become_ready(struct ctlr_info *h, unsigned char lunaddr[]) { @@ -5028,26 +5060,13 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS) waittime = waittime * 2; - /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ - (void) fill_cmd(c, TEST_UNIT_READY, h, - NULL, 0, 0, lunaddr, TYPE_CMD); - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); - if (rc) - goto do_it_again; - /* no unmap needed here because no data xfer. */ - - if (c->err_info->CommandStatus == CMD_SUCCESS) + rc = hpsa_send_test_unit_ready(h, c, lunaddr, + DEFAULT_REPLY_QUEUE); + if (!rc) break; - if (c->err_info->CommandStatus == CMD_TARGET_STATUS && - c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && - (c->err_info->SenseInfo[2] == NO_SENSE || - c->err_info->SenseInfo[2] == UNIT_ATTENTION)) - break; -do_it_again: dev_warn(&h->pdev->dev, "waiting %d secs " "for device to become ready.\n", waittime); - rc = 1; /* device not ready. */ } if (rc) From 31ef6feefca7c8134defad3d7222622cc8762518 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:39 -0500 Subject: [PATCH 152/889] hpsa: factor out hpsa_wait_for_test_unit_ready function. Move the code which waits for the TEST_UNIT_READY from wait_for_device_to_become_ready() into its own function Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 432516f84de65e..de6c6ae1d167eb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5036,39 +5036,49 @@ static int hpsa_send_test_unit_ready(struct ctlr_info *h, return 1; } -static int wait_for_device_to_become_ready(struct ctlr_info *h, - unsigned char lunaddr[]) +/* Wait for a TEST_UNIT_READY command to complete, retrying as necessary; + * returns zero when the unit is ready, and non-zero when giving up. */ +static int hpsa_wait_for_test_unit_ready(struct ctlr_info *h, struct CommandList *c, + unsigned char lunaddr[], int reply_queue) { int rc; int count = 0; int waittime = 1; /* seconds */ - struct CommandList *c; - - c = cmd_alloc(h); /* Send test unit ready until device ready, or give up. */ - while (count < HPSA_TUR_RETRY_LIMIT) { + for (count = 0; count < HPSA_TUR_RETRY_LIMIT; count++) { /* Wait for a bit. do this first, because if we send * the TUR right away, the reset will just abort it. */ msleep(1000 * waittime); - count++; - rc = 0; /* Device ready. */ + + rc = hpsa_send_test_unit_ready(h, c, lunaddr, reply_queue); + if (!rc) + break; /* Increase wait time with each try, up to a point. */ if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS) waittime = waittime * 2; - rc = hpsa_send_test_unit_ready(h, c, lunaddr, - DEFAULT_REPLY_QUEUE); - if (!rc) - break; - - dev_warn(&h->pdev->dev, "waiting %d secs " - "for device to become ready.\n", waittime); + dev_warn(&h->pdev->dev, + "waiting %d secs for device to become ready.\n", + waittime); } + return rc; +} + +static int wait_for_device_to_become_ready(struct ctlr_info *h, + unsigned char lunaddr[]) +{ + int rc; + struct CommandList *c; + + c = cmd_alloc(h); + + rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, DEFAULT_REPLY_QUEUE); + if (rc) dev_warn(&h->pdev->dev, "giving up on device.\n"); else From d5301ef5a895cb81ae5e9df68d6d50af3899ab95 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:39 -0500 Subject: [PATCH 153/889] hpsa: follow device resets with a TUR per reply queue to avoid races Since command completions may arrive on any reply queue, the completion of the reset doesn't mean that all affected commands' completions have been received and processed. This patch sends the test-unit-ready command multiple times specifying each reply queue; thus, when the last of the test unit ready completions is received, we can be sure that all affected commands have been completed. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index de6c6ae1d167eb..ea2520f86ab0da 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5070,14 +5070,34 @@ static int hpsa_wait_for_test_unit_ready(struct ctlr_info *h, struct CommandList } static int wait_for_device_to_become_ready(struct ctlr_info *h, - unsigned char lunaddr[]) + unsigned char lunaddr[], + int reply_queue) { - int rc; + int first_queue; + int last_queue; + int rq; + int rc = 0; struct CommandList *c; c = cmd_alloc(h); - rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, DEFAULT_REPLY_QUEUE); + /* If no specific reply queue was requested, then send the TUR + * repeatedly, requesting a reply on each reply queue; otherwise execute + * the loop exactly once using only the specified queue. */ + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) { + first_queue = 0; + last_queue = h->nreply_queues - 1; + } else { + first_queue = reply_queue; + last_queue = reply_queue; + } + + for (rq = first_queue; rq <= last_queue; rq++) { + rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, + reply_queue == DEFAULT_REPLY_QUEUE ? rq : reply_queue); + if (rc) + break; + } if (rc) dev_warn(&h->pdev->dev, "giving up on device.\n"); @@ -5126,8 +5146,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, DEFAULT_REPLY_QUEUE); - if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) - return SUCCESS; + if (rc == 0) + if (!wait_for_device_to_become_ready(h, dev->scsi3addr, + DEFAULT_REPLY_QUEUE)) + return SUCCESS; dev_warn(&h->pdev->dev, "resetting scsi %d:%d:%d:%d failed\n", @@ -5317,7 +5339,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, } /* wait for device to recover */ - if (wait_for_device_to_become_ready(h, psa) != 0) { + if (wait_for_device_to_become_ready(h, psa, reply_queue) != 0) { dev_warn(&h->pdev->dev, "Reset as abort: Failed: Device never recovered from reset: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", psa[0], psa[1], psa[2], psa[3], From 317a7f50841ea13e5e9b82f54e11e244ad383d51 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:40 -0500 Subject: [PATCH 154/889] hpsa: move SG descriptor set-up out of hpsa_scatter_gather() Move the code which sets up the SG descriptor out of hpsa_scatter_gather() and into a subroutine where it can be reused (in the next patch). The Ext field is now assigned unconditionally: this makes the refactor much simpler, but more importantly it removes a conditional operation from inside the loop. The case for which the conditional formerly tested is now executed (unconditionally) after the loop is exited. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ea2520f86ab0da..86367bdb24d980 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3784,6 +3784,17 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) kfree(id_phys); } +static void hpsa_set_sg_descriptor(struct SGDescriptor *desc, + struct scatterlist *sg) +{ + u64 addr64 = (u64) sg_dma_address(sg); + unsigned int len = sg_dma_len(sg); + + desc->Addr = cpu_to_le64(addr64); + desc->Len = cpu_to_le32(len); + desc->Ext = 0; +} + /* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci * dma mapping and fills in the scatter gather entries of the * hpsa command, cp. @@ -3792,9 +3803,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct CommandList *cp, struct scsi_cmnd *cmd) { - unsigned int len; struct scatterlist *sg; - u64 addr64; int use_sg, i, sg_index, chained, last_sg; struct SGDescriptor *curr_sg; @@ -3818,14 +3827,13 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = h->cmd_sg_list[cp->cmdindex]; sg_index = 0; } - addr64 = (u64) sg_dma_address(sg); - len = sg_dma_len(sg); - curr_sg->Addr = cpu_to_le64(addr64); - curr_sg->Len = cpu_to_le32(len); - curr_sg->Ext = cpu_to_le32((i == last_sg) * HPSA_SG_LAST); + hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; } + /* Back the pointer up to the last entry and mark it as "last". */ + (curr_sg - 1)->Ext = cpu_to_le32(HPSA_SG_LAST); + if (use_sg + chained > h->maxSG) h->maxSG = use_sg + chained; From e5394c7f011547a1cadff2eca7ae88a6d5beaeb8 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:40 -0500 Subject: [PATCH 155/889] hpsa: performance tweak for hpsa_scatter_gather() Divide the loop in hpsa_scatter_gather() into two, one for the initial SG list and a second one for the chained list, if any. This allows the conditional check which resets the indicies for the chained list to be performed outside the loop instead of being done on every iteration inside the loop. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 86367bdb24d980..88052420fc4bd5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3804,7 +3804,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct scsi_cmnd *cmd) { struct scatterlist *sg; - int use_sg, i, sg_index, chained, last_sg; + int use_sg, i, sg_limit, chained, last_sg; struct SGDescriptor *curr_sg; BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); @@ -3816,21 +3816,33 @@ static int hpsa_scatter_gather(struct ctlr_info *h, if (!use_sg) goto sglist_finished; + /* If the number of entries is greater than the max for a single list, + * then we have a chained list; we will set up all but one entry in the + * first list (the last entry is saved for link information); + * otherwise, we don't have a chained list and we'll set up at each of + * the entries in the one list. */ curr_sg = cp->SG; - chained = 0; - sg_index = 0; + chained = use_sg > h->max_cmd_sg_entries; + sg_limit = chained ? h->max_cmd_sg_entries - 1 : use_sg; last_sg = scsi_sg_count(cmd) - 1; - scsi_for_each_sg(cmd, sg, use_sg, i) { - if (i == h->max_cmd_sg_entries - 1 && - use_sg > h->max_cmd_sg_entries) { - chained = 1; - curr_sg = h->cmd_sg_list[cp->cmdindex]; - sg_index = 0; - } + scsi_for_each_sg(cmd, sg, sg_limit, i) { hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; } + if (chained) { + /* Continue with the chained list. Set curr_sg to the chained + * list. Modify the limit to the total count less the entries + * we've already set up. Resume the scan at the list entry + * where the previous loop left off. */ + curr_sg = h->cmd_sg_list[cp->cmdindex]; + sg_limit = use_sg - sg_limit; + for_each_sg(sg, sg, sg_limit, i) { + hpsa_set_sg_descriptor(curr_sg, sg); + curr_sg++; + } + } + /* Back the pointer up to the last entry and mark it as "last". */ (curr_sg - 1)->Ext = cpu_to_le32(HPSA_SG_LAST); From d8adb72ac1b91719b9c0a7baaebdee6c00b7eb06 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:41 -0500 Subject: [PATCH 156/889] hpsa: restructure simple controller command interface/implementation, step 1. Rename hpsa_scsi_do_simple_cmd_core() to hpsa_scsi_do_simple_cmd(), since this function is the interface for issuing commands to the controller and not the "core" of that implementation. Add a parameter to it which allows the caller to specify the reply queue to be used. Modify existing callers to specify the default reply queue. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 88052420fc4bd5..006d471a45f38c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2508,15 +2508,14 @@ static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, return 0; } -static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c, unsigned long timeout_msecs) +static int hpsa_scsi_do_simple_cmd(struct ctlr_info *h, struct CommandList *c, + int reply_queue, unsigned long timeout_msecs) { if (unlikely(lockup_detected(h))) { c->err_info->CommandStatus = CMD_CTLR_LOCKUP; return 0; } - return __hpsa_scsi_do_simple_cmd_core(h, c, - DEFAULT_REPLY_QUEUE, timeout_msecs); + return __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, timeout_msecs); } static u32 lockup_detected(struct ctlr_info *h) @@ -2540,7 +2539,8 @@ static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, do { memset(c->err_info, 0, sizeof(*c->err_info)); - rc = hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, + timeout_msecs); if (rc) break; retry_count++; @@ -3132,7 +3132,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, c = cmd_alloc(h); (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (rc) { cmd_free(h, c); return 0; @@ -5865,7 +5865,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (rc) rc = -EIO; if (iocommand.buf_size > 0) @@ -5995,7 +5995,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - status = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (status) { status = -EIO; goto cleanup0; From f444247415eaee685f9f79c4f3ad211d1d997017 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:41 -0500 Subject: [PATCH 157/889] hpsa: restructure simple controller command interface/implementation, step 2 Rename __hpsa_scsi_do_simple_cmd_core() to hpsa_scsi_do_simple_cmd_core(), since this routine is the "core" implementation of the "do simple command" function and there is no longer any other function with a similar name. Modify the existing callers of this routine (other than hpsa_scsi_do_simple_cmd()) to instead call hpsa_scsi_do_simple_cmd(), since it will now accept the reply_queue paramenter, and it provides a controller lock-up check. (Also, tweak two related message strings to make them distinct from each other.) Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 006d471a45f38c..abc5a22bb91ff2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2488,7 +2488,7 @@ static int hpsa_map_one(struct pci_dev *pdev, #define NO_TIMEOUT ((unsigned long) -1) #define DEFAULT_TIMEOUT (30000) /* milliseconds */ -static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, +static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, struct CommandList *c, int reply_queue, unsigned long timeout_msecs) { DECLARE_COMPLETION_ONSTACK(wait); @@ -2515,7 +2515,7 @@ static int hpsa_scsi_do_simple_cmd(struct ctlr_info *h, struct CommandList *c, c->err_info->CommandStatus = CMD_CTLR_LOCKUP; return 0; } - return __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, timeout_msecs); + return hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, timeout_msecs); } static u32 lockup_detected(struct ctlr_info *h) @@ -2719,7 +2719,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); goto out; @@ -3205,7 +3205,7 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, c = cmd_alloc(h); (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); - (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, 0, NO_TIMEOUT); /* no unmap needed here because no data xfer. */ ei = c->err_info; switch (ei->CommandStatus) { @@ -5035,7 +5035,7 @@ static int hpsa_send_test_unit_ready(struct ctlr_info *h, /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) return rc; /* no unmap needed here because no data xfer. */ @@ -5229,9 +5229,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (h->needs_abort_tags_swizzled) swizzle_abort_tag(&c->Request.CDB[4]); - (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); - dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd(abort) completed.\n", __func__, tagupper, taglower); /* no unmap needed here because no data xfer. */ @@ -5392,10 +5392,10 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h, c = cmd_alloc(h); setup_ioaccel2_abort_cmd(c, h, abort, reply_queue); c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, - "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + "%s: Tag:0x%08x:%08x: do_simple_cmd(ioaccel2 abort) completed.\n", __func__, tagupper, taglower); /* no unmap needed here because no data xfer. */ From 4b2f1ea65625e90c86a34cef17be9dc24cd715b8 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:42 -0500 Subject: [PATCH 158/889] hpsa: refactor worker requeue code Refactor common code from hpsa_requeue_worker() and hpsa_rescan_ctlr_worker() which requeues the work item and place it in a separate routine, to encapsulate the conditional and make the code consistent (and remove a bug). Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index abc5a22bb91ff2..6d1ca7c9ee5b9b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7701,9 +7701,18 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } -static void hpsa_rescan_ctlr_worker(struct work_struct *work) +static void hpsa_requeue_worker(struct ctlr_info *h, struct delayed_work *wi) { unsigned long flags; + + spin_lock_irqsave(&h->lock, flags); + if (!h->remove_in_progress) + schedule_delayed_work(wi, h->heartbeat_sample_interval); + spin_unlock_irqrestore(&h->lock, flags); +} + +static void hpsa_rescan_ctlr_worker(struct work_struct *work) +{ struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, rescan_ctlr_work); @@ -7713,32 +7722,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work) hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); } - spin_lock_irqsave(&h->lock, flags); - if (h->remove_in_progress) { - spin_unlock_irqrestore(&h->lock, flags); - return; - } - schedule_delayed_work(&h->rescan_ctlr_work, - h->heartbeat_sample_interval); - spin_unlock_irqrestore(&h->lock, flags); + + hpsa_requeue_worker(h, &h->rescan_ctlr_work); } static void hpsa_monitor_ctlr_worker(struct work_struct *work) { - unsigned long flags; struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, monitor_ctlr_work); detect_controller_lockup(h); if (lockup_detected(h)) return; - spin_lock_irqsave(&h->lock, flags); - if (h->remove_in_progress) - spin_unlock_irqrestore(&h->lock, flags); - else - schedule_delayed_work(&h->monitor_ctlr_work, - h->heartbeat_sample_interval); - spin_unlock_irqrestore(&h->lock, flags); + hpsa_requeue_worker(h, &h->monitor_ctlr_work); } static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) From 50cb531b6106c2607747e8c6c681b32f2c864960 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:43 -0500 Subject: [PATCH 159/889] hpsa: refactor hpsa_find_board_params() to encapsulate legacy test Encapsulate the conditional predicate which tests for legacy controllers in a separate function and rework the code comments. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6d1ca7c9ee5b9b..4f324ad728193e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7061,6 +7061,15 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) } } +/* If the controller reports that the total max sg entries is greater than 512, + * then we know that chained SG blocks work. (Original smart arrays did not + * support chained SG blocks and would return zero for max sg entries.) + */ +static int hpsa_supports_chained_sg_blocks(struct ctlr_info *h) +{ + return h->maxsgentries > 512; +} + /* Interrogate the hardware for some limits: * max commands, max SG elements without chaining, and with chaining, * SG chain block size, etc. @@ -7071,18 +7080,20 @@ static void hpsa_find_board_params(struct ctlr_info *h) h->nr_cmds = h->max_commands; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); - /* - * Limit in-command s/g elements to 32 save dma'able memory. - * Howvever spec says if 0, use 31 - */ - h->max_cmd_sg_entries = 31; - if (h->maxsgentries > 512) { + if (hpsa_supports_chained_sg_blocks(h)) { + /* Limit in-command s/g elements to 32 save dma'able memory. */ h->max_cmd_sg_entries = 32; h->chainsize = h->maxsgentries - h->max_cmd_sg_entries; h->maxsgentries--; /* save one for chain pointer */ } else { - h->chainsize = 0; + /* Original smart arrays supported at most 31 scatter gather + * entries embedded inline in the command (trying to use more + * would lock up the controller, see + * https://lkml.org/lkml/2001/12/4/139 ). + */ + h->max_cmd_sg_entries = 31; h->maxsgentries = 31; /* default to traditional values */ + h->chainsize = 0; } /* Find out what task management functions are supported and cache */ From f950d9f33349b760b7ccde6e7b8543f37631cc81 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 20 Oct 2014 17:01:43 -0500 Subject: [PATCH 160/889] hpsa: move test out of set_encrypt_ioaccel2 to avoid function call overhead Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4f324ad728193e..d586110f09268b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4022,18 +4022,14 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, * Set encryption parameters for the ioaccel2 request */ static void set_encrypt_ioaccel2(struct ctlr_info *h, - struct CommandList *c, struct io_accel2_cmd *cp) + struct CommandList *c, struct io_accel2_cmd *cp, u16 dekindex) { struct scsi_cmnd *cmd = c->scsi_cmd; struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; struct raid_map_data *map = &dev->raid_map; u64 first_block; - /* Are we doing encryption on this device */ - if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON)) - return; - /* Set the data encryption key index. */ - cp->dekindex = map->dekindex; + cp->dekindex = dekindex; /* Set the encryption enable flag, encoded into direction field. */ cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK; @@ -4224,7 +4220,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } /* Set encryption parameters, if necessary */ - set_encrypt_ioaccel2(h, c, cp); + if (phys_disk->raid_map.flags & RAID_MAP_FLAG_ENCRYPT_ON) + set_encrypt_ioaccel2(h, c, cp, phys_disk->raid_map.dekindex); cp->scsi_nexus = ioaccel_handle; cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; From 87a36d0ac4d17cff4bf2309164629a8af31a05d3 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:44 -0500 Subject: [PATCH 161/889] hpsa: use block layer tag for command allocation Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 94 ++++++++++++++++++++++++++++++++++++++------- drivers/scsi/hpsa.h | 1 + 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d586110f09268b..c2fa71a43cf0d4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -204,6 +204,9 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); static void cmd_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); +static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c); +static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, + struct scsi_cmnd *scmd); static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type); @@ -891,6 +894,9 @@ static struct scsi_host_template hpsa_driver_template = { .shost_attrs = hpsa_shost_attrs, .max_sectors = 8192, .no_write_same = 1, + .reserved_tags = HPSA_CMDS_RESERVED_FOR_ABORTS + + HPSA_CMDS_RESERVED_FOR_DRIVER + + HPSA_MAX_CONCURRENT_PASSTHRUS, }; static inline u32 next_command(struct ctlr_info *h, u8 q) @@ -2148,8 +2154,7 @@ static void hpsa_cmd_free_and_done(struct ctlr_info *h, * abort handler will know it's a different scsi_cmnd. */ c->scsi_cmd = NULL; - - cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd_tagged_free(h, c); cmd->scsi_done(cmd); } @@ -2171,7 +2176,7 @@ static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", c->Request.CDB, c->err_info->ScsiStatus); c->scsi_cmd = NULL; - cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd_tagged_free(h, c); wake_up_all(&h->abort_sync_wait_queue); } @@ -4676,7 +4681,7 @@ static int hpsa_ciss_submit(struct ctlr_info *h, } if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } enqueue_cmd_and_start_io(h, c); @@ -4742,7 +4747,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (rc == 0) return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->hba_ioaccel_enabled) { @@ -4753,7 +4758,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (rc == 0) return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } } @@ -4839,11 +4844,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); return 0; } - c = cmd_alloc(h); + c = cmd_tagged_alloc(h, cmd); if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ + cmd_tagged_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ cmd->scsi_done(cmd); return 0; } @@ -4994,10 +4999,7 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds - - HPSA_CMDS_RESERVED_FOR_ABORTS - - HPSA_CMDS_RESERVED_FOR_DRIVER - - HPSA_MAX_CONCURRENT_PASSTHRUS; + sh->can_queue = h->nr_cmds; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; @@ -5593,6 +5595,58 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } +/* + * For operations with an associated SCSI command, a command block is allocated + * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the + * block request tag as an index into a table of entries. cmd_tagged_free() is + * the complement, although cmd_free() may be called instead. + * + * The block layer has already gone to the trouble of picking out a unique, + * small-integer tag for this request, and it was squirreled away in the SCSI + * command. We use that value as an index to select our command block. + */ +static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, + struct scsi_cmnd *scmd) +{ + int idx = scmd->request->tag; + struct CommandList *c = h->cmd_pool + idx; + int refcount = 0; + + if (idx < h->reserved_cmds || idx > h->nr_cmds) { + dev_err(&h->pdev->dev, "Bad block tag: %d\n", idx); + return NULL; + } + + refcount = atomic_inc_return(&c->refcount); + if (unlikely(refcount > 1)) { + /* + * We expect that the SCSI layer will hand us a unique tag + * value. Thus, there should never be a collision here between + * two requests; however, it's possible that a lingering abort + * might have an outstanding reference when the next request + * comes in (the block layer tends to reuse the last-used tag + * first). Hopefully, that won't be a problem. + */ + dev_warn(&h->pdev->dev, + "tag collision (tag=%d) in cmd_tagged_alloc().\n", + idx); + } + + hpsa_cmd_partial_init(h, idx, c); + return c; +} + +static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c) +{ + /* + * Release our reference to the block. We don't need to do anything + * else to free it, because it is accessed by index. (There's no point + * in checking the result of the decrement, since we cannot guarantee + * that there isn't a concurrent abort which is also accessing it.) + */ + (void)atomic_dec_and_test(&c->refcount); +} + /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -5616,12 +5670,19 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * very unlucky thread might be starved anyway, never able to * beat the other threads. In reality, this happens so * infrequently as to be indistinguishable from never. + * + * Note that we start allocating commands before the SCSI host structure + * is initialized. Since the last allocation starts out as zero, this + * all works, since we have at least one command structure available; + * however, it means that the structures with the low indexes have to be + * reserved for driver-initiated requests, while requests from the block + * layer will use the higher indexes. */ offset = h->last_allocation; /* benighly racy */ for (;;) { i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); - if (unlikely(i == h->nr_cmds)) { + if (unlikely(i >= h->reserved_cmds)) { offset = 0; continue; } @@ -5641,6 +5702,12 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) return c; } +/* + * This is the complementary operation to cmd_alloc(). Note, however, in some + * corner cases it may also be used to free blocks allocated by + * cmd_tagged_alloc() in which case the ref-count decrement does the trick and + * the clear-bit is harmless. + */ static void cmd_free(struct ctlr_info *h, struct CommandList *c) { if (atomic_dec_and_test(&c->refcount)) { @@ -7075,6 +7142,7 @@ static void hpsa_find_board_params(struct ctlr_info *h) { hpsa_get_max_perf_mode_cmds(h); h->nr_cmds = h->max_commands; + h->reserved_cmds = hpsa_driver_template.reserved_tags; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); if (hpsa_supports_chained_sg_blocks(h)) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index db450bd0964888..81a6549e9f313e 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -136,6 +136,7 @@ struct ctlr_info { void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ + int reserved_cmds; /* Number reserved for driver use */ #define HPSA_CMDS_RESERVED_FOR_ABORTS 2 #define HPSA_CMDS_RESERVED_FOR_DRIVER 1 struct CfgTable __iomem *cfgtable; From 216b8d07a0ed60c65d4a3475f40bd8f022059b91 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:44 -0500 Subject: [PATCH 162/889] hpsa: crash on bad block layer tags Modify cmd_tagged_allocation() to crash when it receives a bad tag from the block layer, instead of returning a NULL pointer and letting the next layer up fail: we should never get a bad tag, and if we do it means that the system is misconfigured (e.g., that the scsi-mq support is not enabled), and it would be best to die a clean, swift death before anyone gets hurt. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c2fa71a43cf0d4..8817337141aff4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5614,7 +5614,8 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, if (idx < h->reserved_cmds || idx > h->nr_cmds) { dev_err(&h->pdev->dev, "Bad block tag: %d\n", idx); - return NULL; + /* This value comes from the block layer...it's not our bug. */ + BUG_ON(idx < HPSA_NRESERVED_CMDS || idx > h->nr_cmds); } refcount = atomic_inc_return(&c->refcount); From 29a04d28df8bc648f25e69fc2f8063f18dcc18be Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:45 -0500 Subject: [PATCH 163/889] hpsa: incorporate review feedback to the tagged-allocation patch Limit the search for free cmd blocks to only the reserved range, and remove the optimization which avoids starting the search at the beginning of the range. This patch should be squashed with hpsa-use-block-layer-tag-for-command-allocation Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 12 +++--------- drivers/scsi/hpsa.h | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8817337141aff4..2736632f098dad 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5660,7 +5660,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) { struct CommandList *c; int refcount, i; - unsigned long offset; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -5673,32 +5672,27 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. * * Note that we start allocating commands before the SCSI host structure - * is initialized. Since the last allocation starts out as zero, this + * is initialized. Since the search starts at bit zero, this * all works, since we have at least one command structure available; * however, it means that the structures with the low indexes have to be * reserved for driver-initiated requests, while requests from the block * layer will use the higher indexes. */ - offset = h->last_allocation; /* benighly racy */ for (;;) { - i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); - if (unlikely(i >= h->reserved_cmds)) { - offset = 0; + i = find_first_zero_bit(h->cmd_pool_bits, h->reserved_cmds); + if (unlikely(i >= h->reserved_cmds)) continue; - } c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); if (unlikely(refcount > 1)) { cmd_free(h, c); /* already in use */ - offset = (i + 1) % h->nr_cmds; continue; } set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); break; /* it's ours now. */ } - h->last_allocation = i; /* benignly racy */ hpsa_cmd_partial_init(h, i, c); return c; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 81a6549e9f313e..1643c9e2876f3c 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -142,7 +142,6 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; - int last_allocation; atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 From 87ccb29023f90ef92b000d6be4bcf0eeccef3f8a Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:46 -0500 Subject: [PATCH 164/889] hpsa: second round of tagged-allocation review-input changes Remove the reserved_cmds commands field from the controller info structure and replace references to it with a #define'd symbol. Add a build-time assertion that the minimum number of available commands is greater than the number which are reserved by the driver to ensure that we can do at least some I/O. Replace the magic number used for the minimum number of commands with at #define'd symbol. (This patch should presumably be squashed with the original patch and the previous review-input changes.) Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 21 ++++++++++++--------- drivers/scsi/hpsa.h | 1 - 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2736632f098dad..eb1a98d7cf6c79 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -870,6 +870,9 @@ static struct device_attribute *hpsa_shost_attrs[] = { NULL, }; +#define HPSA_NRESERVED_CMDS (HPSA_CMDS_RESERVED_FOR_ABORTS + \ + HPSA_CMDS_RESERVED_FOR_DRIVER + HPSA_MAX_CONCURRENT_PASSTHRUS) + static struct scsi_host_template hpsa_driver_template = { .module = THIS_MODULE, .name = HPSA, @@ -894,9 +897,7 @@ static struct scsi_host_template hpsa_driver_template = { .shost_attrs = hpsa_shost_attrs, .max_sectors = 8192, .no_write_same = 1, - .reserved_tags = HPSA_CMDS_RESERVED_FOR_ABORTS + - HPSA_CMDS_RESERVED_FOR_DRIVER + - HPSA_MAX_CONCURRENT_PASSTHRUS, + .reserved_tags = HPSA_NRESERVED_CMDS, }; static inline u32 next_command(struct ctlr_info *h, u8 q) @@ -5612,7 +5613,7 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, struct CommandList *c = h->cmd_pool + idx; int refcount = 0; - if (idx < h->reserved_cmds || idx > h->nr_cmds) { + if (idx < HPSA_NRESERVED_CMDS || idx > h->nr_cmds) { dev_err(&h->pdev->dev, "Bad block tag: %d\n", idx); /* This value comes from the block layer...it's not our bug. */ BUG_ON(idx < HPSA_NRESERVED_CMDS || idx > h->nr_cmds); @@ -5680,8 +5681,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) */ for (;;) { - i = find_first_zero_bit(h->cmd_pool_bits, h->reserved_cmds); - if (unlikely(i >= h->reserved_cmds)) + i = find_first_zero_bit(h->cmd_pool_bits, HPSA_NRESERVED_CMDS); + if (unlikely(i >= HPSA_NRESERVED_CMDS)) continue; c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); @@ -7105,18 +7106,21 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) { +#define MIN_MAX_COMMANDS 16 + BUILD_BUG_ON(MIN_MAX_COMMANDS <= HPSA_NRESERVED_CMDS); + h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); /* Limit commands in memory limited kdump scenario. */ if (reset_devices && h->max_commands > 32) h->max_commands = 32; - if (h->max_commands < 16) { + if (h->max_commands < MIN_MAX_COMMANDS) { dev_warn(&h->pdev->dev, "Controller reports " "max supported commands of %d, an obvious lie. " "Using 16. Ensure that firmware is up to date.\n", h->max_commands); - h->max_commands = 16; + h->max_commands = MIN_MAX_COMMANDS; } } @@ -7137,7 +7141,6 @@ static void hpsa_find_board_params(struct ctlr_info *h) { hpsa_get_max_perf_mode_cmds(h); h->nr_cmds = h->max_commands; - h->reserved_cmds = hpsa_driver_template.reserved_tags; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); if (hpsa_supports_chained_sg_blocks(h)) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1643c9e2876f3c..187bb0d47974bf 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -136,7 +136,6 @@ struct ctlr_info { void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ - int reserved_cmds; /* Number reserved for driver use */ #define HPSA_CMDS_RESERVED_FOR_ABORTS 2 #define HPSA_CMDS_RESERVED_FOR_DRIVER 1 struct CfgTable __iomem *cfgtable; From c4b9caf300f310f3db921315dd26d7ed2b047d90 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:46 -0500 Subject: [PATCH 165/889] hpsa: remove unneeded lockup check Signed-off-by: Webb Scaled Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index eb1a98d7cf6c79..ec8e8e23eaf614 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4847,13 +4847,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) } c = cmd_tagged_alloc(h, cmd); - if (unlikely(lockup_detected(h))) { - cmd->result = DID_NO_CONNECT << 16; - cmd_tagged_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ - cmd->scsi_done(cmd); - return 0; - } - /* Call alternate submit routine for I/O accelerated commands. * Retries always go down the normal I/O path. */ From 6b4beb87f9d3f4ced3b1506e0b8c625280a3e64f Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:47 -0500 Subject: [PATCH 166/889] hpsa: reserve part of the tag space for the driver Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ec8e8e23eaf614..7ec59794ff5067 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -897,7 +897,6 @@ static struct scsi_host_template hpsa_driver_template = { .shost_attrs = hpsa_shost_attrs, .max_sectors = 8192, .no_write_same = 1, - .reserved_tags = HPSA_NRESERVED_CMDS, }; static inline u32 next_command(struct ctlr_info *h, u8 q) @@ -4993,7 +4992,7 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds; + sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; From d58927cb0d0121cc08f7b263993c400843efcc5a Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:47 -0500 Subject: [PATCH 167/889] hpsa: move tag selection to a helper function Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7ec59794ff5067..b7526d77407be6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5588,27 +5588,48 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } +/* + * The block layer has already gone to the trouble of picking out a unique, + * small-integer tag for this request. We use an offset from that value as + * an index to select our command block. (The offset allows us to reserve + * the low-numbered entries for our own uses.) + */ +static int hpsa_get_cmd_index(struct scsi_cmnd *scmd) +{ + struct scsi_device *dev = scmd->device; + int idx = scmd->request->tag; + + if (idx < 0) { + dev_err(&dev->sdev_dev , "Invalid block tag: %d\n", idx); + /* This value comes from an upper layer...it's not our bug. */ + BUG_ON(idx < 0); + } + + /* Offset to leave space for internal cmds. */ + idx += HPSA_NRESERVED_CMDS; + + return idx; +} + /* * For operations with an associated SCSI command, a command block is allocated * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the * block request tag as an index into a table of entries. cmd_tagged_free() is * the complement, although cmd_free() may be called instead. - * - * The block layer has already gone to the trouble of picking out a unique, - * small-integer tag for this request, and it was squirreled away in the SCSI - * command. We use that value as an index to select our command block. */ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, struct scsi_cmnd *scmd) { - int idx = scmd->request->tag; + int idx = hpsa_get_cmd_index(scmd); struct CommandList *c = h->cmd_pool + idx; int refcount = 0; - if (idx < HPSA_NRESERVED_CMDS || idx > h->nr_cmds) { + if (idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds) { dev_err(&h->pdev->dev, "Bad block tag: %d\n", idx); - /* This value comes from the block layer...it's not our bug. */ - BUG_ON(idx < HPSA_NRESERVED_CMDS || idx > h->nr_cmds); + /* The index value comes from the block layer, so if it's out of + * bounds, it's probably not our bug. + */ + BUG_ON(idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds); } refcount = atomic_inc_return(&c->refcount); From e2d52813c39879006c9f3f82f72f532ebcffa8f0 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Mon, 20 Oct 2014 17:01:48 -0500 Subject: [PATCH 168/889] hpsa: add support for tagged allocation on kernels that pre-date blk-mq support If the blk-mq support isn't available, set up the SCSI tagged command queuing (tcq) and use the SCSI midlayer tag. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 57 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b7526d77407be6..13723c19c45bbc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1853,10 +1853,22 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); if (sd && (sd->expose_state & HPSA_SCSI_ADD)) { + int queue_depth = sd->queue_depth; + + if (queue_depth == 0) + queue_depth = sdev->host->can_queue; + sdev->hostdata = sd; - if (sd->queue_depth) + + if (shost_use_blk_mq(sdev->host)) { scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - sd->queue_depth); + queue_depth); + } else { + /* We depend on tags for cmd allocation. */ + BUG_ON(!sdev->tagged_supported); + scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); + scsi_activate_tcq(sdev, queue_depth); + } atomic_set(&sd->ioaccel_cmds_out, 0); } else { sdev->hostdata = NULL; @@ -4957,13 +4969,25 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) { if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else + if (shost_use_blk_mq(sdev->host)) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else { + /* We require tags for our internal cmd allocation; if + * the caller wants to switch tag types, that's fine, + * but don't let them be disabled. */ + if (tag_type) + scsi_set_tag_type(sdev, tag_type); + else + tag_type = scsi_get_tag_type(sdev); + } + } else { + BUG_ON(!shost_use_blk_mq(sdev->host)); tag_type = 0; + } return tag_type; } @@ -4999,6 +5023,11 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; + if (!shost_use_blk_mq(sh)) { + error = scsi_init_shared_tag_map(sh, sh->can_queue); + if (error) + goto fail_host_put; + } error = scsi_add_host(sh, &h->pdev->dev); if (error) goto fail_host_put; @@ -5589,15 +5618,17 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) } /* - * The block layer has already gone to the trouble of picking out a unique, - * small-integer tag for this request. We use an offset from that value as - * an index to select our command block. (The offset allows us to reserve - * the low-numbered entries for our own uses.) + * One of the upper layers has already gone to the trouble of picking out a + * unique, small-integer tag for this request. If the blk-mq support is not + * available, we use the SCSI tag in the SCSI command; otherwise, we use the + * block layer tag in the embedded request structure. We use an offset from + * that value as an index to select our command block. (The offset allows us to + * reserve the low-numbered entries for our own uses.) */ static int hpsa_get_cmd_index(struct scsi_cmnd *scmd) { struct scsi_device *dev = scmd->device; - int idx = scmd->request->tag; + int idx = shost_use_blk_mq(dev->host) ? scmd->request->tag : scmd->tag; if (idx < 0) { dev_err(&dev->sdev_dev , "Invalid block tag: %d\n", idx); From 3566a83218f366580580e431831bcfe7d0081880 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:48 -0500 Subject: [PATCH 169/889] hpsa: abort torture test code This is just debug/test code. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 64 ++++++++++++++++++++++++++++++++++++++++- drivers/scsi/hpsa.h | 3 ++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 13723c19c45bbc..bb68a6fdd17e8c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.8-0" +#define HPSA_DRIVER_VERSION "3.4.9-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -391,6 +391,39 @@ static ssize_t host_show_lockup_detector(struct device *dev, return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); } +static ssize_t host_store_abort_test(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost; + struct ctlr_info *h; + int len, value, timeout; + char tmpbuf[10]; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%d %d", &value, &timeout) != 2) + return -EINVAL; + shost = class_to_shost(dev); + h = shost_to_hba(shost); + h->abort_test = value; + h->abort_timeout = timeout; + return count; +} + +static ssize_t host_show_abort_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + return snprintf(buf, 20, "%d %d\n", h->abort_test, h->abort_timeout); +} + static u32 lockup_detected(struct ctlr_info *h); static ssize_t host_show_lockup_detected(struct device *dev, struct device_attribute *attr, char *buf) @@ -846,6 +879,8 @@ static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, host_show_lockup_detector, host_store_lockup_detector); static DEVICE_ATTR(lockup_detected, S_IRUGO, host_show_lockup_detected, NULL); +static DEVICE_ATTR(abort_test, S_IWUSR|S_IRUGO, + host_show_abort_test, host_store_abort_test); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -867,6 +902,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_raid_offload_debug, &dev_attr_lockup_detector, &dev_attr_lockup_detected, + &dev_attr_abort_test, NULL, }; @@ -1065,11 +1101,36 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; } +static void __enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c, int reply_queue); + +static void hpsa_abort_torture_worker(struct work_struct *work) +{ + struct CommandList *c = container_of(to_delayed_work(work), + struct CommandList, abort_torture_work); + dev_warn(&c->h->pdev->dev, "Submitting delayed command\n"); + __enqueue_cmd_and_start_io(c->h, c, DEFAULT_REPLY_QUEUE); +} + static void __enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c, int reply_queue) { + if (h->abort_test > 0 && + (c->cmd_type == CMD_SCSI || + c->cmd_type == CMD_IOACCEL1|| + c->cmd_type == CMD_IOACCEL2)) { + h->abort_test = 0; + dev_warn(&h->pdev->dev, "delaying command for %d secs.\n", + h->abort_timeout); + INIT_DELAYED_WORK(&c->abort_torture_work, + hpsa_abort_torture_worker); + schedule_delayed_work(&c->abort_torture_work, h->abort_timeout * HZ); + atomic_inc(&h->cmds_sent); + return; + } dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); + atomic_inc(&h->cmds_sent); switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c, reply_queue); @@ -7900,6 +7961,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); + atomic_set(&h->cmds_sent, 0); h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 187bb0d47974bf..f364bff8851977 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -266,6 +266,9 @@ struct ctlr_info { atomic_t abort_cmds_available; wait_queue_head_t abort_cmd_wait_queue; wait_queue_head_t abort_sync_wait_queue; + atomic_t cmds_sent; + int abort_test; + int abort_timeout; }; struct offline_device_entry { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 74f200e0256267..5ab1b13f996f83 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -428,6 +428,7 @@ struct CommandList { struct completion *waiting; struct scsi_cmnd *scsi_cmd; struct work_struct work; + struct delayed_work abort_torture_work; /* For commands using either of the two "ioaccel" paths to * bypass the RAID stack and go directly to the physical disk From ac71f8d569c865ee3e029c5c56113898a7a15be5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:49 -0500 Subject: [PATCH 170/889] hpsa: fix bad lun and target update messages lun and target were being printed as -1 instead of the correct values Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bb68a6fdd17e8c..fb14a9b48831f7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1325,16 +1325,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, dev_info(&h->pdev->dev, "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", - hostno, new_entry->bus, new_entry->target, new_entry->lun, - scsi_device_type(new_entry->devtype), - new_entry->vendor, - new_entry->model, - new_entry->raid_level > RAID_UNKNOWN ? - "RAID-?" : raid_label[new_entry->raid_level], - new_entry->offload_config ? '+' : '-', - new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state, - new_entry->queue_depth); + hostno, h->dev[entry]->bus, + h->dev[entry]->target, h->dev[entry]->lun, + scsi_device_type(h->dev[entry]->devtype), + h->dev[entry]->vendor, + h->dev[entry]->model, + h->dev[entry]->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[h->dev[entry]->raid_level], + h->dev[entry]->offload_config ? '+' : '-', + h->dev[entry]->offload_enabled ? '+' : '-', + h->dev[entry]->expose_state, + h->dev[entry]->queue_depth); } /* Replace an entry from h->dev[] array. */ From f23dc899afcddebe26c9c5c4343d28f7d89b7ae6 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:50 -0500 Subject: [PATCH 171/889] hpsa: do not poll device with TUR after device reset If a logical drive has failed, resetting it will ensure outstanding commands are completed, but polling it with TURs after the reset will not work because the TURs will never report good status. So successful TUR should not be a condition of success for the device reset error handler. NOTE: THERE IS A PROBLEM WITH THIS PATCH. While it fixes the problem that a failed logical drive will never become ready, and so fixes the problem that the reset device error handler would get stuck for too long waiting for a failed logical drive to become ready, it defeats the purpose of that barrage of test unit readys, which was to avoid races of the completions of aborted commands with the device reset command completion in the completion queues. So, an alternative solution for those races is needed (webb is working on this). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index fb14a9b48831f7..9882a26ff9dd5f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5250,9 +5250,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, DEFAULT_REPLY_QUEUE); if (rc == 0) - if (!wait_for_device_to_become_ready(h, dev->scsi3addr, - DEFAULT_REPLY_QUEUE)) - return SUCCESS; + return SUCCESS; dev_warn(&h->pdev->dev, "resetting scsi %d:%d:%d:%d failed\n", From cdc2e9490528196ba4f71c2bfc35e9cd6bb668d0 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:50 -0500 Subject: [PATCH 172/889] hpsa: fix queue_depth calculation for all RAID levels The logical drive queue_depth is ending up 1024 for RAID-5 made from 4 physical drives and other more complex RAID levels, which is too high. The calculation is being confused by parity rotation, ending up adding the depths supported by the drives for each different rotation combination (row_cnt). Stop counting after the true number of physical drives, which is: map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row) Signed-off-by: Robert Elliott --- drivers/scsi/hpsa.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9882a26ff9dd5f..02ab0956967278 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1636,6 +1636,8 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, int i, j; int nraid_map_entries = map->row_cnt * map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row); + int nphys_disk = map->layout_map_count * + (map->data_disks_per_row + map->metadata_disks_per_row); int qdepth; if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) @@ -1655,8 +1657,9 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; logical_drive->phys_disk[i] = dev[j]; - qdepth = min(h->nr_cmds, qdepth + - logical_drive->phys_disk[i]->queue_depth); + if (i < nphys_disk) + qdepth = min(h->nr_cmds, qdepth + + logical_drive->phys_disk[i]->queue_depth); break; } From ca6d4078be30c6105757ebdf940377ac358fcc7d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:01:51 -0500 Subject: [PATCH 173/889] hpsa: check pci ids This isn't meant to go into the driver except temporarily as a way to check that the pci id tables are somewhat sane -- match each other, don't contain duplicates, etc. --- drivers/scsi/hpsa.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 02ab0956967278..f249146f2fb099 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7918,6 +7918,83 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) hpsa_requeue_worker(h, &h->monitor_ctlr_work); } +static void check_board_id_tables(void) +{ + int i, j, found; + uint32_t board_id; + int count; + + for (i = 0; i < ARRAY_SIZE(products); i++) { + board_id = products[i].board_id; + if (board_id == 0xFFFF103C) /* sentinel entry */ + continue; + found = 0; + count = 0; + for (j = 0; j < ARRAY_SIZE(hpsa_pci_device_id); j++) { + uint32_t bid; + + bid = (hpsa_pci_device_id[j].subdevice << 16) | + hpsa_pci_device_id[j].subvendor; + if (bid == board_id) { + found = 1; + if (i != j) { + printk(KERN_WARNING HPSA + ": products[%d] (%s) found at pci table entry %d\n", + i, products[i].product_name, j); + } + count++; + } + } + if (!found) + printk(KERN_WARNING HPSA + ": products[%d] (%s) not found in pci table\n", + i, products[i].product_name); + if (count > 1) + printk(KERN_WARNING HPSA + ": products[%d] (%s) has duplicate entries in pci table\n", + i, products[i].product_name); + } + + for (i = 0; i < ARRAY_SIZE(hpsa_pci_device_id); i++) { + board_id = (hpsa_pci_device_id[i].subdevice << 16) | + hpsa_pci_device_id[i].subvendor; + if (hpsa_pci_device_id[i].vendor == 0) /* sentinel */ + continue; + if (hpsa_pci_device_id[i].subvendor == PCI_ANY_ID && + hpsa_pci_device_id[i].subdevice == PCI_ANY_ID) + continue; + count = 0; + found = 0; + for (j = 0; j < ARRAY_SIZE(products); j++) { + if (board_id == products[j].board_id) { + if (j != i) { + printk(KERN_WARNING HPSA + ": pci table entry %d found at product entry %d (%s)\n", + i, j, products[j].product_name); + } + found = 1; + count++; + } + } + if (!found) + printk(KERN_WARNING HPSA + ": pci table entry %d (%04x:%04x) not found in product table\n", + i, hpsa_pci_device_id[i].subvendor, + hpsa_pci_device_id[i].subdevice); + if (count > 1) + printk(KERN_WARNING HPSA + ": pci table entry %d (%04x:%04x) has duplicate product[] entries\n", + i, hpsa_pci_device_id[i].subvendor, + hpsa_pci_device_id[i].subdevice); + } + if (ARRAY_SIZE(products) != ARRAY_SIZE(hpsa_pci_device_id) - 1) { + printk(KERN_WARNING HPSA + ": suspicious relative cardinality of products vs hpsa_pci_device_id (%lu/%lu)\n", + (unsigned long) ARRAY_SIZE(products), + (unsigned long) ARRAY_SIZE(hpsa_pci_device_id)); + } +} + static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; @@ -7925,6 +8002,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) int try_soft_reset = 0; unsigned long flags; + check_board_id_tables(); if (number_of_controllers == 0) printk(KERN_INFO DRIVER_NAME "\n"); From dbc50919d96e3d32c2bcc52ad462da723c980dbc Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:51 -0500 Subject: [PATCH 174/889] hpsa: remove 0x from queue depth print which is in decimal The queue depth printed at startup is in decimal, so shouldn't have a 0x prefix. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f249146f2fb099..4eaa77d18a499a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6976,7 +6976,7 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb) readl(&(tb->HostWrite.CoalIntDelay))); dev_info(dev, " Coalesce Interrupt Count = 0x%x\n", readl(&(tb->HostWrite.CoalIntCount))); - dev_info(dev, " Max outstanding commands = 0x%d\n", + dev_info(dev, " Max outstanding commands = %d\n", readl(&(tb->CmdsOutMax))); dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes))); for (i = 0; i < 16; i++) From e008e23f31ae3a4cd891f2327d9364178603a537 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:52 -0500 Subject: [PATCH 175/889] hpsa: clean up register_scsi clean up new block layer tag error handling Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4eaa77d18a499a..9d97080651d83a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5090,18 +5090,23 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->unique_id = sh->irq; if (!shost_use_blk_mq(sh)) { error = scsi_init_shared_tag_map(sh, sh->can_queue); - if (error) + if (error) { + dev_err(&h->pdev->dev, + "%s: scs_init_shared_tag_map failed for controller %d\n", + __func__, h->ctlr); goto fail_host_put; + } } error = scsi_add_host(sh, &h->pdev->dev); - if (error) + if (error) { + dev_err(&h->pdev->dev, "%s: scsi_add_host failed for controller %d\n", + __func__, h->ctlr); goto fail_host_put; + } scsi_scan_host(sh); return 0; fail_host_put: - dev_err(&h->pdev->dev, "%s: scsi_add_host" - " failed for controller %d\n", __func__, h->ctlr); scsi_host_put(sh); return error; fail: From 1c81a3d691ae8dde72346d44330ec6dfab983084 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:53 -0500 Subject: [PATCH 176/889] hpsa: propagate errors in ioacccel2_sg_chain_blocks The error, if any, returned by hpsa_allocate_ioaccel2_sg_chain_blocks to hpsa_alloc_ioaccel2_cmd_and_bft should be returned upstream rather than assumed to be -ENOMEM. This differs slightly from hpsa_alloc_ioaccel1_cmd_and_bft, which does not call another hpsa_allocate function and only has -ENOMEM to return from some kmalloc calls. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9d97080651d83a..81e8400c2aa74b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8606,6 +8606,8 @@ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) /* Allocate ioaccel2 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { + int rc; + /* Allocate ioaccel2 mode command blocks and block fetch table */ h->ioaccel_maxsg = @@ -8625,10 +8627,13 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) sizeof(u32)), GFP_KERNEL); if ((h->ioaccel2_cmd_pool == NULL) || - (h->ioaccel2_blockFetchTable == NULL)) + (h->ioaccel2_blockFetchTable == NULL)) { + rc = -ENOMEM; goto clean_up; + } - if (hpsa_allocate_ioaccel2_sg_chain_blocks(h)) + rc = hpsa_allocate_ioaccel2_sg_chain_blocks(h); + if (rc) goto clean_up; memset(h->ioaccel2_cmd_pool, 0, @@ -8637,7 +8642,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) clean_up: hpsa_free_ioaccel2_cmd_and_bft(h); - return -ENOMEM; + return rc; } /* Free items allocated by hpsa_put_ctlr_into_performant_mode */ From a44b3b746c3708d978c0a0db0bde7e1a2d6459b7 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:53 -0500 Subject: [PATCH 177/889] hpsa: free ioaccel2_sg_chain_blocks correctly hpsa_put_ctlr_into_performant_mode is the function that allocates ioaccel2_sg_chain_blocks (via hpsa_alloc_ioaccel2_cmd_and_bft), so hpsa_free_performant_mode should free it (via hpsa_free_ioaccel2_cmd_and_bft). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 81e8400c2aa74b..1f525d58cf34bc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7688,7 +7688,6 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_performant_mode(h); /* init_one 7 */ - hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ @@ -8292,7 +8291,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ hpsa_unregister_scsi(h); /* init_one "8" */ - hpsa_free_ioaccel2_sg_chain_blocks(h); kfree(h->hba_inquiry_data); /* init_one "8" */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ @@ -8596,6 +8594,8 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) /* Free ioaccel2 mode command blocks and block fetch table */ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) { + hpsa_free_ioaccel2_sg_chain_blocks(h); + if (h->ioaccel2_cmd_pool) pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), From 61964a0cf978263e5c7a8a63c4d8e3b22bf47f5b Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:54 -0500 Subject: [PATCH 178/889] hpsa: call pci_release_regions after pci_disable_device Despite the fact that PCI devices are enabled in this order: 1. pci_enable_device 2. pci_request_regions Documentation/PCI/pci.txt specifies that they be undone in this order 1. pci_disable_device 2. pci_release_regions Tested by injecting error in the call to pci_enable_device in hpsa_init_one -> hpsa_pci_init: [ 9.095001] hpsa 0000:04:00.0: failed to enable PCI device [ 9.095005] hpsa: probe of 0000:04:00.0 failed with error -22 (-22 is -EINVAL) and then in the call pci_request_regions: [ 9.178623] hpsa 0000:04:00.0: failed to obtain PCI resources [ 9.178671] hpsa: probe of 0000:04:00.0 failed with error -16 (-16 is -EBUSY) and then by adding reset_devices to the kernel command line and inject errors into the two calls to pci_enable_device and the call to pci_request_regions in hpsa_init_one -> hpsa_init_reset_devices. (inject on 6th call, 1st to hpsa2) [ 62.413750] hpsa 0000:04:00.0: Failed to enable PCI device (inject on 7th call, 2nd to hpsa2) [ 62.807571] hpsa 0000:04:00.0: failed to enable device. (inject on 8th call, 3rd to hpsa2) [ 62.697198] hpsa 0000:04:00.0: failed to obtain PCI resources [ 62.697234] hpsa: probe of 0000:04:00.0 failed with error -16 The reset_devices path calls return -ENODEV on failure rather than passing the result, which apparently doesn't cause the pci driver to print anything. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Signed-off-by: Don Brace < don.brace@pmcs.com > --- drivers/scsi/hpsa.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1f525d58cf34bc..220a6333ad71fc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7394,8 +7394,12 @@ static void hpsa_free_pci_init(struct ctlr_info *h) hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ - pci_release_regions(h->pdev); /* pci_init 2 */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); /* pci_init 1 */ + pci_release_regions(h->pdev); /* pci_init 2 */ } /* several items must be freed later */ @@ -7418,6 +7422,7 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_enable_device(h->pdev); if (err) { dev_err(&h->pdev->dev, "failed to enable PCI device\n"); + pci_disable_device(h->pdev); return err; } @@ -7428,7 +7433,8 @@ static int hpsa_pci_init(struct ctlr_info *h) if (err) { dev_err(&h->pdev->dev, "failed to obtain PCI resources\n"); - goto clean1; /* pci */ + pci_disable_device(h->pdev); + return err; } hpsa_interrupt_mode(h); err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); @@ -7465,9 +7471,12 @@ static int hpsa_pci_init(struct ctlr_info *h) iounmap(h->vaddr); clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); - pci_release_regions(h->pdev); -clean1: /* pci */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); + pci_release_regions(h->pdev); return err; } @@ -7694,6 +7703,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); /* pci_init 2 */ kfree(h); /* init_one 1 */ From 7714d639d0bf681bb3ed29e0e76eac8013c7e1b4 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:54 -0500 Subject: [PATCH 179/889] hpsa: propagate hard_reset failures in reset_devices mode Return the real reason for kdump_hard_reset failure rather than change them all to -ENODEV. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 220a6333ad71fc..2887662188654e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7528,11 +7528,8 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) * "performant mode". Or, it might be 640x, which can't reset * due to concerns about shared bbwc between 6402/6404 pair. */ - if (rc) { - if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */ - rc = -ENODEV; + if (rc) goto out_disable; - } /* Now try to get the controller to respond to a no-op */ dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); From 64feb0961ef53abf5151d17d94c78623e25a48f2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:55 -0500 Subject: [PATCH 180/889] hpsa: propagate return value from board ID lookup If the board ID lookup function fails, return the return code rather than return -ENODEV. The only board ID failure reason right now is -ENODEV, so this just provides more informative prints in kdump and adapts to future changes. Tested with error injection while booting with reset_devices on the kernel command line: [ 62.804324] injecting error in inj_hpsa_lookup_board_id: 1 11 [ 62.804423] hpsa 0000:04:00.0: Board ID not found (the pci probe layer does not print an additional message if -ENODEV is the reason) Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2887662188654e..20b17844303aee 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6863,8 +6863,12 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) */ rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0 || !ctlr_is_resettable(board_id)) { - dev_warn(&pdev->dev, "Not resetting device.\n"); + if (rc < 0) { + dev_warn(&pdev->dev, "Board ID not found\n"); + return rc; + } + if (!ctlr_is_resettable(board_id)) { + dev_warn(&pdev->dev, "Controller not resettable\n"); return -ENODEV; } @@ -7409,7 +7413,7 @@ static int hpsa_pci_init(struct ctlr_info *h) prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); if (prod_index < 0) - return -ENODEV; + return prod_index; h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); From 55317328a3bda4ab75935a4843cb3bc32602c4e1 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:55 -0500 Subject: [PATCH 181/889] hpsa: downgrade the Waiting for no-op print to dev_info There is nothing worrisome about the "Waiting for controller to respond to no-op" print, so use dev_info rather than dev_warn. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 20b17844303aee..2ea395de3f6d59 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7536,7 +7536,7 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) goto out_disable; /* Now try to get the controller to respond to a no-op */ - dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); + dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n"); for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { if (hpsa_noop(pdev) == 0) break; From 7cae9c9b6ddeacbf904e461618804ada75fb9260 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:56 -0500 Subject: [PATCH 182/889] hpsa: set pointers to NULL after freeing After freeing dynamically allocated pointers, set the variable or structure containing the pointer to NULL so a stale address cannot inadvertently be used. Do this for every case except local stack variables at the end of a function Also zero out size variables that match the pointers Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 ++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2ea395de3f6d59..d252b471a3c7ec 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1881,6 +1881,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * since it didn't get added to scsi mid layer */ fixup_botched_add(h, added[i]); + added[i] = NULL; } free_and_out: @@ -7037,9 +7038,11 @@ static void hpsa_disable_interrupt_mode(struct ctlr_info *h) if (h->msix_vector) { if (h->pdev->msix_enabled) pci_disable_msix(h->pdev); + h->msix_vector = 0; } else if (h->msi_vector) { if (h->pdev->msi_enabled) pci_disable_msi(h->pdev); + h->msi_vector = 0; } #endif /* CONFIG_PCI_MSI */ } @@ -7179,8 +7182,14 @@ static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, static void hpsa_free_cfgtables(struct ctlr_info *h) { - iounmap(h->transtable); - iounmap(h->cfgtable); + if (h->transtable) { + iounmap(h->transtable); + h->transtable = NULL; + } + if (h->cfgtable) { + iounmap(h->cfgtable); + h->cfgtable = NULL; + } } /* Find and map CISS config table and transfer table @@ -7397,6 +7406,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h) { hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ + h->vaddr = NULL; hpsa_disable_interrupt_mode(h); /* pci_init 2 */ /* * call pci_disable_device before pci_release_regions per @@ -7473,6 +7483,7 @@ static int hpsa_pci_init(struct ctlr_info *h) hpsa_free_cfgtables(h); clean3: /* vaddr, intmode+region, pci */ iounmap(h->vaddr); + h->vaddr = NULL; clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); /* @@ -7554,15 +7565,22 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) static void hpsa_free_cmd_pool(struct ctlr_info *h) { kfree(h->cmd_pool_bits); - if (h->cmd_pool) + h->cmd_pool_bits = NULL; + if (h->cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct CommandList), h->cmd_pool, h->cmd_pool_dhandle); - if (h->errinfo_pool) + h->cmd_pool = NULL; + h->cmd_pool_dhandle = 0; + } + if (h->errinfo_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct ErrorInfo), h->errinfo_pool, h->errinfo_pool_dhandle); + h->errinfo_pool = NULL; + h->errinfo_pool_dhandle = 0; + } } static int hpsa_alloc_cmd_pool(struct ctlr_info *h) @@ -7610,12 +7628,14 @@ static void hpsa_free_irqs(struct ctlr_info *h) i = h->intr_mode; irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); + h->q[i] = 0; return; } for (i = 0; i < h->msix_vector; i++) { irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); + h->q[i] = 0; } } @@ -7651,6 +7671,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, intxhandler, IRQF_SHARED, h->devname, &h->q[h->intr_mode]); } + irq_set_affinity_hint(h->intr[h->intr_mode], NULL); } if (rc) { dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", @@ -7692,6 +7713,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) h->reply_queue[i].head, h->reply_queue[i].busaddr); h->reply_queue[i].head = NULL; h->reply_queue[i].busaddr = 0; + h->reply_queue_size = 0; } } @@ -7701,15 +7723,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ - hpsa_free_cfgtables(h); /* pci_init 4 */ - iounmap(h->vaddr); /* pci_init 3 */ - hpsa_disable_interrupt_mode(h); /* pci_init 2 */ - /* - * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt - */ - pci_disable_device(h->pdev); - pci_release_regions(h->pdev); /* pci_init 2 */ + hpsa_free_pci_init(h); /* init_one 3 */ kfree(h); /* init_one 1 */ } @@ -8215,8 +8229,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean3: /* pci, lockup, wq/aer/h */ hpsa_free_pci_init(h); clean2: /* lockup, wq/aer/h */ - if (h->lockup_detected) + if (h->lockup_detected) { free_percpu(h->lockup_detected); + h->lockup_detected = NULL; + } clean1: /* wq/aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); @@ -8276,8 +8292,10 @@ static void hpsa_free_device_info(struct ctlr_info *h) { int i; - for (i = 0; i < h->ndevices; i++) + for (i = 0; i < h->ndevices; i++) { kfree(h->dev[i]); + h->dev[i] = NULL; + } } static void hpsa_remove_one(struct pci_dev *pdev) @@ -8306,6 +8324,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_unregister_scsi(h); /* init_one "8" */ kfree(h->hba_inquiry_data); /* init_one "8" */ + h->hba_inquiry_data = NULL; /* init_one "8" */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ @@ -8316,6 +8335,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_pci_init(h); /* init_one 3 */ free_percpu(h->lockup_detected); /* init_one 2 */ + h->lockup_detected = NULL; /* init_one 2 */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); /* init_one 1 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ @@ -8523,7 +8543,7 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->ReplyQueue = 0; cp->tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); cp->host_addr = - cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + + cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + (i * sizeof(struct io_accel1_cmd)))); } } else if (trans_support & CFGTBL_Trans_io_accel2) { @@ -8562,11 +8582,15 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) /* Free ioaccel1 mode command blocks and block fetch table */ static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h) { - if (h->ioaccel_cmd_pool) + if (h->ioaccel_cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); + h->ioaccel_cmd_pool = NULL; + h->ioaccel_cmd_pool_dhandle = 0; + } kfree(h->ioaccel1_blockFetchTable); + h->ioaccel1_blockFetchTable = NULL; } /* Allocate ioaccel1 mode command blocks and block fetch table */ @@ -8610,11 +8634,15 @@ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) { hpsa_free_ioaccel2_sg_chain_blocks(h); - if (h->ioaccel2_cmd_pool) + if (h->ioaccel2_cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); + h->ioaccel2_cmd_pool = NULL; + h->ioaccel2_cmd_pool_dhandle = 0; + } kfree(h->ioaccel2_blockFetchTable); + h->ioaccel2_blockFetchTable = NULL; } /* Allocate ioaccel2 mode command blocks and block fetch table */ @@ -8663,6 +8691,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) static void hpsa_free_performant_mode(struct ctlr_info *h) { kfree(h->blockFetchTable); + h->blockFetchTable = NULL; hpsa_free_reply_queues(h); hpsa_free_ioaccel1_cmd_and_bft(h); hpsa_free_ioaccel2_cmd_and_bft(h); @@ -8733,6 +8762,7 @@ static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) clean2: /* bft, rq, ioaccel */ kfree(h->blockFetchTable); + h->blockFetchTable = NULL; clean1: /* rq, ioaccel */ hpsa_free_reply_queues(h); hpsa_free_ioaccel1_cmd_and_bft(h); From 9faf14508948f33d70b6f35f09ab69f2f93722db Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:57 -0500 Subject: [PATCH 183/889] hpsa: notice all request_irq errors In MSI and MSI-X mode, where hpsa asks for more than one interrupt, hpsa_request_irqs forgets if the first request_irq calls failed if later ones succeed. It needs exit the loop on any failure rather than continue, freeing all irqs that were requested until that point. Also, it needs to clear out the q numbers up to MAX_REPLY_QUEUES. The same is true for the general hpsa_free_irqs function. Tested with error injection of -ENOSYS on the 4th call: [ 9.277691] injecting error in inj_request_irq: 1 4 [ 9.277780] hpsa 0000:02:00.0: failed to get irq 35 for hpsa1 [ 10.711623] scsi host1: Error handler scsi_eh_1 exiting [ 10.739170] hpsa: probe of 0000:02:00.0 failed with error -38 Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d252b471a3c7ec..27ba92325e9f3c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7637,6 +7637,8 @@ static void hpsa_free_irqs(struct ctlr_info *h) free_irq(h->intr[i], &h->q[i]); h->q[i] = 0; } + for (; i < MAX_REPLY_QUEUES; i++) + h->q[i] = 0; } /* returns 0 on success; cleans up and returns -Enn on error */ @@ -7655,10 +7657,25 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) { /* If performant mode and MSI-X, use multiple reply queues */ - for (i = 0; i < h->msix_vector; i++) + for (i = 0; i < h->msix_vector; i++) { rc = request_irq(h->intr[i], msixhandler, 0, h->devname, &h->q[i]); + if (rc) { + int j; + + dev_err(&h->pdev->dev, + "failed to get irq %d for %s\n", + h->intr[i], h->devname); + for (j = 0; j < i; j++) { + free_irq(h->intr[j], &h->q[j]); + h->q[j] = 0; + } + for (; j < MAX_REPLY_QUEUES; j++) + h->q[j] = 0; + return rc; + } + } hpsa_irq_affinity_hints(h); } else { /* Use single reply pool */ From 5fc8412e22f315cc6df4b30c8e71420821dc863a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:57 -0500 Subject: [PATCH 184/889] hpsa: skip free_irq calls if irqs are not allocated If try_soft_reset fails to re-allocate irqs, the error exit starts with free_irq calls, which generate kernel WARN messages since they were already freed a few lines earlier. Jump to the next exit label to skip the free_irq calls. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 27ba92325e9f3c..439c9c3ab5df45 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8180,7 +8180,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - goto clean4; + /* clean4 starts with free_irqs, but that was just + * done. Then, request_irqs_failed, so there is + * nothing to free. So, goto the next label. */ + goto clean3; } rc = hpsa_kdump_soft_reset(h); From 54fa069062aa5893d30716ecb3185ecddea4ab8e Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:58 -0500 Subject: [PATCH 185/889] hpsa: cleanup for init_one step 2 in kdump In hpsa_undo_allocations_after_kdump_soft_reset, the things allocated in hpsa_init_one step 2 - h->resubmit_wq and h->lockup_detected need to be freed, in the right order. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 439c9c3ab5df45..e3f8fa51e88561 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7741,6 +7741,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ hpsa_free_pci_init(h); /* init_one 3 */ + free_percpu(h->lockup_detected); /* init_one 2 */ + h->lockup_detected = NULL; /* init_one 2 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 1 */ kfree(h); /* init_one 1 */ } From 81bc4c3b755b3ea03a1d8257c0eca53882f4a397 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:58 -0500 Subject: [PATCH 186/889] hpsa: fix try_soft_reset error handling If registering the special interrupt handlers in hpsa_init_one before a soft reset fails, the error exit needs to deallocate everything that was allocated before. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e3f8fa51e88561..24afe04400fb21 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8184,16 +8184,20 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* clean4 starts with free_irqs, but that was just - * done. Then, request_irqs_failed, so there is - * nothing to free. So, goto the next label. */ + /* cannot goto clean7 or free_irqs will be called + * again. Instead, do its work */ + hpsa_free_performant_mode(h); /* clean7 */ + hpsa_free_sg_chain_blocks(h); /* clean6 */ + hpsa_free_cmd_pool(h); /* clean5 */ + /* skip hpsa_free_irqs(h) clean4 since that + * was just called before request_irqs failed */ goto clean3; } rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean4; + goto clean7; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8214,7 +8218,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpsa_undo_allocations_after_kdump_soft_reset(h); try_soft_reset = 0; if (rc) - /* don't go to clean4, we already unallocated */ + /* don't goto clean, we already unallocated */ return -ENODEV; goto reinit_after_soft_reset; From 629808b6ab9bb33d48fcb25fa5a6af8f11358fe9 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:01:59 -0500 Subject: [PATCH 187/889] hpsa: create workqueue after the driver is ready for use Don't create the resubmit workqueue in hpsa_init_one until everything else is ready to use, so everything can be freed in reverse order of when they were allocated without risking freeing things while workqueue items are still active. Destroy the workqueue in the right order in hpsa_undo_allocations_after_kdump_soft_reset too. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 65 ++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 24afe04400fb21..525ac35ea7ff51 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8096,24 +8096,18 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); atomic_set(&h->cmds_sent, 0); - h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); - if (!h->resubmit_wq) { - dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); - rc = -ENOMEM; - goto clean1; /* aer/h */ - } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { dev_err(&h->pdev->dev, "Failed to allocate lockup detector\n"); rc = -ENOMEM; - goto clean1; /* wq/aer/h */ + goto clean1; /* aer/h */ } set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); if (rc) - goto clean2; /* lockup, wq/aer/h */ + goto clean2; /* lockup, aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); h->ctlr = number_of_controllers; @@ -8129,7 +8123,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean3; /* pci, lockup, wq/aer/h */ + goto clean3; /* pci, lockup, aer/h */ } } @@ -8138,16 +8132,16 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) - goto clean3; /* pci, lockup, wq/aer/h */ + goto clean3; /* pci, lockup, aer/h */ dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean4; /* irq, pci, lockup, wq/aer/h */ + goto clean4; /* irq, pci, lockup, aer/h */ rc = hpsa_alloc_sg_chain_blocks(h); if (rc) - goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ + goto clean5; /* cmd, irq, pci, lockup, aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); init_waitqueue_head(&h->abort_sync_wait_queue); @@ -8160,7 +8154,15 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->devlock); rc = hpsa_put_ctlr_into_performant_mode(h); if (rc) - goto clean6; /* sg, cmd, irq, pci, lockup, wq/aer/h */ + goto clean6; /* sg, cmd, irq, pci, lockup, aer/h */ + + /* create the resubmit workqueue */ + h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!h->resubmit_wq) { + dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); + rc = -ENOMEM; + goto clean7; /* perf, sg, cmd, irq, pci, lockup, aer/h */ + } /* At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -8184,8 +8186,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* cannot goto clean7 or free_irqs will be called + /* cannot goto clean8 or free_irqs will be called * again. Instead, do its work */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* clean8 */ hpsa_free_performant_mode(h); /* clean7 */ hpsa_free_sg_chain_blocks(h); /* clean6 */ hpsa_free_cmd_pool(h); /* clean5 */ @@ -8197,7 +8201,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean7; + goto clean8; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8235,7 +8239,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpsa_hba_inquiry(h); rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ if (rc) - goto clean7; + goto clean8; /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -8247,23 +8251,24 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean7: /* perf, sg, cmd, irq, pci, lockup, wq/aer/h */ +clean8: /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); +clean7: /* perf, sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_performant_mode(h); -clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); -clean5: /* cmd, irq, pci, lockup, wq/aer/h */ +clean6: /* sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, pci, lockup, aer/h */ hpsa_free_cmd_pool(h); -clean4: /* irq, pci, lockup, wq/aer/h */ +clean4: /* irq, pci, lockup, aer/h */ hpsa_free_irqs(h); -clean3: /* pci, lockup, wq/aer/h */ +clean3: /* pci, lockup, aer/h */ hpsa_free_pci_init(h); -clean2: /* lockup, wq/aer/h */ +clean2: /* lockup, aer/h */ if (h->lockup_detected) { free_percpu(h->lockup_detected); h->lockup_detected = NULL; } -clean1: /* wq/aer/h */ - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); +clean1: /* aer/h */ /* (void) pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; @@ -8350,9 +8355,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ - hpsa_unregister_scsi(h); /* init_one "8" */ - kfree(h->hba_inquiry_data); /* init_one "8" */ - h->hba_inquiry_data = NULL; /* init_one "8" */ + hpsa_unregister_scsi(h); /* init_one 9 */ + kfree(h->hba_inquiry_data); /* init_one 9 */ + h->hba_inquiry_data = NULL; /* init_one 9 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 8 */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ @@ -8364,8 +8371,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* init_one 1 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ kfree(h); /* init_one 1 */ } From 35d6e26274a851b55c90f1160bcdd9e64f524d17 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:00 -0500 Subject: [PATCH 188/889] hpsa: add interrupt number to /proc/interrupts interrupt name Add the interrupt number to the interrupt names that appear in /proc/interrupts, so they are unique Also, delete the IRQ and DAC prints. Other parts of the kernel already print the IRQ assignments, and dual-address-cycle support has not been interesting since the parallel PCI bus went from 32 to 64 bits wide. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 20 ++++++++++++++------ drivers/scsi/hpsa.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 525ac35ea7ff51..ff7dd9439c4e83 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7658,8 +7658,9 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) { /* If performant mode and MSI-X, use multiple reply queues */ for (i = 0; i < h->msix_vector; i++) { + sprintf(h->intrname[i], "%s-msix%d", h->devname, i); rc = request_irq(h->intr[i], msixhandler, - 0, h->devname, + 0, h->intrname[i], &h->q[i]); if (rc) { int j; @@ -7680,12 +7681,22 @@ static int hpsa_request_irqs(struct ctlr_info *h, } else { /* Use single reply pool */ if (h->msix_vector > 0 || h->msi_vector) { + if (h->msix_vector) + sprintf(h->intrname[h->intr_mode], + "%s-msix", h->devname); + else + sprintf(h->intrname[h->intr_mode], + "%s-msi", h->devname); rc = request_irq(h->intr[h->intr_mode], - msixhandler, 0, h->devname, + msixhandler, 0, + h->intrname[h->intr_mode], &h->q[h->intr_mode]); } else { + sprintf(h->intrname[h->intr_mode], + "%s-intx", h->devname); rc = request_irq(h->intr[h->intr_mode], - intxhandler, IRQF_SHARED, h->devname, + intxhandler, IRQF_SHARED, + h->intrname[h->intr_mode], &h->q[h->intr_mode]); } irq_set_affinity_hint(h->intr[h->intr_mode], NULL); @@ -8133,9 +8144,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) goto clean3; /* pci, lockup, aer/h */ - dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", - h->devname, pdev->device, - h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean4; /* irq, pci, lockup, aer/h */ diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index f364bff8851977..5643d55ac5a805 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -219,6 +219,7 @@ struct ctlr_info { int remove_in_progress; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; + char intrname[MAX_REPLY_QUEUES][16]; /* "hpsa0-msix00" names */ u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ #define HPSATMF_BITS_SUPPORTED (1 << 0) #define HPSATMF_PHYS_LUN_RESET (1 << 1) From 24c83d934503a7c34ba54bc0788400ea5efdc756 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:00 -0500 Subject: [PATCH 189/889] hpsa: use scsi host_no as hpsa controller number Rather than numbering the hpsa controllers with an incrementing 0..n value (e.g., that shows up in /proc/interrupts), use the scsi midlayer host_no (e.g. matching /sys/class/scsi_host/hostNN). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 153 ++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 68 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ff7dd9439c4e83..eba0b69ce44f2d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -318,32 +318,36 @@ static int check_for_unit_attention(struct ctlr_info *h, switch (asc) { case STATE_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: a state change " - "detected, command retried\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: a state change detected, command retried\n", + h->devname); break; case LUN_FAILED: dev_warn(&h->pdev->dev, - HPSA "%d: LUN failure detected\n", h->ctlr); + "%s: LUN failure detected\n", h->devname); break; case REPORT_LUNS_CHANGED: dev_warn(&h->pdev->dev, - HPSA "%d: report LUN data changed\n", h->ctlr); + "%s: report LUN data changed\n", h->devname); /* * Note: this REPORT_LUNS_CHANGED condition only occurs on the external * target (array) devices. */ break; case POWER_OR_RESET: - dev_warn(&h->pdev->dev, HPSA "%d: a power on " - "or device reset detected\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: a power on or device reset detected\n", + h->devname); break; case UNIT_ATTENTION_CLEARED: - dev_warn(&h->pdev->dev, HPSA "%d: unit attention " - "cleared by another initiator\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: unit attention cleared by another initiator\n", + h->devname); break; default: - dev_warn(&h->pdev->dev, HPSA "%d: unknown " - "unit attention detected\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: unknown unit attention detected\n", + h->devname); break; } return 1; @@ -5058,22 +5062,15 @@ static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) return tag_type; } -static void hpsa_unregister_scsi(struct ctlr_info *h) -{ - /* we are being forcibly unloaded, and may not refuse. */ - scsi_remove_host(h->scsi_host); - scsi_host_put(h->scsi_host); - h->scsi_host = NULL; -} - -static int hpsa_register_scsi(struct ctlr_info *h) +static int hpsa_scsi_host_alloc(struct ctlr_info *h) { struct Scsi_Host *sh; - int error; sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); - if (sh == NULL) - goto fail; + if (sh == NULL) { + dev_err(&h->pdev->dev, "scsi_host_alloc failed\n"); + return -ENOMEM; + } sh->io_port = 0; sh->n_io_port = 0; @@ -5085,35 +5082,35 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; - h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; if (!shost_use_blk_mq(sh)) { - error = scsi_init_shared_tag_map(sh, sh->can_queue); + int error = scsi_init_shared_tag_map(sh, sh->can_queue); + if (error) { dev_err(&h->pdev->dev, "%s: scs_init_shared_tag_map failed for controller %d\n", __func__, h->ctlr); - goto fail_host_put; + scsi_host_put(sh); + return error; } } - error = scsi_add_host(sh, &h->pdev->dev); - if (error) { - dev_err(&h->pdev->dev, "%s: scsi_add_host failed for controller %d\n", - __func__, h->ctlr); - goto fail_host_put; - } - scsi_scan_host(sh); + h->scsi_host = sh; return 0; +} - fail_host_put: - scsi_host_put(sh); - return error; - fail: - dev_err(&h->pdev->dev, "%s: scsi_host_alloc" - " failed for controller %d\n", __func__, h->ctlr); - return -ENOMEM; +static int hpsa_scsi_add_host(struct ctlr_info *h) +{ + int rv; + + rv = scsi_add_host(h->scsi_host, &h->pdev->dev); + if (rv) { + dev_err(&h->pdev->dev, "scsi_add_host failed\n"); + return rv; + } + scsi_scan_host(h->scsi_host); + return 0; } /* Send a TEST_UNIT_READY command to the specified LUN using the specified @@ -7751,7 +7748,9 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ - hpsa_free_pci_init(h); /* init_one 3 */ + scsi_host_put(h->scsi_host); /* init_one 3 */ + h->scsi_host = NULL; /* init_one 3 */ + hpsa_free_pci_init(h); /* init_one 2_5 */ free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ if (h->resubmit_wq) @@ -8118,10 +8117,15 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_pci_init(h); if (rc) - goto clean2; /* lockup, aer/h */ + goto clean2; /* lu, aer/h */ - sprintf(h->devname, HPSA "%d", number_of_controllers); - h->ctlr = number_of_controllers; + /* relies on h-> settings made by hpsa_pci_init, including + * interrupt_mode h->intr */ + rc = hpsa_scsi_host_alloc(h); + if (rc) + goto clean2_5; /* pci, lu, aer/h */ + + sprintf(h->devname, HPSA "%d", h->scsi_host->host_no); number_of_controllers++; /* configure PCI DMA stuff */ @@ -8134,7 +8138,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean3; /* pci, lockup, aer/h */ + goto clean3; /* shost, pci, lu, aer/h */ } } @@ -8143,13 +8147,13 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) - goto clean3; /* pci, lockup, aer/h */ + goto clean3; /* shost, pci, lu, aer/h */ rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean4; /* irq, pci, lockup, aer/h */ + goto clean4; /* irq, shost, pci, lu, aer/h */ rc = hpsa_alloc_sg_chain_blocks(h); if (rc) - goto clean5; /* cmd, irq, pci, lockup, aer/h */ + goto clean5; /* cmd, irq, shost, pci, lu, aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); init_waitqueue_head(&h->abort_sync_wait_queue); @@ -8158,18 +8162,23 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, h); h->ndevices = 0; h->hba_mode_enabled = 0; - h->scsi_host = NULL; + spin_lock_init(&h->devlock); rc = hpsa_put_ctlr_into_performant_mode(h); if (rc) - goto clean6; /* sg, cmd, irq, pci, lockup, aer/h */ + goto clean6; /* sg, cmd, irq, shost, pci, lu, aer/h */ + + /* hook into SCSI subsystem */ + rc = hpsa_scsi_add_host(h); + if (rc) + goto clean7; /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ /* create the resubmit workqueue */ h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; - goto clean7; /* perf, sg, cmd, irq, pci, lockup, aer/h */ + goto clean8; /* sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ } /* At this point, the controller is ready to take commands. @@ -8194,10 +8203,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* cannot goto clean8 or free_irqs will be called + /* cannot goto clean9 or free_irqs will be called * again. Instead, do its work */ if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* clean8 */ + destroy_workqueue(h->resubmit_wq); /* clean9 */ hpsa_free_performant_mode(h); /* clean7 */ hpsa_free_sg_chain_blocks(h); /* clean6 */ hpsa_free_cmd_pool(h); /* clean5 */ @@ -8209,7 +8218,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean8; + goto clean9; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8245,9 +8254,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ - if (rc) - goto clean8; /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -8259,19 +8265,26 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean8: /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ +clean9: /* wq, sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); -clean7: /* perf, sg, cmd, irq, pci, lockup, aer/h */ +clean8: /* sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ + /* nothing to clean from scsi_add_host... + * scsi_host_put will do so below */ +clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ hpsa_free_performant_mode(h); -clean6: /* sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_sg_chain_blocks(h); -clean5: /* cmd, irq, pci, lockup, aer/h */ +clean6: /* sg, cmd, irq, shost, pci, lu, aer/h */ + hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, shost, pci, lu, aer/h */ hpsa_free_cmd_pool(h); -clean4: /* irq, pci, lockup, aer/h */ +clean4: /* irq, shost, pci, lu, aer/h */ hpsa_free_irqs(h); -clean3: /* pci, lockup, aer/h */ +clean3: /* shost, pci, lu, aer/h */ + scsi_host_put(h->scsi_host); + h->scsi_host = NULL; +clean2_5: /* pci, lu, aer/h */ hpsa_free_pci_init(h); -clean2: /* lockup, aer/h */ +clean2: /* lu, aer/h */ if (h->lockup_detected) { free_percpu(h->lockup_detected); h->lockup_detected = NULL; @@ -8363,19 +8376,23 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ - hpsa_unregister_scsi(h); /* init_one 9 */ - kfree(h->hba_inquiry_data); /* init_one 9 */ - h->hba_inquiry_data = NULL; /* init_one 9 */ + kfree(h->hba_inquiry_data); /* init_one 10 */ + h->hba_inquiry_data = NULL; /* init_one 10 */ if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* init_one 8 */ + destroy_workqueue(h->resubmit_wq); /* init_one 9 */ + scsi_remove_host(h->scsi_host); /* init_one 8 */ + hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ + scsi_host_put(h->scsi_host); /* init_one 3 */ + h->scsi_host = NULL; /* init_one 3 */ + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ - hpsa_free_pci_init(h); /* init_one 3 */ + hpsa_free_pci_init(h); /* init_one 2.5 */ free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ From 476c773bb4148ea54da6dd455b5141c03efb464a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:01 -0500 Subject: [PATCH 190/889] hpsa: propagate the error code in hpsa_kdump_soft_reset If hpsa_wait_for_board_state fails, hpsa_kdump_soft_reset should propagate its return value (e.g., -ENODEV) rather than just returning -1. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index eba0b69ce44f2d..b8e4058b34318c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7709,19 +7709,22 @@ static int hpsa_request_irqs(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { + int rc; hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { + rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY); + if (rc) { dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); - return -1; + return rc; } dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) { + rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); + if (rc) { dev_warn(&h->pdev->dev, "Board failed to become ready " "after soft reset.\n"); - return -1; + return rc; } return 0; From 0d2627bbc1c85edd582e9cc28be32c8bc1312bc2 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:01 -0500 Subject: [PATCH 191/889] hpsa: adjust RAID-1, RAID-1ADM, and RAID-6 names HP now uses RAID-6 rather than RAID-ADG (Advanced Data Guarding) as the marketing name for our implementation of RAID-6. The driver considers RAID-1 and RAID-1+0 to be the same level, and considers RAID-1ADM and RAID-1+0ADM to be the same level. Parenthesis can be used to reflect the optional +0 portion of both those RAID levels. Rename: RAID-ADG to RAID-6 RAID-1(1+0) to RAID-1(+0) RAID-1(ADM) to RAID-1(+0)ADM Also, add another const after the pointer type as suggested by checkpatch.pl so the array is: static const char * const raid_label[] Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b8e4058b34318c..99860c156c0e06 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -738,8 +738,8 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) return (scsi3addr[3] & 0xC0) == 0x40; } -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "1(ADM)", "UNKNOWN" +static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", + "1(+0)ADM", "UNKNOWN" }; #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 From 34abeef9a7e5eaa14b6972c9a0ee4864518c764d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:02 -0500 Subject: [PATCH 192/889] hpsa: remove queue depth from add/remove prints The queue depth is not finalized when device add/update prints are done, so is inaccurate. It is correct in device removal prints, when it doesn't matter any more. Since the final queue depth is available in /sys/block/sdNN/device/queue_depth just drop printing them. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 99860c156c0e06..6b53ac82ad2898 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1273,7 +1273,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), @@ -1283,8 +1283,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[device->raid_level], device->offload_config ? '+' : '-', device->offload_enabled ? '+' : '-', - device->expose_state, - device->queue_depth); + device->expose_state); return 0; } @@ -1328,7 +1327,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->queue_depth = new_entry->queue_depth; dev_info(&h->pdev->dev, - "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, h->dev[entry]->bus, h->dev[entry]->target, h->dev[entry]->lun, scsi_device_type(h->dev[entry]->devtype), @@ -1338,8 +1337,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[h->dev[entry]->raid_level], h->dev[entry]->offload_config ? '+' : '-', h->dev[entry]->offload_enabled ? '+' : '-', - h->dev[entry]->expose_state, - h->dev[entry]->queue_depth); + h->dev[entry]->expose_state); } /* Replace an entry from h->dev[] array. */ @@ -1368,7 +1366,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, added[*nadded] = new_entry; (*nadded)++; dev_info(&h->pdev->dev, - "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1377,8 +1375,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state, - new_entry->queue_depth); + new_entry->expose_state); } /* Remove an entry from h->dev[] array. */ @@ -1399,7 +1396,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, h->dev[i] = h->dev[i+1]; h->ndevices--; dev_info(&h->pdev->dev, - "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, sd->bus, sd->target, sd->lun, scsi_device_type(sd->devtype), sd->vendor, @@ -1408,8 +1405,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, "RAID-?" : raid_label[sd->raid_level], sd->offload_config ? '+' : '-', sd->offload_enabled ? '+' : '-', - sd->expose_state, - sd->queue_depth); + sd->expose_state); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1786,7 +1782,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); dev_info(&h->pdev->dev, - "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, scsi_device_type(sd[i]->devtype), sd[i]->vendor, @@ -1796,8 +1792,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, raid_label[sd[i]->raid_level], sd[i]->offload_config ? '+' : '-', sd[i]->offload_enabled ? '+' : '-', - sd[i]->expose_state, - sd[i]->queue_depth); + sd[i]->expose_state); continue; } From e7211f6534d08b0aea4d1b9adeef98c1bd029738 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Mon, 20 Oct 2014 17:02:02 -0500 Subject: [PATCH 193/889] hpsa: print accurate SSD Smart Path Enabled status offload_enabled changes are deferred until after the added/updated prints occur, so the values are incorrect. Print the offload_to_be_enabled values when those are correct. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6b53ac82ad2898..e5718df439b114 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1282,7 +1282,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, device->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[device->raid_level], device->offload_config ? '+' : '-', - device->offload_enabled ? '+' : '-', + device->offload_to_be_enabled ? '+' : '-', device->expose_state); return 0; } @@ -1336,7 +1336,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[h->dev[entry]->raid_level], h->dev[entry]->offload_config ? '+' : '-', - h->dev[entry]->offload_enabled ? '+' : '-', + h->dev[entry]->offload_to_be_enabled ? '+' : '-', h->dev[entry]->expose_state); } @@ -1374,7 +1374,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, new_entry->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', - new_entry->offload_enabled ? '+' : '-', + new_entry->offload_to_be_enabled ? '+' : '-', new_entry->expose_state); } From 6265c19421c81670649b35ba6cd26667e68a2578 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:02:03 -0500 Subject: [PATCH 194/889] debug tag collisions --- drivers/scsi/hpsa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e5718df439b114..cc5fc8d24594fa 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5703,6 +5703,14 @@ static int hpsa_get_cmd_index(struct scsi_cmnd *scmd) return idx; } +static void print_scsi_cmd(struct ctlr_info *h, struct scsi_cmnd *scmd, int idx) +{ + char format[50]; + + sprintf(format, "Tag %d: CDB: %dph\n", idx, scmd->cmd_len); + dev_warn(&h->pdev->dev, format, scmd->cmnd); +} + /* * For operations with an associated SCSI command, a command block is allocated * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the @@ -5737,6 +5745,7 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, dev_warn(&h->pdev->dev, "tag collision (tag=%d) in cmd_tagged_alloc().\n", idx); + print_scsi_cmd(h, scmd, idx); } hpsa_cmd_partial_init(h, idx, c); From 8493a68f7a2cc308d2db2a3a37547625a4347b27 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 20 Oct 2014 17:02:04 -0500 Subject: [PATCH 195/889] debug aborts --- drivers/scsi/hpsa.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cc5fc8d24594fa..84a18eedf3d9e2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5564,6 +5564,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) u32 tagupper, taglower; int refcount, reply_queue; + /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); if (WARN(h == NULL, @@ -5571,8 +5572,10 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) sc)) return FAILED; + dev_warn(&h->pdev->dev, "abort 0\n"); /* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, "abort 0.1\n"); dev_warn(&h->pdev->dev, "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, @@ -5583,10 +5586,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* FIXME eh_timeout_handler would be even better. * for testing, abort is just being used for timeouts, * so is equivalent */ + dev_warn(&h->pdev->dev, "abort 0.2\n"); detect_controller_lockup(h); + dev_warn(&h->pdev->dev, "abort 0.3\n"); /* check again in case one just occurred */ if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, "abort 0.4\n"); dev_warn(&h->pdev->dev, "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, @@ -5595,11 +5601,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) } } + dev_warn(&h->pdev->dev, "abort 1\n"); /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) return FAILED; + dev_warn(&h->pdev->dev, "abort 2\n"); memset(msg, 0, sizeof(msg)); ml += sprintf(msg+ml, "scsi %d:%d:%d:%llu scmd %p ABORT ", h->scsi_host->host_no, sc->device->channel, @@ -5613,18 +5621,21 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } + dev_warn(&h->pdev->dev, "abort 3\n"); /* Get SCSI command to be aborted */ abort = (struct CommandList *) sc->host_scribble; if (abort == NULL) { /* This can happen if the command already completed. */ return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 4\n"); refcount = atomic_inc_return(&abort->refcount); if (refcount == 1) { /* Command is done already. */ cmd_free(h, abort); return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 5\n"); /* Don't bother trying the abort if we know it won't work. */ if (abort->cmd_type != CMD_IOACCEL2 && abort->cmd_type != CMD_IOACCEL1 && !dev->supports_aborts) { @@ -5632,6 +5643,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } + dev_warn(&h->pdev->dev, "abort 6\n"); /* Check that we're aborting the right command. * It's possible the CommandList already completed and got re-used. */ @@ -5639,6 +5651,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 7\n"); abort->abort_pending = true; hpsa_get_tag(h, abort, &taglower, &tagupper); @@ -5651,6 +5664,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) as->cmd_len, as->cmnd[0], as->cmnd[1], as->serial_number); dev_warn(&h->pdev->dev, "%s BEING SENT\n", msg); + dev_warn(&h->pdev->dev, "abort 8 (waiting for abort command to be free)\n"); /* * Command is in flight, or possibly already completed @@ -5664,6 +5678,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return FAILED; } + dev_warn(&h->pdev->dev, "abort 9 (got abort command)\n"); rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); atomic_inc(&h->abort_cmds_available); wake_up_all(&h->abort_cmd_wait_queue); @@ -5672,9 +5687,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return FAILED; } + dev_warn(&h->pdev->dev, "abort 10\n"); dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); wait_event(h->abort_sync_wait_queue, atomic_read(&abort->refcount) == 1); cmd_free(h, abort); + dev_warn(&h->pdev->dev, "abort 11\n"); return SUCCESS; } From f98f6a03a0dfe8791537f682d914b21961729ce6 Mon Sep 17 00:00:00 2001 From: Christopher Voltz Date: Tue, 28 Oct 2014 10:46:06 -0500 Subject: [PATCH 196/889] Test --- drivers/scsi/hpsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 84a18eedf3d9e2..6ded7d4746980d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -19,6 +19,8 @@ * */ +/* test */ + #include #include #include From 7a6a36c5014717fa959627d01d2880582abb11a2 Mon Sep 17 00:00:00 2001 From: Christopher Voltz Date: Tue, 28 Oct 2014 10:48:10 -0500 Subject: [PATCH 197/889] Revert "Test" This reverts commit f98f6a03a0dfe8791537f682d914b21961729ce6. --- drivers/scsi/hpsa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6ded7d4746980d..84a18eedf3d9e2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -19,8 +19,6 @@ * */ -/* test */ - #include #include #include From 4f31deca4cff522781f0647f8564d8977bc09f2a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:40 -0500 Subject: [PATCH 198/889] Change scsi.c scsi_log_completion() to print strings for QUEUED, SOFT_ERROR, SCSI_RETURN_NOT_HANDLED, and FAST_IO_FAIL rather than "UNKNOWN". Signed-off-by: Robert Elliott --- drivers/scsi/scsi.c | 59 ++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 79c77b485a6729..a6ae88b5e32223 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -553,6 +553,23 @@ void scsi_log_send(struct scsi_cmnd *cmd) } } +/* Strings for internal return values in scsi.h */ +/* NEEDS_RETRY must be the lowest numbered value */ +static const char * const disposition_label[] = { + "NEEDS_RETRY", + "SUCCESS", + "FAILED", + "QUEUED", + "SOFT_ERROR", + "ADD_TO_MLQUEUE", + "TIMEOUT_ERROR", + "SCSI_RETURN_NOT_HANDLED", + "FAST_IO_FAIL", + "UNKNOWN", +}; +#define DISPOSITION_BASE NEEDS_RETRY +#define DISPOSITION_UNKNOWN (ARRAY_SIZE(disposition_label) - 1) + void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) { unsigned int level; @@ -574,35 +591,21 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - scmd_printk(KERN_INFO, cmd, "Done: "); + int dindex; + + if (disposition >= DISPOSITION_BASE && + disposition <= DISPOSITION_BASE + + DISPOSITION_UNKNOWN) + dindex = disposition - DISPOSITION_BASE; + else + dindex = DISPOSITION_UNKNOWN; if (level > 2) - printk("0x%p ", cmd); - /* - * Dump truncated values, so we usually fit within - * 80 chars. - */ - switch (disposition) { - case SUCCESS: - printk("SUCCESS\n"); - break; - case NEEDS_RETRY: - printk("RETRY\n"); - break; - case ADD_TO_MLQUEUE: - printk("MLQUEUE\n"); - break; - case FAILED: - printk("FAILED\n"); - break; - case TIMEOUT_ERROR: - /* - * If called via scsi_times_out. - */ - printk("TIMEOUT\n"); - break; - default: - printk("UNKNOWN\n"); - } + scmd_printk(KERN_INFO, cmd, "Done: 0x%p %s\n", + cmd, + disposition_label[dindex]); + else + scmd_printk(KERN_INFO, cmd, "Done: %s\n", + disposition_label[dindex]); scsi_print_result(cmd); scsi_print_command(cmd); if (status_byte(cmd->result) & CHECK_CONDITION) From 5c817d3a12599eaef2352d18dd06bf518fc82f8f Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:40 -0500 Subject: [PATCH 199/889] Set scsi_logging_level to be more verbose to get better messages while booting --- drivers/scsi/scsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a6ae88b5e32223..362e443e7d5eb1 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -80,7 +80,10 @@ * Note - the initial logging level can be set here to log events at boot time. * After the system is up, you may enable logging via the /proc interface. */ -unsigned int scsi_logging_level; +unsigned int scsi_logging_level = + (0x5 & ((1 << SCSI_LOG_ERROR_BITS) - 1)) << SCSI_LOG_ERROR_SHIFT | + (0x1 & ((1 << SCSI_LOG_MLCOMPLETE_BITS) - 1)) << SCSI_LOG_MLCOMPLETE_SHIFT; + #if defined(CONFIG_SCSI_LOGGING) EXPORT_SYMBOL(scsi_logging_level); #endif From d9ce393cf44ccf710d64046a5edf7e1b39fb02ea Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:41 -0500 Subject: [PATCH 200/889] hpsa: remove dev_warn prints from RAID-1ADM RAID-1ADM is unusable with dev_warn called on every command. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cef5d49b59cd24..2a213fa968f21a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3809,11 +3809,6 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, offload_to_mirror = (offload_to_mirror >= map->layout_map_count - 1) ? 0 : offload_to_mirror + 1; - /* FIXME: remove after debug/dev */ - BUG_ON(offload_to_mirror >= map->layout_map_count); - dev_warn(&h->pdev->dev, - "DEBUG: Using physical disk map index %d from mirror group %d\n", - map_index, offload_to_mirror); dev->offload_to_mirror = offload_to_mirror; /* Avoid direct use of dev->offload_to_mirror within this * function since multiple threads might simultaneously From 275a1552378441b07af7e0cbc4116ffdd8802f63 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:41 -0500 Subject: [PATCH 201/889] hpsa: fix a couple pci id table mistakes Subdevice ID 0x3323 was missing from product[] table (another name for HP Smart Storage 1210m) Bogus 0x1925 subdevice id removed from hpsa_pci_device_id[] (no such thing.) Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2a213fa968f21a..34f941dc5e8584 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -103,7 +103,6 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1925}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1929}, @@ -149,6 +148,7 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324A103C, "Smart Array P712m", &SA5_access}, {0x324B103C, "Smart Array P711m", &SA5_access}, + {0x3233103C, "HP StorageWorks 1210m", &SA5_access}, /* alias of 333f */ {0x3350103C, "Smart Array P222", &SA5_access}, {0x3351103C, "Smart Array P420", &SA5_access}, {0x3352103C, "Smart Array P421", &SA5_access}, From 439ae4c4252833ef7600f4f51ad6cbfd53aa706f Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:42 -0500 Subject: [PATCH 202/889] hpsa: fix a string constant broken into two lines Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 34f941dc5e8584..87c8c49cd62cfb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7073,8 +7073,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irq(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { - dev_warn(&h->pdev->dev, "Failed to request_irq after " - "soft reset.\n"); + dev_warn(&h->pdev->dev, + "Failed to request_irq after soft reset.\n"); goto clean4; } From d28c329dbae2149603cc673e8e710a9363bbc809 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:50:43 -0500 Subject: [PATCH 203/889] hpsa: correct off-by-one sizing of chained SG block Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 87c8c49cd62cfb..bd04092909936c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6318,11 +6318,11 @@ static void hpsa_find_board_params(struct ctlr_info *h) h->max_cmd_sg_entries = 31; if (h->maxsgentries > 512) { h->max_cmd_sg_entries = 32; - h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; + h->chainsize = h->maxsgentries - h->max_cmd_sg_entries; h->maxsgentries--; /* save one for chain pointer */ } else { - h->maxsgentries = 31; /* default to traditional values */ h->chainsize = 0; + h->maxsgentries = 31; /* default to traditional values */ } /* Find out what task management functions are supported and cache */ From 40c683e69b2b51e811669ce1cbe531a5840a8603 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:43 -0500 Subject: [PATCH 204/889] hpsa: remove 'action required' phrasing In the case of LUN data changing, the driver will auto rescan and so it's not even true that "action" is "required". Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik --- drivers/scsi/hpsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bd04092909936c..e519f070fd10ec 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -274,12 +274,12 @@ static int check_for_unit_attention(struct ctlr_info *h, "detected, command retried\n", h->ctlr); break; case LUN_FAILED: - dev_warn(&h->pdev->dev, HPSA "%d: LUN failure " - "detected, action required\n", h->ctlr); + dev_warn(&h->pdev->dev, + HPSA "%d: LUN failure detected\n", h->ctlr); break; case REPORT_LUNS_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: report LUN data " - "changed, action required\n", h->ctlr); + dev_warn(&h->pdev->dev, + HPSA "%d: report LUN data changed\n", h->ctlr); /* * Note: this REPORT_LUNS_CHANGED condition only occurs on the external * target (array) devices. From 0a00316abe1d7954f9d58fa371fa938f1bcfa7e0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:44 -0500 Subject: [PATCH 205/889] hpsa: fix allocation sizes for CISS_REPORT_LUNs commands We were allocating roughly double the amount of memory we should be due to ReportLUNdata and ExtendedReportLUNdata containing a non-zero sized array but adding extra memory to allocate as if the array were zero sized. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++------- drivers/scsi/hpsa_cmd.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e519f070fd10ec..d2386d4e24e225 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2891,7 +2891,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, * Returns 0 on success, -1 otherwise. */ static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportlunsize, + int reportphyslunsize, int reportloglunsize, struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode, struct ReportLUNdata *logdev, u32 *nlogicals) { @@ -2905,7 +2905,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, *physical_mode = HPSA_REPORT_PHYS_EXTENDED; physical_entry_size = 24; } - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, + if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize, *physical_mode)) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; @@ -2918,7 +2918,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, *nphysicals - HPSA_MAX_PHYS_LUN); *nphysicals = HPSA_MAX_PHYS_LUN; } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportlunsize)) { + if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) { dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } @@ -3011,15 +3011,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; - int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; int rescan_hba_mode; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); - physdev_list = kzalloc(reportlunsize, GFP_KERNEL); - logdev_list = kzalloc(reportlunsize, GFP_KERNEL); + physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); + logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { @@ -3039,7 +3038,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, reportlunsize, + if (hpsa_gather_lun_info(h, + sizeof(*physdev_list), sizeof(*logdev_list), (struct ReportLUNdata *) physdev_list, &nphysicals, &physical_mode, logdev_list, &nlogicals)) goto out; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index b5125dc3143912..9b19042ff3304a 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -252,7 +252,7 @@ struct ReportExtendedLUNdata { u8 LUNListLength[4]; u8 extended_response_flag; u8 reserved[3]; - struct ext_report_lun_entry LUN[HPSA_MAX_LUN]; + struct ext_report_lun_entry LUN[HPSA_MAX_PHYS_LUN]; }; struct SenseSubsystem_info { From 21216441ae50d0e4b8c96e0de72b3d329dd39d78 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:44 -0500 Subject: [PATCH 206/889] hpsa: fix endianness issue with scatter gather elements The hardware needs little endian scatter gather addresses and lengths but we were not bothering to convert from cpu byte order as we should have been. On Intel, this is all just a bunch of no-ops macros, but it makes the code endian-clean(er). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 213 ++++++++++++++++++---------------------- drivers/scsi/hpsa_cmd.h | 14 +-- 2 files changed, 103 insertions(+), 124 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d2386d4e24e225..85dcc911dcc679 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1500,22 +1500,22 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h, { struct SGDescriptor *chain_sg, *chain_block; u64 temp64; + u32 chain_len; chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; chain_block = h->cmd_sg_list[c->cmdindex]; - chain_sg->Ext = HPSA_SG_CHAIN; - chain_sg->Len = sizeof(*chain_sg) * + chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN); + chain_len = sizeof(*chain_sg) * (c->Header.SGTotal - h->max_cmd_sg_entries); - temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len, + chain_sg->Len = cpu_to_le32(chain_len); + temp64 = pci_map_single(h->pdev, chain_block, chain_len, PCI_DMA_TODEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { /* prevent subsequent unmapping */ - chain_sg->Addr.lower = 0; - chain_sg->Addr.upper = 0; + chain_sg->Addr = 0; return -1; } - chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL); - chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL); + chain_sg->Addr = cpu_to_le64(temp64); return 0; } @@ -1523,15 +1523,13 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, struct CommandList *c) { struct SGDescriptor *chain_sg; - union u64bit temp64; - if (c->Header.SGTotal <= h->max_cmd_sg_entries) + if (le16_to_cpu(c->Header.SGTotal) <= h->max_cmd_sg_entries) return; chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; - temp64.val32.lower = chain_sg->Addr.lower; - temp64.val32.upper = chain_sg->Addr.upper; - pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); + pci_unmap_single(h->pdev, le64_to_cpu(chain_sg->Addr), + le32_to_cpu(chain_sg->Len), PCI_DMA_TODEVICE); } @@ -1732,8 +1730,7 @@ static void complete_scsi_command(struct CommandList *cp) struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; - cp->Header.Tag.lower = c->Tag.lower; - cp->Header.Tag.upper = c->Tag.upper; + cp->Header.tag = c->tag; memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8); memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen); @@ -1934,14 +1931,11 @@ static void hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c, int sg_used, int data_direction) { int i; - union u64bit addr64; - for (i = 0; i < sg_used; i++) { - addr64.val32.lower = c->SG[i].Addr.lower; - addr64.val32.upper = c->SG[i].Addr.upper; - pci_unmap_single(pdev, (dma_addr_t) addr64.val, c->SG[i].Len, - data_direction); - } + for (i = 0; i < sg_used; i++) + pci_unmap_single(pdev, (dma_addr_t) le64_to_cpu(c->SG[i].Addr), + le32_to_cpu(c->SG[i].Len), + data_direction); } static int hpsa_map_one(struct pci_dev *pdev, @@ -1954,7 +1948,7 @@ static int hpsa_map_one(struct pci_dev *pdev, if (buflen == 0 || data_direction == PCI_DMA_NONE) { cp->Header.SGList = 0; - cp->Header.SGTotal = 0; + cp->Header.SGTotal = cpu_to_le16(0); return 0; } @@ -1962,17 +1956,14 @@ static int hpsa_map_one(struct pci_dev *pdev, if (dma_mapping_error(&pdev->dev, addr64)) { /* Prevent subsequent unmap of something never mapped */ cp->Header.SGList = 0; - cp->Header.SGTotal = 0; + cp->Header.SGTotal = cpu_to_le16(0); return -1; } - cp->SG[0].Addr.lower = - (u32) (addr64 & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Addr.upper = - (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Len = buflen; - cp->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining */ + cp->SG[0].Addr = cpu_to_le64(addr64); + cp->SG[0].Len = cpu_to_le32(buflen); + cp->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* we are not chaining */ cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */ + cp->Header.SGTotal = (u16) cpu_to_le16(1); /* total sgs in cmd list */ return 0; } @@ -3186,7 +3177,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, unsigned int len; struct scatterlist *sg; u64 addr64; - int use_sg, i, sg_index, chained; + int use_sg, i, sg_index, chained, last_sg; struct SGDescriptor *curr_sg; BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); @@ -3201,6 +3192,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = cp->SG; chained = 0; sg_index = 0; + last_sg = scsi_sg_count(cmd) - 1; scsi_for_each_sg(cmd, sg, use_sg, i) { if (i == h->max_cmd_sg_entries - 1 && use_sg > h->max_cmd_sg_entries) { @@ -3210,10 +3202,9 @@ static int hpsa_scatter_gather(struct ctlr_info *h, } addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); - curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); - curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); - curr_sg->Len = len; - curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST; + curr_sg->Addr = cpu_to_le64(addr64); + curr_sg->Len = cpu_to_le32(len); + curr_sg->Ext = cpu_to_le32((i == last_sg) * HPSA_SG_LAST); curr_sg++; } @@ -3295,7 +3286,7 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, unsigned int total_len = 0; struct scatterlist *sg; u64 addr64; - int use_sg, i; + int use_sg, i, last_sg; struct SGDescriptor *curr_sg; u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE; @@ -3320,20 +3311,16 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, return use_sg; if (use_sg) { + last_sg = scsi_sg_count(cmd) - 1; curr_sg = cp->SG; scsi_for_each_sg(cmd, sg, use_sg, i) { addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); total_len += len; - curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); - curr_sg->Addr.upper = - (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); - curr_sg->Len = len; - - if (i == (scsi_sg_count(cmd) - 1)) - curr_sg->Ext = HPSA_SG_LAST; - else - curr_sg->Ext = 0; /* we are not chaining */ + curr_sg->Addr = cpu_to_le64(addr64); + curr_sg->Len = cpu_to_le32(len); + curr_sg->Ext = + cpu_to_le32((i == last_sg) * HPSA_SG_LAST); curr_sg++; } @@ -4021,8 +4008,9 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT); - c->Header.Tag.lower |= DIRECT_LOOKUP_BIT; + c->Header.tag = cpu_to_le64( + (u64) ((c->cmdindex << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT)); /* Fill in the request block... */ @@ -4324,8 +4312,8 @@ static void hpsa_get_tag(struct ctlr_info *h, if (c->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *) &h->ioaccel_cmd_pool[c->cmdindex]; - *tagupper = cm1->Tag.upper; - *taglower = cm1->Tag.lower; + *tagupper = (u32) (cm1->tag >> 32); + *taglower = (u32) (cm1->tag & 0x0ffffffffULL); return; } if (c->cmd_type == CMD_IOACCEL2) { @@ -4336,11 +4324,10 @@ static void hpsa_get_tag(struct ctlr_info *h, *taglower = cm2->Tag; return; } - *tagupper = c->Header.Tag.upper; - *taglower = c->Header.Tag.lower; + *tagupper = (u32) (c->Header.tag >> 32); + *taglower = (u32) (c->Header.tag & 0x0ffffffffULL); } - static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int swizzle) { @@ -4427,7 +4414,7 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, spin_lock_irqsave(&h->lock, flags); list_for_each_entry(c, queue_head, list) { - if (memcmp(&c->Header.Tag, tag, 8) != 0) + if (memcmp(&c->Header.tag, tag, 8) != 0) continue; spin_unlock_irqrestore(&h->lock, flags); return c; @@ -4709,9 +4696,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; - c->ErrDesc.Len = sizeof(*c->err_info); + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); + c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); c->h = h; return c; @@ -4724,7 +4710,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) static struct CommandList *cmd_special_alloc(struct ctlr_info *h) { struct CommandList *c; - union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); @@ -4745,9 +4730,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); c->ErrDesc.Len = sizeof(*c->err_info); c->h = h; @@ -4768,12 +4751,9 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c) static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) { - union u64bit temp64; - - temp64.val32.lower = c->ErrDesc.Addr.lower; - temp64.val32.upper = c->ErrDesc.Addr.upper; pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, (dma_addr_t) temp64.val); + c->err_info, + (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr)); pci_free_consistent(h->pdev, sizeof(*c), c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); } @@ -4927,7 +4907,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) IOCTL_Command_struct iocommand; struct CommandList *c; char *buff = NULL; - union u64bit temp64; + u64 temp64; int rc = 0; if (!argp) @@ -4965,15 +4945,15 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) /* Fill in Command Header */ c->Header.ReplyQueue = 0; /* unused in simple mode */ if (iocommand.buf_size > 0) { /* buffer to fill */ - c->Header.SGList = 1; - c->Header.SGTotal = 1; + c->Header.SGList = (u8) 1; + c->Header.SGTotal = cpu_to_le16(1); } else { /* no buffers to fill */ c->Header.SGList = 0; - c->Header.SGTotal = 0; + c->Header.SGTotal = cpu_to_le16(0); } memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); /* use the kernel address the cmd block for tag */ - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; /* Fill in Request block */ memcpy(&c->Request, &iocommand.Request, @@ -4981,19 +4961,17 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) /* Fill in the scatter gather information */ if (iocommand.buf_size > 0) { - temp64.val = pci_map_single(h->pdev, buff, + temp64 = (u64) pci_map_single(h->pdev, buff, iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(&h->pdev->dev, temp64.val)) { - c->SG[0].Addr.lower = 0; - c->SG[0].Addr.upper = 0; - c->SG[0].Len = 0; + if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) { + c->SG[0].Addr = cpu_to_le64(0); + c->SG[0].Len = cpu_to_le32(0); rc = -ENOMEM; goto out; } - c->SG[0].Addr.lower = temp64.val32.lower; - c->SG[0].Addr.upper = temp64.val32.upper; - c->SG[0].Len = iocommand.buf_size; - c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/ + c->SG[0].Addr = cpu_to_le64(temp64); + c->SG[0].Len = cpu_to_le32(iocommand.buf_size); + c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); if (iocommand.buf_size > 0) @@ -5028,7 +5006,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) struct CommandList *c; unsigned char **buff = NULL; int *buff_size = NULL; - union u64bit temp64; + u64 temp64; BYTE sg_used = 0; int status = 0; int i; @@ -5102,28 +5080,29 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; - c->Header.SGList = c->Header.SGTotal = sg_used; + c->Header.SGList = (u8) sg_used; + c->Header.SGTotal = cpu_to_le16(sg_used); memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; for (i = 0; i < sg_used; i++) { - temp64.val = pci_map_single(h->pdev, buff[i], + temp64 = (u64) pci_map_single(h->pdev, buff[i], buff_size[i], PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(&h->pdev->dev, temp64.val)) { - c->SG[i].Addr.lower = 0; - c->SG[i].Addr.upper = 0; + if (dma_mapping_error(&h->pdev->dev, + (dma_addr_t) temp64)) { + c->SG[i].Addr = 0; c->SG[i].Len = 0; hpsa_pci_unmap(h->pdev, c, i, PCI_DMA_BIDIRECTIONAL); status = -ENOMEM; goto cleanup0; } - c->SG[i].Addr.lower = temp64.val32.lower; - c->SG[i].Addr.upper = temp64.val32.upper; - c->SG[i].Len = buff_size[i]; - c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST; + c->SG[i].Addr = cpu_to_le64(temp64); + c->SG[i].Len = cpu_to_le32(buff_size[i]); + c->SG[i].Ext = + cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); @@ -5263,17 +5242,18 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, { int pci_dir = XFER_NONE; struct CommandList *a; /* for commands to be aborted */ + u32 tupper, tlower; c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; if (buff != NULL && size > 0) { - c->Header.SGList = 1; - c->Header.SGTotal = 1; + c->Header.SGList = (u8) 1; + c->Header.SGTotal = cpu_to_le32(1); } else { c->Header.SGList = 0; c->Header.SGTotal = 0; } - c->Header.Tag.lower = c->busaddr; + c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); c->Request.Type.Type = cmd_type; @@ -5371,9 +5351,10 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case HPSA_ABORT_MSG: a = buff; /* point to command to be aborted */ - dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n", - a->Header.Tag.upper, a->Header.Tag.lower, - c->Header.Tag.upper, c->Header.Tag.lower); + dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx", + a->Header.tag, c->Header.tag); + tlower = (u32) (a->Header.tag >> 32); + tupper = (u32) (a->Header.tag & 0x0ffffffffULL); c->Request.CDBLen = 16; c->Request.Type.Type = TYPE_MSG; c->Request.Type.Attribute = ATTR_SIMPLE; @@ -5384,14 +5365,14 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[2] = 0x00; /* reserved */ c->Request.CDB[3] = 0x00; /* reserved */ /* Tag to abort goes in CDB[4]-CDB[11] */ - c->Request.CDB[4] = a->Header.Tag.lower & 0xFF; - c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF; - c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF; - c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF; - c->Request.CDB[8] = a->Header.Tag.upper & 0xFF; - c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF; - c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF; - c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF; + c->Request.CDB[4] = tlower & 0xFF; + c->Request.CDB[5] = (tlower >> 8) & 0xFF; + c->Request.CDB[6] = (tlower >> 16) & 0xFF; + c->Request.CDB[7] = (tlower >> 24) & 0xFF; + c->Request.CDB[8] = tupper & 0xFF; + c->Request.CDB[9] = (tupper >> 8) & 0xFF; + c->Request.CDB[10] = (tupper >> 16) & 0xFF; + c->Request.CDB[11] = (tupper >> 24) & 0xFF; c->Request.CDB[12] = 0x00; /* reserved */ c->Request.CDB[13] = 0x00; /* reserved */ c->Request.CDB[14] = 0x00; /* reserved */ @@ -5761,8 +5742,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, cmd->CommandHeader.ReplyQueue = 0; cmd->CommandHeader.SGList = 0; cmd->CommandHeader.SGTotal = 0; - cmd->CommandHeader.Tag.lower = paddr32; - cmd->CommandHeader.Tag.upper = 0; + cmd->CommandHeader.tag = (u64) paddr32; memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); cmd->Request.CDBLen = 16; @@ -5773,9 +5753,9 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, cmd->Request.CDB[0] = opcode; cmd->Request.CDB[1] = type; memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */ - cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(*cmd); - cmd->ErrorDescriptor.Addr.upper = 0; - cmd->ErrorDescriptor.Len = sizeof(struct ErrorInfo); + cmd->ErrorDescriptor.Addr = + cpu_to_le64((u64) (paddr32 + sizeof(*cmd))); + cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo)); writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET); @@ -7426,13 +7406,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT; cp->timeout_sec = 0; cp->ReplyQueue = 0; - cp->Tag.lower = (i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT; - cp->Tag.upper = 0; - cp->host_addr.lower = - (u32) (h->ioaccel_cmd_pool_dhandle + - (i * sizeof(struct io_accel1_cmd))); - cp->host_addr.upper = 0; + cp->tag = + cpu_to_le64((u64) ((i << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT)); + cp->host_addr = + cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + + (i * sizeof(struct io_accel1_cmd)))); } } else if (trans_support & CFGTBL_Trans_io_accel2) { u64 cfg_offset, cfg_base_addr_index; @@ -7706,7 +7685,7 @@ static void __attribute__((unused)) verify_offsets(void) VERIFY_OFFSET(timeout_sec, 0x62); VERIFY_OFFSET(ReplyQueue, 0x64); VERIFY_OFFSET(reserved9, 0x65); - VERIFY_OFFSET(Tag, 0x68); + VERIFY_OFFSET(tag, 0x68); VERIFY_OFFSET(host_addr, 0x70); VERIFY_OFFSET(CISS_LUN, 0x78); VERIFY_OFFSET(SG, 0x78 + 8); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 9b19042ff3304a..575eda8a8c5e51 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -314,7 +314,7 @@ struct CommandListHeader { u8 ReplyQueue; u8 SGList; u16 SGTotal; - struct vals32 Tag; + u64 tag; union LUNAddr LUN; }; @@ -330,12 +330,12 @@ struct RequestBlock { }; struct ErrDescriptor { - struct vals32 Addr; + u64 Addr; u32 Len; }; struct SGDescriptor { - struct vals32 Addr; + u64 Addr; u32 Len; u32 Ext; }; @@ -434,8 +434,8 @@ struct io_accel1_cmd { u16 timeout_sec; /* 0x62 - 0x63 */ u8 ReplyQueue; /* 0x64 */ u8 reserved9[3]; /* 0x65 - 0x67 */ - struct vals32 Tag; /* 0x68 - 0x6F */ - struct vals32 host_addr; /* 0x70 - 0x77 */ + u64 tag; /* 0x68 - 0x6F */ + u64 host_addr; /* 0x70 - 0x77 */ u8 CISS_LUN[8]; /* 0x78 - 0x7F */ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES]; } __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT); @@ -555,8 +555,8 @@ struct hpsa_tmf_struct { u8 reserved1; /* byte 3 Reserved */ u32 it_nexus; /* SCSI I-T Nexus */ u8 lun_id[8]; /* LUN ID for TMF request */ - struct vals32 Tag; /* cciss tag associated w/ request */ - struct vals32 abort_tag;/* cciss tag of SCSI cmd or task to abort */ + u64 tag; /* cciss tag associated w/ request */ + u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */ u64 error_ptr; /* Error Pointer */ u32 error_len; /* Error Length */ }; From d82a4cef4220ae99ca021d123ed04ea98f1b448c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:45 -0500 Subject: [PATCH 207/889] hpsa: get rid of type/attribute/direction bit field where possible Using bit fields for hardware command fields isn't portable and relies on assumptions about how the compiler lays out the bits. We can fix this in the driver's internal command structure, but the ioctl interface we can't change because it is part of the userland ABI. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 ++++++++++++++++++++--------------------- drivers/scsi/hpsa_cmd.h | 18 +++++++++---- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 85dcc911dcc679..679668b4f019b7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4019,17 +4019,18 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB)); c->Request.CDBLen = cmd->cmd_len; memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); - c->Request.Type.Type = TYPE_CMD; - c->Request.Type.Attribute = ATTR_SIMPLE; switch (cmd->sc_data_direction) { case DMA_TO_DEVICE: - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_WRITE); break; case DMA_FROM_DEVICE: - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_READ); break; case DMA_NONE: - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_NONE); break; case DMA_BIDIRECTIONAL: /* This can happen if a buggy application does a scsi passthru @@ -4037,7 +4038,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, * ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() ) */ - c->Request.Type.Direction = XFER_RSVD; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_RSVD); /* This is technically wrong, and hpsa controllers should * reject it with CMD_INVALID, which is the most correct * response, but non-fibre backends appear to let it @@ -5256,7 +5258,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); - c->Request.Type.Type = cmd_type; if (cmd_type == TYPE_CMD) { switch (cmd) { case HPSA_INQUIRY: @@ -5266,8 +5267,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[2] = (page_code & 0xff); } c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = HPSA_INQUIRY; c->Request.CDB[4] = size & 0xFF; @@ -5278,8 +5279,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, mode = 00 target = 0. Nothing to write. */ c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = cmd; c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */ @@ -5289,8 +5290,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case HPSA_CACHE_FLUSH: c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; @@ -5299,14 +5301,14 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case TEST_UNIT_READY: c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); c->Request.Timeout = 0; break; case HPSA_GET_RAID_MAP: c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = HPSA_CISS_READ; c->Request.CDB[1] = cmd; @@ -5317,8 +5319,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case BMIC_SENSE_CONTROLLER_PARAMETERS: c->Request.CDBLen = 10; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_READ; c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS; @@ -5335,9 +5337,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, case HPSA_DEVICE_RESET_MSG: c->Request.CDBLen = 16; - c->Request.Type.Type = 1; /* It is a MSG not a CMD */ - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); c->Request.Timeout = 0; /* Don't time out */ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); c->Request.CDB[0] = cmd; @@ -5356,9 +5357,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, tlower = (u32) (a->Header.tag >> 32); tupper = (u32) (a->Header.tag & 0x0ffffffffULL); c->Request.CDBLen = 16; - c->Request.Type.Type = TYPE_MSG; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); c->Request.Timeout = 0; /* Don't time out */ c->Request.CDB[0] = HPSA_TASK_MANAGEMENT; c->Request.CDB[1] = HPSA_TMF_ABORT_TASK; @@ -5388,7 +5389,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, BUG(); } - switch (c->Request.Type.Direction) { + switch (GET_DIR(c->Request.type_attr_dir)) { case XFER_READ: pci_dir = PCI_DMA_FROMDEVICE; break; @@ -5746,9 +5747,8 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); cmd->Request.CDBLen = 16; - cmd->Request.Type.Type = TYPE_MSG; - cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE; - cmd->Request.Type.Direction = XFER_NONE; + cmd->Request.type_attr_dir = + TYPE_ATTR_DIR(TYPE_MSG, ATTR_HEADOFQUEUE, XFER_NONE); cmd->Request.Timeout = 0; /* Don't time out */ cmd->Request.CDB[0] = opcode; cmd->Request.CDB[1] = type; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 575eda8a8c5e51..cb988c41cad915 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -320,11 +320,19 @@ struct CommandListHeader { struct RequestBlock { u8 CDBLen; - struct { - u8 Type:3; - u8 Attribute:3; - u8 Direction:2; - } Type; + /* + * type_attr_dir: + * type: low 3 bits + * attr: middle 3 bits + * dir: high 2 bits + */ + u8 type_attr_dir; +#define TYPE_ATTR_DIR(t, a, d) ((((d) & 0x03) << 6) |\ + (((a) & 0x07) << 3) |\ + ((t) & 0x07)) +#define GET_TYPE(tad) ((tad) & 0x07) +#define GET_ATTR(tad) (((tad) >> 3) & 0x07) +#define GET_DIR(tad) (((tad) >> 6) & 0x03) u16 Timeout; u8 CDB[16]; }; From 6824ccbd6c5580ea4e78dd92833d8a4897dfa6bd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:45 -0500 Subject: [PATCH 208/889] hpsa: use atomics for commands_outstanding instead of protecting with spin locks Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik --- drivers/scsi/hpsa.c | 26 +++++++++----------------- drivers/scsi/hpsa.h | 27 +++++++-------------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 679668b4f019b7..663a254f69f229 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -392,7 +392,8 @@ static ssize_t host_show_commands_outstanding(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct ctlr_info *h = shost_to_hba(shost); - return snprintf(buf, 20, "%d\n", h->commands_outstanding); + return snprintf(buf, 20, "%d\n", + atomic_read(&h->commands_outstanding)); } static ssize_t host_show_transport_mode(struct device *dev, @@ -698,7 +699,6 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags; if (h->transMethod & CFGTBL_Trans_io_accel1) return h->access.command_completed(h, q); @@ -709,9 +709,7 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { a = rq->head[rq->current_entry]; rq->current_entry++; - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } else { a = FIFO_EMPTY; } @@ -5444,15 +5442,9 @@ static void start_io(struct ctlr_info *h, unsigned long *flags) /* Put job onto the completed Q */ addQ(&h->cmpQ, c); - - /* Must increment commands_outstanding before unlocking - * and submitting to avoid race checking for fifo full - * condition. - */ - h->commands_outstanding++; - - /* Tell the controller execute command */ + atomic_inc(&h->commands_outstanding); spin_unlock_irqrestore(&h->lock, *flags); + /* Tell the controller execute command */ h->access.submit_command(h, c); spin_lock_irqsave(&h->lock, *flags); } @@ -5498,6 +5490,7 @@ static inline void finish_cmd(struct CommandList *c) unsigned long flags; int io_may_be_stalled = 0; struct ctlr_info *h = c->h; + int count; spin_lock_irqsave(&h->lock, flags); removeQ(c); @@ -5518,11 +5511,10 @@ static inline void finish_cmd(struct CommandList *c) * want to get in a cycle where we call start_io every time * through here. */ - if (unlikely(h->fifo_recently_full) && - h->commands_outstanding < 5) - io_may_be_stalled = 1; - + count = atomic_read(&h->commands_outstanding); spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(h->fifo_recently_full) && count < 5) + io_may_be_stalled = 1; dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 24472cec7de34d..954f0de33b97f3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -118,7 +118,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; - int commands_outstanding; + atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 # define SIMPLE_MODE_INT 2 @@ -395,7 +395,7 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) { struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags, register_value = FIFO_EMPTY; + unsigned long register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ if (!(h->msi_vector || h->msix_vector)) { @@ -413,9 +413,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { register_value = rq->head[rq->current_entry]; rq->current_entry++; - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } else { register_value = FIFO_EMPTY; } @@ -433,11 +431,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) */ static unsigned long SA5_fifo_full(struct ctlr_info *h) { - if (h->commands_outstanding >= h->max_commands) - return 1; - else - return 0; - + return atomic_read(&h->commands_outstanding) >= h->max_commands; } /* * returns value read from hardware. @@ -448,13 +442,9 @@ static unsigned long SA5_completed(struct ctlr_info *h, { unsigned long register_value = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); - unsigned long flags; - if (register_value != FIFO_EMPTY) { - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); - } + if (register_value != FIFO_EMPTY) + atomic_dec(&h->commands_outstanding); #ifdef HPSA_DEBUG if (register_value != FIFO_EMPTY) @@ -510,7 +500,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) { u64 register_value; struct reply_queue_buffer *rq = &h->reply_queue[q]; - unsigned long flags; BUG_ON(q >= h->nreply_queues); @@ -528,9 +517,7 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) wmb(); writel((q << 24) | rq->current_entry, h->vaddr + IOACCEL_MODE1_CONSUMER_INDEX); - spin_lock_irqsave(&h->lock, flags); - h->commands_outstanding--; - spin_unlock_irqrestore(&h->lock, flags); + atomic_dec(&h->commands_outstanding); } return (unsigned long) register_value; } From 53303132c544db894fff3c32cb7f3b70774e6365 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:46 -0500 Subject: [PATCH 209/889] hpsa: remove spin lock around command allocation It is already using atomic test_and_set_bit to do the allocation. There is some microscopic chance of starvation, but it is so microscopic that it should never happen in reality. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 663a254f69f229..70a1b1d3e4587d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4668,19 +4668,32 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - unsigned long flags; + int loopcount; + + /* There is some *extremely* small but non-zero chance that that + * multiple threads could get in here, and one thread could + * be scanning through the list of bits looking for a free + * one, but the free ones are always behind him, and other + * threads sneak in behind him and eat them before he can + * get to them, so that while there is always a free one, a + * very unlucky thread might be starved anyway, never able to + * beat the other threads. In reality, this happens so + * infrequently as to be indistinguishable from never. + */ - spin_lock_irqsave(&h->lock, flags); + loopcount = 0; do { i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) { - spin_unlock_irqrestore(&h->lock, flags); - return NULL; - } - } while (test_and_set_bit - (i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0); - spin_unlock_irqrestore(&h->lock, flags); + if (i == h->nr_cmds) + i = 0; + loopcount++; + } while (test_and_set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && + loopcount < 10); + + /* Thread got starved? We do not expect this to ever happen. */ + if (loopcount >= 10 && i == h->nr_cmds) + return NULL; c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); @@ -4740,13 +4753,10 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; - unsigned long flags; i = c - h->cmd_pool; - spin_lock_irqsave(&h->lock, flags); clear_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); - spin_unlock_irqrestore(&h->lock, flags); } static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) From 123b6100b087c23a7336dadd2b976a3484e6fcb8 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:47 -0500 Subject: [PATCH 210/889] hpsa: reserve some commands for use by driver We need to reserve some commands for device rescans, aborts, and the pass through ioctls, etc. so we cannot give them all to the scsi mid layer. This is in preparation for removing cmd_special_alloc and cmd_special_free so that we can stop queuing commands internally in the driver so that we can remove the locks thta protect the queue that we will no longer have. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++-- drivers/scsi/hpsa.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 70a1b1d3e4587d..a6c5a443d3f4b1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4176,11 +4176,14 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds; + sh->can_queue = h->nr_cmds - + HPSA_CMDS_RESERVED_FOR_ABORTS - + HPSA_CMDS_RESERVED_FOR_DRIVER - + HPSA_MAX_CONCURRENT_PASSTHRUS; if (h->hba_mode_enabled) sh->cmd_per_lun = 7; else - sh->cmd_per_lun = h->nr_cmds; + sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 954f0de33b97f3..4fae28e1af56e5 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -115,6 +115,8 @@ struct ctlr_info { void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ +#define HPSA_CMDS_RESERVED_FOR_ABORTS 2 +#define HPSA_CMDS_RESERVED_FOR_DRIVER 1 struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; From b12dd6e9f96cbaa50ee9f2e4b3a84c87dedece93 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:47 -0500 Subject: [PATCH 211/889] hpsa: add change_queue_type function This is so that hpsa based devices support /sys/block/sdNN/device/queue_type of simple, which lets the SCSI midlayer automatically adjust the queue_depth based on TASK SET FULL and GOOD status. This patch does not change the default to simple, however; that is left as a user choice. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a6c5a443d3f4b1..1b68e6a29eea33 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -216,6 +216,7 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); +static int hpsa_change_queue_type(struct scsi_device *sdev, int type); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); @@ -672,6 +673,7 @@ static struct scsi_host_template hpsa_driver_template = { .scan_start = hpsa_scan_start, .scan_finished = hpsa_scan_finished, .change_queue_depth = hpsa_change_queue_depth, + .change_queue_type = hpsa_change_queue_type, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .eh_abort_handler = hpsa_eh_abort_handler, @@ -4152,6 +4154,20 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, return sdev->queue_depth; } +static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + static void hpsa_unregister_scsi(struct ctlr_info *h) { /* we are being forcibly unloaded, and may not refuse. */ From 10fd786747248a7932bcf492ed5373883edd73c7 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Tue, 28 Oct 2014 11:50:48 -0500 Subject: [PATCH 212/889] hpsa: add hpsa_bmic_id_physical_device function We need to get the queue depths from physical drives Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 39 ++++++++++++ drivers/scsi/hpsa_cmd.h | 133 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1b68e6a29eea33..b98e95c79d9f77 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2330,6 +2330,35 @@ static int hpsa_get_raid_map(struct ctlr_info *h, return rc; } +static int hpsa_bmic_id_physical_device(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_identify_physical_device *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + rc = fill_cmd(c, BMIC_IDENTIFY_PHYSICAL_DEVICE, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, + NO_TIMEOUT); + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -5354,6 +5383,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; break; + case BMIC_IDENTIFY_PHYSICAL_DEVICE: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_IDENTIFY_PHYSICAL_DEVICE; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index cb988c41cad915..ef5ad149a4fed0 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -268,6 +268,7 @@ struct SenseSubsystem_info { #define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ #define BMIC_FLASH_FIRMWARE 0xF7 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 +#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 /* Command List Structure */ union SCSI3Addr { @@ -644,5 +645,137 @@ struct hpsa_pci_info { u32 board_id; }; +struct bmic_identify_physical_device { + u8 scsi_bus; /* SCSI Bus number on controller */ + u8 scsi_id; /* SCSI ID on this bus */ + u16 block_size; /* sector size in bytes */ + u32 total_blocks; /* number for sectors on drive */ + u32 reserved_blocks; /* controller reserved (RIS) */ + u8 model[40]; /* Physical Drive Model */ + u8 serial_number[40]; /* Drive Serial Number */ + u8 firmware_revision[8]; /* drive firmware revision */ + u8 scsi_inquiry_bits; /* inquiry byte 7 bits */ + u8 compaq_drive_stamp; /* 0 means drive not stamped */ + u8 last_failure_reason; +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_LOAD_CONFIG 0x01 +#define BMIC_LAST_FAILURE_ERROR_ERASING_RIS 0x02 +#define BMIC_LAST_FAILURE_ERROR_SAVING_RIS 0x03 +#define BMIC_LAST_FAILURE_FAIL_DRIVE_COMMAND 0x04 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED 0x05 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED_IN_FINISH_REMAP 0x06 +#define BMIC_LAST_FAILURE_TIMEOUT 0x07 +#define BMIC_LAST_FAILURE_AUTOSENSE_FAILED 0x08 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_1 0x09 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_2 0x0a +#define BMIC_LAST_FAILURE_NOT_READY_BAD_SENSE 0x0b +#define BMIC_LAST_FAILURE_NOT_READY 0x0c +#define BMIC_LAST_FAILURE_HARDWARE_ERROR 0x0d +#define BMIC_LAST_FAILURE_ABORTED_COMMAND 0x0e +#define BMIC_LAST_FAILURE_WRITE_PROTECTED 0x0f +#define BMIC_LAST_FAILURE_SPIN_UP_FAILURE_IN_RECOVER 0x10 +#define BMIC_LAST_FAILURE_REBUILD_WRITE_ERROR 0x11 +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_HOT_PLUG 0x12 +#define BMIC_LAST_FAILURE_BUS_RESET_RECOVERY_ABORTED 0x13 +#define BMIC_LAST_FAILURE_REMOVED_IN_HOT_PLUG 0x14 +#define BMIC_LAST_FAILURE_INIT_REQUEST_SENSE_FAILED 0x15 +#define BMIC_LAST_FAILURE_INIT_START_UNIT_FAILED 0x16 +#define BMIC_LAST_FAILURE_INQUIRY_FAILED 0x17 +#define BMIC_LAST_FAILURE_NON_DISK_DEVICE 0x18 +#define BMIC_LAST_FAILURE_READ_CAPACITY_FAILED 0x19 +#define BMIC_LAST_FAILURE_INVALID_BLOCK_SIZE 0x1a +#define BMIC_LAST_FAILURE_HOT_PLUG_REQUEST_SENSE_FAILED 0x1b +#define BMIC_LAST_FAILURE_HOT_PLUG_START_UNIT_FAILED 0x1c +#define BMIC_LAST_FAILURE_WRITE_ERROR_AFTER_REMAP 0x1d +#define BMIC_LAST_FAILURE_INIT_RESET_RECOVERY_ABORTED 0x1e +#define BMIC_LAST_FAILURE_DEFERRED_WRITE_ERROR 0x1f +#define BMIC_LAST_FAILURE_MISSING_IN_SAVE_RIS 0x20 +#define BMIC_LAST_FAILURE_WRONG_REPLACE 0x21 +#define BMIC_LAST_FAILURE_GDP_VPD_INQUIRY_FAILED 0x22 +#define BMIC_LAST_FAILURE_GDP_MODE_SENSE_FAILED 0x23 +#define BMIC_LAST_FAILURE_DRIVE_NOT_IN_48BIT_MODE 0x24 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_HOT_PLUG 0x25 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_LOAD_CFG 0x26 +#define BMIC_LAST_FAILURE_PROTOCOL_ADAPTER_FAILED 0x27 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_EMPTY 0x28 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_OCCUPIED 0x29 +#define BMIC_LAST_FAILURE_FAULTY_ID_INVALID_BAY 0x2a +#define BMIC_LAST_FAILURE_WRITE_RETRIES_FAILED 0x2b + +#define BMIC_LAST_FAILURE_SMART_ERROR_REPORTED 0x37 +#define BMIC_LAST_FAILURE_PHY_RESET_FAILED 0x38 +#define BMIC_LAST_FAILURE_ONLY_ONE_CTLR_CAN_SEE_DRIVE 0x40 +#define BMIC_LAST_FAILURE_KC_VOLUME_FAILED 0x41 +#define BMIC_LAST_FAILURE_UNEXPECTED_REPLACEMENT 0x42 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE 0x80 +#define BMIC_LAST_FAILURE_OFFLINE_TOO_SMALL 0x81 +#define BMIC_LAST_FAILURE_OFFLINE_DRIVE_TYPE_MIX 0x82 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE_COMPLETE 0x83 + + u8 flags; + u8 more_flags; + u8 scsi_lun; /* SCSI LUN for phys drive */ + u8 yet_more_flags; + u8 even_more_flags; + u32 spi_speed_rules;/* SPI Speed data:Ultra disable diagnose */ + u8 phys_connector[2]; /* connector number on controller */ + u8 phys_box_on_bus; /* phys enclosure this drive resides */ + u8 phys_bay_in_box; /* phys drv bay this drive resides */ + u32 rpm; /* Drive rotational speed in rpm */ + u8 device_type; /* type of drive */ + u8 sata_version; /* only valid when drive_type is SATA */ + u64 big_total_block_count; + u64 ris_starting_lba; + u32 ris_size; + u8 wwid[20]; + u8 controller_phy_map[32]; + u16 phy_count; + u8 phy_connected_dev_type[256]; + u8 phy_to_drive_bay_num[256]; + u16 phy_to_attached_dev_index[256]; + u8 box_index; + u8 reserved; + u16 extra_physical_drive_flags; +#define BMIC_PHYS_DRIVE_SUPPORTS_GAS_GAUGE(idphydrv) \ + (idphydrv->extra_physical_drive_flags & (1 << 10)) + u8 negotiated_link_rate[256]; + u8 phy_to_phy_map[256]; + u8 redundant_path_present_map; + u8 redundant_path_failure_map; + u8 active_path_number; + u16 alternate_paths_phys_connector[8]; + u8 alternate_paths_phys_box_on_port[8]; + u8 multi_lun_device_lun_count; + u8 minimum_good_fw_revision[8]; + u8 unique_inquiry_bytes[20]; + u8 current_temperature_degreesC; + u8 temperature_threshold_degreesC; + u8 max_temperature_degreesC; + u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512 * 2^exp */ + u16 current_queue_depth_limit; + u8 switch_name[10]; + u16 switch_port; + u8 alternate_paths_switch_name[40]; + u8 alternate_paths_switch_port[8]; + u16 power_on_hours; /* valid only if gas gauge supported */ + u16 percent_endurance_used; /* valid only if gas gauge supported. */ +#define BMIC_PHYS_DRIVE_SSD_WEAROUT(idphydrv) \ + ((idphydrv->percent_endurance_used & 0x80) || \ + (idphydrv->percent_endurance_used > 10000)) + u8 drive_authentication; +#define BMIC_PHYS_DRIVE_AUTHENTICATED(idphydrv) \ + (idphydrv->drive_authentication == 0x80) + u8 smart_carrier_authentication; +#define BMIC_SMART_CARRIER_AUTHENTICATION_SUPPORTED(idphydrv) \ + (idphydrv->smart_carrier_authentication != 0x0) +#define BMIC_SMART_CARRIER_AUTHENTICATED(idphydrv) \ + (idphydrv->smart_carrier_authentication == 0x01) + u8 smart_carrier_app_fw_version; + u8 smart_carrier_bootloader_fw_version; + u8 encryption_key_name[64]; + u32 misc_drive_flags; + u16 dek_index; + u8 padding[112]; +}; + #pragma pack() #endif /* HPSA_CMD_H */ From 6618d23a875868bddc12c13ade152fb786487f5a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:48 -0500 Subject: [PATCH 213/889] hpsa: add hpsa_disable_interrupt_mode In preparation for cleaning up in case of irq allocation failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b98e95c79d9f77..8d6f78749222b1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6161,10 +6161,22 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) return -1; } +static void hpsa_disable_interrupt_mode(struct ctlr_info *h) +{ +#ifdef CONFIG_PCI_MSI + if (h->msix_vector) { + if (h->pdev->msix_enabled) + pci_disable_msix(h->pdev); + } else if (h->msi_vector) { + if (h->pdev->msi_enabled) + pci_disable_msi(h->pdev); + } +#endif /* CONFIG_PCI_MSI */ +} + /* If MSI/MSI-X is supported by the kernel we will try to enable it on * controllers that are capable. If not, we use IO-APIC mode. */ - static void hpsa_interrupt_mode(struct ctlr_info *h) { #ifdef CONFIG_PCI_MSI From 19ddc34046c3c52cd05956531667f20e9370a588 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:49 -0500 Subject: [PATCH 214/889] hpsa: add hpsa_free_pci_init function In preparation for cleanup of error handling in hpsa_pci_init Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8d6f78749222b1..c7ce32bf623e56 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6484,6 +6484,17 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) return -ENODEV; } +/* free items allocated or mapped by hpsa_pci_init */ +static void hpsa_free_pci_init(struct ctlr_info *h) +{ + hpsa_free_cfgtables(h); /* pci_init 4 */ + iounmap(h->vaddr); /* pci_init 3 */ + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ + pci_release_regions(h->pdev); /* pci_init 2 */ + pci_disable_device(h->pdev); /* pci_init 1 */ +} + +/* several items must be freed later */ static int hpsa_pci_init(struct ctlr_info *h) { int prod_index, err; From 97a763599d2fcb1b82eeb0c65578cf894b4f6020 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:49 -0500 Subject: [PATCH 215/889] hpsa: allow lockup detector to be turned off Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/hpsa.h | 1 + 2 files changed, 40 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c7ce32bf623e56..aa205e26c65b1b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -312,6 +312,38 @@ static int check_for_busy(struct ctlr_info *h, struct CommandList *c) return 1; } +static ssize_t host_store_lockup_detector(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost; + struct ctlr_info *h; + int len, enabled; + char tmpbuf[10]; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%d", &enabled) != 1) + return -EINVAL; + shost = class_to_shost(dev); + h = shost_to_hba(shost); + h->lockup_detector_enabled = !!enabled; + return count; +} + +static ssize_t host_show_lockup_detector(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); +} + static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -645,6 +677,8 @@ static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL); static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); +static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, + host_show_lockup_detector, host_store_lockup_detector); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -662,6 +696,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, + &dev_attr_lockup_detector, NULL, }; @@ -6874,6 +6909,9 @@ static void detect_controller_lockup(struct ctlr_info *h) u32 heartbeat; unsigned long flags; + if (!h->lockup_detector_enabled) + return; + now = get_jiffies_64(); /* If we've received an interrupt recently, we're ok. */ if (time_after64(h->last_intr_timestamp + @@ -7175,6 +7213,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->acciopath_status = 1; h->drv_req_rescan = 0; + h->lockup_detector_enabled = 1; /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 4fae28e1af56e5..f6cf8b2f82e616 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -241,6 +241,7 @@ struct ctlr_info { int acciopath_status; int drv_req_rescan; /* flag for driver to request rescan event */ int raid_offload_debug; + int lockup_detector_enabled; }; struct offline_device_entry { From 31bec7717b3a5c1b01c377023c818250aa6a6434 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:50 -0500 Subject: [PATCH 216/889] hpsa: change driver version to 3.4.6 Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index aa205e26c65b1b..7979a2accb1873 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.4-1" +#define HPSA_DRIVER_VERSION "3.4.6-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" From 312a7c3eaf3508d49aca44904389c24f69e9b04c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:51 -0500 Subject: [PATCH 217/889] hpsa: check for ctlr lockup after command allocation in main io path Command allocation is the thing that takes the longest in the main i/o path, so check for controller lockup immediately after this to prevent submitting commands to locked up controller as much as possible. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 81 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7979a2accb1873..5346edf3abcf91 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4130,7 +4130,86 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, return 0; } -static DEF_SCSI_QCMD(hpsa_scsi_queue_command) +static void hpsa_command_resubmit_worker(struct work_struct *work) +{ + struct scsi_cmnd *cmd; + struct hpsa_scsi_dev_t *dev; + struct CommandList *c = + container_of(work, struct CommandList, work); + + cmd = c->scsi_cmd; + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return; + } + if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + /* + * If we get here, it means dma mapping failed. Try + * again via scsi mid layer, which will then get + * SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } +} + +/* Running in struct Scsi_Host->host_lock less mode */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct ctlr_info *h; + struct hpsa_scsi_dev_t *dev; + unsigned char scsi3addr[8]; + struct CommandList *c; + int rc = 0; + + /* Get the ptr to our adapter structure out of cmd->host. */ + h = sdev_to_hba(cmd->device); + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); + + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + return 0; + } + c = cmd_alloc(h); + if (c == NULL) { /* trouble... */ + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd_free(h, c); + cmd->scsi_done(cmd); + return 0; + } +>>>>>>> patched + + break; + + default: + dev_err(&h->pdev->dev, "unknown data direction: %d\n", + cmd->sc_data_direction); + BUG(); + break; + } + + if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + enqueue_cmd_and_start_io(h, c); + /* the cmd'll come back via intr handler in complete_scsi_command() */ + return 0; +} +>>>>>>> patched static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) { From a459d4066f683eda49fcc6660b79d7910a9e37bf Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 28 Oct 2014 11:50:51 -0500 Subject: [PATCH 218/889] hpsa: Convert SCSI LLD ->queuecommand() for host_lock less operation There isn't anything in hpsa that requires the host lock to be held during queuecommand. Signed-off-by: Nicholas Bellinger Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5346edf3abcf91..2d728570e9a94f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4005,8 +4005,11 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +/* + * Running in struct Scsi_Host->host_lock less mode using LLD internal + * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection. + */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; @@ -4019,14 +4022,14 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); if (unlikely(lockup_detected(h))) { cmd->result = DID_ERROR << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } c = cmd_alloc(h); @@ -4036,9 +4039,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, } /* Fill in the command list header */ - - cmd->scsi_done = done; /* save this for use by completion code */ - /* save c in case we have to abort it */ cmd->host_scribble = (unsigned char *) c; @@ -4190,16 +4190,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); return 0; } ->>>>>>> patched - - break; - - default: - dev_err(&h->pdev->dev, "unknown data direction: %d\n", - cmd->sc_data_direction); - BUG(); - break; - } if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ cmd_free(h, c); @@ -4209,7 +4199,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) /* the cmd'll come back via intr handler in complete_scsi_command() */ return 0; } ->>>>>>> patched static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) { From bc4c86af76d9bbc0b0018d669e0562d723d8a766 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:52 -0500 Subject: [PATCH 219/889] hpsa: check pci ids This isn't meant to go into the driver except temporarily as a way to check that the pci id tables are somewhat sane -- match each other, don't contain duplicates, etc. --- drivers/scsi/hpsa.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2d728570e9a94f..1153370bf5a1f2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7126,6 +7126,83 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) spin_unlock_irqrestore(&h->lock, flags); } +static void check_board_id_tables(void) +{ + int i, j, found; + uint32_t board_id; + int count; + + for (i = 0; i < ARRAY_SIZE(products); i++) { + board_id = products[i].board_id; + if (board_id == 0xFFFF103C) /* sentinel entry */ + continue; + found = 0; + count = 0; + for (j = 0; j < ARRAY_SIZE(hpsa_pci_device_id); j++) { + uint32_t bid; + + bid = (hpsa_pci_device_id[j].subdevice << 16) | + hpsa_pci_device_id[j].subvendor; + if (bid == board_id) { + found = 1; + if (i != j) { + printk(KERN_WARNING HPSA + ": products[%d] (%s) found at pci table entry %d\n", + i, products[i].product_name, j); + } + count++; + } + } + if (!found) + printk(KERN_WARNING HPSA + ": products[%d] (%s) not found in pci table\n", + i, products[i].product_name); + if (count > 1) + printk(KERN_WARNING HPSA + ": products[%d] (%s) has duplicate entries in pci table\n", + i, products[i].product_name); + } + + for (i = 0; i < ARRAY_SIZE(hpsa_pci_device_id); i++) { + board_id = (hpsa_pci_device_id[i].subdevice << 16) | + hpsa_pci_device_id[i].subvendor; + if (hpsa_pci_device_id[i].vendor == 0) /* sentinel */ + continue; + if (hpsa_pci_device_id[i].subvendor == PCI_ANY_ID && + hpsa_pci_device_id[i].subdevice == PCI_ANY_ID) + continue; + count = 0; + found = 0; + for (j = 0; j < ARRAY_SIZE(products); j++) { + if (board_id == products[j].board_id) { + if (j != i) { + printk(KERN_WARNING HPSA + ": pci table entry %d found at product entry %d (%s)\n", + i, j, products[j].product_name); + } + found = 1; + count++; + } + } + if (!found) + printk(KERN_WARNING HPSA + ": pci table entry %d (%04x:%04x) not found in product table\n", + i, hpsa_pci_device_id[i].subvendor, + hpsa_pci_device_id[i].subdevice); + if (count > 1) + printk(KERN_WARNING HPSA + ": pci table entry %d (%04x:%04x) has duplicate product[] entries\n", + i, hpsa_pci_device_id[i].subvendor, + hpsa_pci_device_id[i].subdevice); + } + if (ARRAY_SIZE(products) != ARRAY_SIZE(hpsa_pci_device_id) - 1) { + printk(KERN_WARNING HPSA + ": suspicious relative cardinality of products vs hpsa_pci_device_id (%lu/%lu)\n", + (unsigned long) ARRAY_SIZE(products), + (unsigned long) ARRAY_SIZE(hpsa_pci_device_id)); + } +} + static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; @@ -7133,6 +7210,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) int try_soft_reset = 0; unsigned long flags; + check_board_id_tables(); if (number_of_controllers == 0) printk(KERN_INFO DRIVER_NAME "\n"); From 5aafc39ab3efd58c1359578175e21a819ded963c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:52 -0500 Subject: [PATCH 220/889] hpsa: do not be so noisy about check conditions We were printing a lot of useless information before ultimately just passing things up to the SCSI mid layer. Just let the midlayer handle it without LLD chatter. Signed-off-by: Stephen M. Cameron Reviewed-by: Joe Handzik Reviewed-by: Scott Teel --- drivers/scsi/hpsa.c | 59 --------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1153370bf5a1f2..9345a186bbc42b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1795,72 +1795,13 @@ static void complete_scsi_command(struct CommandList *cp) /* Get addition sense code qualifier */ ascq = ei->SenseInfo[13]; } - if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { - if (check_for_unit_attention(h, cp)) - break; - if (sense_key == ILLEGAL_REQUEST) { - /* - * SCSI REPORT_LUNS is commonly unsupported on - * Smart Array. Suppress noisy complaint. - */ - if (cp->Request.CDB[0] == REPORT_LUNS) - break; - - /* If ASC/ASCQ indicate Logical Unit - * Not Supported condition, - */ - if ((asc == 0x25) && (ascq == 0x0)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition\n", cp); - break; - } - } - - if (sense_key == NOT_READY) { - /* If Sense is Not Ready, Logical Unit - * Not ready, Manual Intervention - * required - */ - if ((asc == 0x04) && (ascq == 0x03)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: unit " - "not ready, manual " - "intervention required\n", cp); - break; - } - } if (sense_key == ABORTED_COMMAND) { - /* Aborted command is retryable */ - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: aborted command: " - "ASC: 0x%x, ASCQ: 0x%x\n", - cp, asc, ascq); cmd->result |= DID_SOFT_ERROR << 16; break; } - /* Must be some other type of check condition */ - dev_dbg(&h->pdev->dev, "cp %p has check condition: " - "unknown type: " - "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " - "Returning result: 0x%x, " - "cmd=[%02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x]\n", - cp, sense_key, asc, ascq, - cmd->result, - cmd->cmnd[0], cmd->cmnd[1], - cmd->cmnd[2], cmd->cmnd[3], - cmd->cmnd[4], cmd->cmnd[5], - cmd->cmnd[6], cmd->cmnd[7], - cmd->cmnd[8], cmd->cmnd[9], - cmd->cmnd[10], cmd->cmnd[11], - cmd->cmnd[12], cmd->cmnd[13], - cmd->cmnd[14], cmd->cmnd[15]); break; } - - /* Problem was not a check condition * Pass it up to the upper layers... */ From f1c3fe8fb1c947b4dc5a6cc446100c7b04a4e50a Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:53 -0500 Subject: [PATCH 221/889] hpsa: do not check for msi(x) in interrupt_pending No need to check whether interrupt pending for MSI(X) and conversely, no need to check whether MSI(X) interrupts are being used when checking if interrupts are pending. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index f6cf8b2f82e616..97da71d8ee1364 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -476,9 +476,6 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h) if (!register_value) return false; - if (h->msi_vector || h->msix_vector) - return true; - /* Read outbound doorbell to flush */ register_value = readl(h->vaddr + SA5_OUTDB_STATUS); return register_value & SA5_OUTDB_STATUS_PERF_BIT; From b35f5c3b1c11845fb4df3bdd5b8b2abdf671a750 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:53 -0500 Subject: [PATCH 222/889] hpsa: do not ignore return value of hpsa_register_scsi Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9345a186bbc42b..0b8af730a95c6f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7306,7 +7306,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ + if (hpsa_register_scsi(h)) /* hook ourselves into SCSI subsystem */ + goto clean4; /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; From 91da208aec32255142a028ea7f484b947a6fa0df Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:54 -0500 Subject: [PATCH 223/889] hpsa: get rid of cmd_special_alloc and cmd_special_free Always use cmd_alloc and cmd_free instead, we should have reserved enough commands that we should not need to ever dynamically allocate any and should always have enough. This is laying the groundwork for removing the internal queue of commands from the driver so that the locks that protect that queue may be removed. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 106 +++++++++++++------------------------------- drivers/scsi/hpsa.h | 2 +- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0b8af730a95c6f..268efb91fbe208 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -202,9 +202,7 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); #endif static void cmd_free(struct ctlr_info *h, struct CommandList *c); -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); -static struct CommandList *cmd_special_alloc(struct ctlr_info *h); static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type); @@ -2085,10 +2083,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2104,7 +2102,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2116,10 +2114,10 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2135,7 +2133,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2146,10 +2144,9 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); - + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2165,7 +2162,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, hpsa_scsi_interpret_error(h, c); rc = -1; } - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2275,26 +2272,26 @@ static int hpsa_get_raid_map(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - cmd_special_free(h, c); + cmd_free(h, c); return -ENOMEM; } hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); - cmd_special_free(h, c); + cmd_free(h, c); return -1; } - cmd_special_free(h, c); + cmd_free(h, c); /* @todo in the future, dynamically allocate RAID map memory */ if (le32_to_cpu(this_device->raid_map.structure_size) > @@ -2443,9 +2440,9 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, unsigned char scsi3addr[8]; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -1; } /* address the controller */ @@ -2473,7 +2470,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -4303,7 +4300,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, int waittime = 1; /* seconds */ struct CommandList *c; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { dev_warn(&h->pdev->dev, "out of memory in " "wait_for_device_to_become_ready.\n"); @@ -4349,7 +4346,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, else dev_warn(&h->pdev->dev, "device is ready.\n"); - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -4428,9 +4425,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; u32 tagupper, taglower; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -4459,7 +4456,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; break; } - cmd_special_free(h, c); + cmd_free(h, c); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, tagupper, taglower); return rc; @@ -4808,40 +4805,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) return c; } -/* For operations that can wait for kmalloc to possibly sleep, - * this routine can be called. Lock need not be held to call - * cmd_special_alloc. cmd_special_free() is the complement. - */ -static struct CommandList *cmd_special_alloc(struct ctlr_info *h) -{ - struct CommandList *c; - dma_addr_t cmd_dma_handle, err_dma_handle; - - c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); - if (c == NULL) - return NULL; - - c->cmd_type = CMD_SCSI; - c->cmdindex = -1; - - c->err_info = pci_zalloc_consistent(h->pdev, sizeof(*c->err_info), - &err_dma_handle); - - if (c->err_info == NULL) { - pci_free_consistent(h->pdev, - sizeof(*c), c, cmd_dma_handle); - return NULL; - } - - INIT_LIST_HEAD(&c->list); - c->busaddr = (u32) cmd_dma_handle; - c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); - c->ErrDesc.Len = sizeof(*c->err_info); - - c->h = h; - return c; -} - static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; @@ -4851,15 +4814,6 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c) h->cmd_pool_bits + (i / BITS_PER_LONG)); } -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) -{ - pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, - (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr)); - pci_free_consistent(h->pdev, sizeof(*c), - c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); -} - #ifdef CONFIG_COMPAT static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg) @@ -5037,7 +4991,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) memset(buff, 0, iocommand.buf_size); } } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { rc = -ENOMEM; goto out_kfree; @@ -5096,7 +5050,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) } } out: - cmd_special_free(h, c); + cmd_free(h, c); out_kfree: kfree(buff); return rc; @@ -5175,7 +5129,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) data_ptr += sz; sg_used++; } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { status = -ENOMEM; goto cleanup1; @@ -5230,7 +5184,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } status = 0; cleanup0: - cmd_special_free(h, c); + cmd_free(h, c); cleanup1: if (buff) { for (i = 0; i < sg_used; i++) @@ -6404,7 +6358,7 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) static void hpsa_find_board_params(struct ctlr_info *h) { hpsa_get_max_perf_mode_cmds(h); - h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ + h->nr_cmds = h->max_commands; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); /* @@ -7340,9 +7294,9 @@ static void hpsa_flush_cache(struct ctlr_info *h) if (!flush_buf) return; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); goto out_of_memory; } if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, @@ -7354,7 +7308,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) out: dev_warn(&h->pdev->dev, "error flushing cache on controller\n"); - cmd_special_free(h, c); + cmd_free(h, c); out_of_memory: kfree(flush_buf); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 97da71d8ee1364..38ef11718cd5e4 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -170,7 +170,7 @@ struct ctlr_info { unsigned long transMethod; /* cap concurrent passthrus at some reasonable maximum */ -#define HPSA_MAX_CONCURRENT_PASSTHRUS (20) +#define HPSA_MAX_CONCURRENT_PASSTHRUS (10) spinlock_t passthru_count_lock; /* protects passthru_count */ int passthru_count; From 92c9f60f86347498dcaa5be1a4c5163a219e9b37 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:55 -0500 Subject: [PATCH 224/889] hpsa: do not queue commands internally in driver By not doing this, we can eliminate some spin locking in the main i/o path and gain significant improvement in IOPS. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 257 ++++++---------------------------------- drivers/scsi/hpsa.h | 3 - drivers/scsi/hpsa_cmd.h | 1 - 3 files changed, 34 insertions(+), 227 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 268efb91fbe208..040b8f5817b896 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -194,8 +194,6 @@ static int number_of_controllers; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); -static void lock_and_start_io(struct ctlr_info *h); -static void start_io(struct ctlr_info *h, unsigned long *flags); #ifdef CONFIG_COMPAT static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); @@ -723,13 +721,6 @@ static struct scsi_host_template hpsa_driver_template = { .no_write_same = 1, }; - -/* Enqueuing and dequeuing functions for cmdlists. */ -static inline void addQ(struct list_head *list, struct CommandList *c) -{ - list_add_tail(&c->list, list); -} - static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; @@ -863,8 +854,6 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - unsigned long flags; - switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c); @@ -876,18 +865,8 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h, set_performant_mode(h, c); } dial_down_lockup_detection_during_fw_flash(h, c); - spin_lock_irqsave(&h->lock, flags); - addQ(&h->reqQ, c); - h->Qdepth++; - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - -static inline void removeQ(struct CommandList *c) -{ - if (WARN_ON(list_empty(&c->list))) - return; - list_del_init(&c->list); + atomic_inc(&h->commands_outstanding); + h->access.submit_command(h, c); } static inline int is_hba_lunid(unsigned char scsi3addr[]) @@ -3943,10 +3922,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -/* - * Running in struct Scsi_Host->host_lock less mode using LLD internal - * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection. - */ +/* Running in struct Scsi_Host->host_lock less mode */ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; @@ -4462,56 +4438,6 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, return rc; } -/* - * hpsa_find_cmd_in_queue - * - * Used to determine whether a command (find) is still present - * in queue_head. Optionally excludes the last element of queue_head. - * - * This is used to avoid unnecessary aborts. Commands in h->reqQ have - * not yet been submitted, and so can be aborted by the driver without - * sending an abort to the hardware. - * - * Returns pointer to command if found in queue, NULL otherwise. - */ -static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h, - struct scsi_cmnd *find, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c = NULL; /* ptr into cmpQ */ - - if (!find) - return 0; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */ - continue; - if (c->scsi_cmd == find) { - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - -static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, - u8 *tag, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c; - - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (memcmp(&c->Header.tag, tag, 8) != 0) - continue; - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - /* ioaccel2 path firmware cannot handle abort task requests. * Change abort requests to physical target reset, and send to the * address of the physical disk used for the ioaccel 2 command. @@ -4598,10 +4524,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort) { - u8 swizzled_tag[8]; - struct CommandList *c; - int rc = 0, rc2 = 0; - /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, * but underlying firmware can't handle abort TMF. @@ -4610,27 +4532,8 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, if (abort->cmd_type == CMD_IOACCEL2) return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort); - /* we do not expect to find the swizzled tag in our queue, but - * check anyway just to be sure the assumptions which make this - * the case haven't become wrong. - */ - memcpy(swizzled_tag, &abort->Request.CDB[4], 8); - swizzle_abort_tag(swizzled_tag); - c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ); - if (c != NULL) { - dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n"); - return hpsa_send_abort(h, scsi3addr, abort, 0); - } - rc = hpsa_send_abort(h, scsi3addr, abort, 0); - - /* if the command is still in our queue, we can't conclude that it was - * aborted (it might have just completed normally) but in any case - * we don't need to try to abort it another way. - */ - c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ); - if (c) - rc2 = hpsa_send_abort(h, scsi3addr, abort, 1); - return rc && rc2; + return hpsa_send_abort(h, scsi3addr, abort, 0) && + hpsa_send_abort(h, scsi3addr, abort, 1); } /* Send an abort for the specified command. @@ -4644,7 +4547,6 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; struct CommandList *abort; /* pointer to command to be aborted */ - struct CommandList *found; struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */ char msg[256]; /* For debug messaging. */ int ml = 0; @@ -4690,28 +4592,6 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) dev_dbg(&h->pdev->dev, "%s\n", msg); dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); - - /* Search reqQ to See if command is queued but not submitted, - * if so, complete the command with aborted status and remove - * it from the reqQ. - */ - found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ); - if (found) { - found->err_info->CommandStatus = CMD_ABORTED; - finish_cmd(found); - dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n", - msg); - return SUCCESS; - } - - /* not in reqQ, if also not in cmpQ, must have already completed */ - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) { - dev_dbg(&h->pdev->dev, "%s Request SUCCEEDED (not known to driver).\n", - msg); - return SUCCESS; - } - /* * Command is in flight, or possibly already completed * by the firmware (but not to the scsi mid layer) but we can't @@ -4734,10 +4614,12 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ #define ABORT_COMPLETE_WAIT_SECS 30 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) + if (test_bit(abort->cmdindex & (BITS_PER_LONG - 1), + h->cmd_pool_bits + + (abort->cmdindex / BITS_PER_LONG))) + msleep(100); + else return SUCCESS; - msleep(100); } dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", msg, ABORT_COMPLETE_WAIT_SECS); @@ -4786,6 +4668,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); + c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT) | + DIRECT_LOOKUP_BIT); cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; @@ -4795,7 +4679,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c->cmdindex = i; - INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; temp64.val = (u64) err_dma_handle; c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); @@ -5008,8 +4891,6 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGTotal = cpu_to_le16(0); } memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); - /* use the kernel address the cmd block for tag */ - c->Header.tag = c->busaddr; /* Fill in Request block */ memcpy(&c->Request, &iocommand.Request, @@ -5139,7 +5020,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGList = (u8) sg_used; c->Header.SGTotal = cpu_to_le16(sg_used); memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.tag = c->busaddr; memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; @@ -5309,7 +5189,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Header.SGList = 0; c->Header.SGTotal = 0; } - c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); if (cmd_type == TYPE_CMD) { @@ -5484,47 +5363,6 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) return page_remapped ? (page_remapped + page_offs) : NULL; } -/* Takes cmds off the submission queue and sends them to the hardware, - * then puts them on the queue of cmds waiting for completion. - * Assumes h->lock is held - */ -static void start_io(struct ctlr_info *h, unsigned long *flags) -{ - struct CommandList *c; - - while (!list_empty(&h->reqQ)) { - c = list_entry(h->reqQ.next, struct CommandList, list); - /* can't do anything if fifo is full */ - if ((h->access.fifo_full(h))) { - h->fifo_recently_full = 1; - dev_warn(&h->pdev->dev, "fifo full\n"); - break; - } - h->fifo_recently_full = 0; - - /* Get the first entry from the Request Q */ - removeQ(c); - h->Qdepth--; - - /* Put job onto the completed Q */ - addQ(&h->cmpQ, c); - atomic_inc(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, *flags); - /* Tell the controller execute command */ - h->access.submit_command(h, c); - spin_lock_irqsave(&h->lock, *flags); - } -} - -static void lock_and_start_io(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->lock, flags); - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q) { return h->access.command_completed(h, q); @@ -5553,43 +5391,12 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index, static inline void finish_cmd(struct CommandList *c) { - unsigned long flags; - int io_may_be_stalled = 0; - struct ctlr_info *h = c->h; - int count; - - spin_lock_irqsave(&h->lock, flags); - removeQ(c); - - /* - * Check for possibly stalled i/o. - * - * If a fifo_full condition is encountered, requests will back up - * in h->reqQ. This queue is only emptied out by start_io which is - * only called when a new i/o request comes in. If no i/o's are - * forthcoming, the i/o's in h->reqQ can get stuck. So we call - * start_io from here if we detect such a danger. - * - * Normally, we shouldn't hit this case, but pounding on the - * CCISS_PASSTHRU ioctl can provoke it. Only call start_io if - * commands_outstanding is low. We want to avoid calling - * start_io from in here as much as possible, and esp. don't - * want to get in a cycle where we call start_io every time - * through here. - */ - count = atomic_read(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, flags); - if (unlikely(h->fifo_recently_full) && count < 5) - io_may_be_stalled = 1; - dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI || c->cmd_type == CMD_IOACCEL2)) complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); - if (unlikely(io_may_be_stalled)) - lock_and_start_io(h); } static inline u32 hpsa_tag_contains_index(u32 tag) @@ -5634,6 +5441,10 @@ static inline void process_nonindexed_cmd(struct ctlr_info *h, struct CommandList *c = NULL; unsigned long flags; + /* FIXME finish removing process nonindexed command */ + dev_warn(&h->pdev->dev, "unexpectedly got non-indexed command\n"); + return; +#if 0 tag = hpsa_tag_discard_error_bits(h, raw_tag); spin_lock_irqsave(&h->lock, flags); list_for_each_entry(c, &h->cmpQ, list) { @@ -5645,6 +5456,7 @@ static inline void process_nonindexed_cmd(struct ctlr_info *h, } spin_unlock_irqrestore(&h->lock, flags); bad_tag(h, h->nr_cmds + 1, raw_tag); +#endif } /* Some controllers, like p400, will give us one interrupt @@ -6814,14 +6626,16 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) } /* Called when controller lockup detected. */ -static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) +static void fail_all_outstanding_cmds(struct ctlr_info *h) { + int i; struct CommandList *c = NULL; - assert_spin_locked(&h->lock); - /* Mark all outstanding commands as failed and complete them. */ - while (!list_empty(list)) { - c = list_entry(list->next, struct CommandList, list); + for (i = 0; i < h->nr_cmds; i++) { + if (!test_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG))) + continue; + c = h->cmd_pool + i; c->err_info->CommandStatus = CMD_HARDWARE_ERR; finish_cmd(c); } @@ -6861,8 +6675,7 @@ static void controller_lockup_detected(struct ctlr_info *h) lockup_detected); pci_disable_device(h->pdev); spin_lock_irqsave(&h->lock, flags); - fail_all_cmds_on_list(h, &h->cmpQ); - fail_all_cmds_on_list(h, &h->reqQ); + fail_all_outstanding_cmds(h); spin_unlock_irqrestore(&h->lock, flags); } @@ -7135,8 +6948,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->pdev = pdev; h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; - INIT_LIST_HEAD(&h->cmpQ); - INIT_LIST_HEAD(&h->reqQ); INIT_LIST_HEAD(&h->offline_device_list); spin_lock_init(&h->lock); spin_lock_init(&h->offline_device_lock); @@ -7747,19 +7558,19 @@ static int is_accelerated_cmd(struct CommandList *c) static void hpsa_drain_accel_commands(struct ctlr_info *h) { struct CommandList *c = NULL; - unsigned long flags; - int accel_cmds_out; + int i, accel_cmds_out; - do { /* wait for all outstanding commands to drain out */ + do { /* wait for all outstanding ioaccel commands to drain out */ accel_cmds_out = 0; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) - accel_cmds_out += is_accelerated_cmd(c); - list_for_each_entry(c, &h->reqQ, list) + for (i = 0; i < h->nr_cmds; i++) { + if (!test_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG))) + continue; + c = h->cmd_pool + i; accel_cmds_out += is_accelerated_cmd(c); - spin_unlock_irqrestore(&h->lock, flags); + } if (accel_cmds_out <= 0) - break; + break; msleep(100); } while (1); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 38ef11718cd5e4..d00c29e9cad26d 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -133,8 +133,6 @@ struct ctlr_info { char hba_mode_enabled; /* queue and queue Info */ - struct list_head reqQ; - struct list_head cmpQ; unsigned int Qdepth; unsigned int maxSG; spinlock_t lock; @@ -197,7 +195,6 @@ struct ctlr_info { u32 *lockup_detected; struct delayed_work monitor_ctlr_work; int remove_in_progress; - u32 fifo_recently_full; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index ef5ad149a4fed0..037b10f773e97c 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -406,7 +406,6 @@ struct CommandList { struct ctlr_info *h; int cmd_type; long cmdindex; - struct list_head list; struct completion *waiting; void *scsi_cmd; } __aligned(COMMANDLIST_ALIGNMENT); From dc0161da27ed6bb6118c7f31217b796793b74fd0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:55 -0500 Subject: [PATCH 225/889] hpsa: remove unused interrupt handler code Now that we never use "non-indexed" method for completing commands we can remove the code to handle that from the interrupt handler Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 040b8f5817b896..298b2fe897c1c6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5399,11 +5399,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } -static inline u32 hpsa_tag_contains_index(u32 tag) -{ - return tag & DIRECT_LOOKUP_BIT; -} - static inline u32 hpsa_tag_to_index(u32 tag) { return tag >> DIRECT_LOOKUP_SHIFT; @@ -5433,32 +5428,6 @@ static inline void process_indexed_cmd(struct ctlr_info *h, } } -/* process completion of a non-indexed command */ -static inline void process_nonindexed_cmd(struct ctlr_info *h, - u32 raw_tag) -{ - u32 tag; - struct CommandList *c = NULL; - unsigned long flags; - - /* FIXME finish removing process nonindexed command */ - dev_warn(&h->pdev->dev, "unexpectedly got non-indexed command\n"); - return; -#if 0 - tag = hpsa_tag_discard_error_bits(h, raw_tag); - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) { - if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { - spin_unlock_irqrestore(&h->lock, flags); - finish_cmd(c); - return; - } - } - spin_unlock_irqrestore(&h->lock, flags); - bad_tag(h, h->nr_cmds + 1, raw_tag); -#endif -} - /* Some controllers, like p400, will give us one interrupt * after a soft reset, even if we turned interrupts off. * Only need to check for this in the hpsa_xxx_discard_completions @@ -5536,10 +5505,7 @@ static irqreturn_t do_hpsa_intr_intx(int irq, void *queue) while (interrupt_pending(h)) { raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } } @@ -5555,10 +5521,7 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *queue) h->last_intr_timestamp = get_jiffies_64(); raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } return IRQ_HANDLED; From 5b9119f7378760991191b86ba3b7d3dd6c98b905 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:56 -0500 Subject: [PATCH 226/889] hpsa: remove direct lookup bit from command tags Now that every commmand is "direct lookup" we don't need a bit to tell us whether it is "direct lookup" Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++------------------ drivers/scsi/hpsa_cmd.h | 9 +++------ 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 298b2fe897c1c6..612d69938b50cb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3550,8 +3550,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, set_encrypt_ioaccel2(h, c, cp); cp->scsi_nexus = ioaccel_handle; - cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT; + cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; memcpy(cp->cdb, cdb, sizeof(cp->cdb)); /* fill in sg elements */ @@ -3986,9 +3985,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.tag = cpu_to_le64( - (u64) ((c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT)); + c->Header.tag = cpu_to_le64((u64) c->cmdindex << DIRECT_LOOKUP_SHIFT); /* Fill in the request block... */ @@ -4668,10 +4665,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); - c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT); - cmd_dma_handle = h->cmd_pool_dhandle - + i * sizeof(*c); + c->Header.tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); + cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(*c->err_info)); err_dma_handle = h->errinfo_pool_dhandle @@ -5399,11 +5394,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } -static inline u32 hpsa_tag_to_index(u32 tag) -{ - return tag >> DIRECT_LOOKUP_SHIFT; -} - static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) { @@ -5421,7 +5411,7 @@ static inline void process_indexed_cmd(struct ctlr_info *h, u32 tag_index; struct CommandList *c; - tag_index = hpsa_tag_to_index(raw_tag); + tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT; if (!bad_tag(h, tag_index, raw_tag)) { c = h->cmd_pool + tag_index; finish_cmd(c); @@ -7344,9 +7334,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT; cp->timeout_sec = 0; cp->ReplyQueue = 0; - cp->tag = - cpu_to_le64((u64) ((i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT)); + cp->tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); cp->host_addr = cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + (i * sizeof(struct io_accel1_cmd)))); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 037b10f773e97c..f7be8540985410 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -376,22 +376,19 @@ struct ErrorInfo { #define CMD_IOACCEL1 0x04 #define CMD_IOACCEL2 0x05 -#define DIRECT_LOOKUP_SHIFT 5 -#define DIRECT_LOOKUP_BIT 0x10 +#define DIRECT_LOOKUP_SHIFT 4 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) #define HPSA_ERROR_BIT 0x02 struct ctlr_info; /* defined in hpsa.h */ -/* The size of this structure needs to be divisible by 32 - * on all architectures because low 5 bits of the addresses +/* The size of this structure needs to be divisible by 128 + * on all architectures. The low 4 bits of the addresses * are used as follows: * * bit 0: to device, used to indicate "performant mode" command * from device, indidcates error status. * bit 1-3: to device, indicates block fetch table entry for * reducing DMA in fetching commands from host memory. - * bit 4: used to indicate whether tag is "direct lookup" (index), - * or a bus address. */ #define COMMANDLIST_ALIGNMENT 128 From ed52e87a3490ddfb58113fac2c640cdb7c28eeff Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:56 -0500 Subject: [PATCH 227/889] hpsa: fix race between abort handler and main i/o path This means changing the allocator to reference count commands. The reference count is now the authoritative indicator of whether a command is allocated or not. The h->cmd_pool_bits bitmap is now only a heuristic hint to speed up the allocation process, it is no longer the authoritative record of allocated commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 76 ++++++++++++++++++++++++----------------- drivers/scsi/hpsa.h | 2 ++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 612d69938b50cb..8ddc5cec5b5f3c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4548,6 +4548,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) char msg[256]; /* For debug messaging. */ int ml = 0; u32 tagupper, taglower; + int refcount; /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); @@ -4576,9 +4577,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* Get SCSI command to be aborted */ abort = (struct CommandList *) sc->host_scribble; if (abort == NULL) { - dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n", - msg); - return FAILED; + /* This can happen if the command already completed. */ + return SUCCESS; + } + refcount = atomic_inc_return(&abort->refcount); + if (refcount == 1) { /* Command is done already. */ + cmd_free(h, abort); + return SUCCESS; } hpsa_get_tag(h, abort, &taglower, &tagupper); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); @@ -4600,6 +4605,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + cmd_free(h, abort); return FAILED; } dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); @@ -4611,19 +4617,20 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ #define ABORT_COMPLETE_WAIT_SECS 30 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - if (test_bit(abort->cmdindex & (BITS_PER_LONG - 1), - h->cmd_pool_bits + - (abort->cmdindex / BITS_PER_LONG))) - msleep(100); - else + refcount = atomic_read(&abort->refcount); + if (refcount < 2) { + cmd_free(h, abort); return SUCCESS; + } else { + msleep(100); + } } dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", msg, ABORT_COMPLETE_WAIT_SECS); + cmd_free(h, abort); return FAILED; } - /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -4636,7 +4643,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - int loopcount; + int refcount; + unsigned long offset = 0; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -4649,23 +4657,27 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. */ - loopcount = 0; - do { - i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) - i = 0; - loopcount++; - } while (test_and_set_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && - loopcount < 10); - - /* Thread got starved? We do not expect this to ever happen. */ - if (loopcount >= 10 && i == h->nr_cmds) - return NULL; - - c = h->cmd_pool + i; - memset(c, 0, sizeof(*c)); - c->Header.tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); + for (;;) { + i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); + if (unlikely(i == h->nr_cmds)) { + offset = 0; + continue; + } + c = h->cmd_pool + i; + refcount = atomic_inc_return(&c->refcount); + if (unlikely(refcount > 1)) { + cmd_free(h, c); /* already in use */ + offset = (i + 1) % h->nr_cmds; + continue; + } + set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + break; /* it's ours now. */ + } + + /* Zero out all of commandlist except the last field, refcount */ + memset(c, 0, offsetof(struct CommandList, refcount)); + c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT)); cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(*c->err_info)); @@ -4685,11 +4697,13 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { - int i; + if (atomic_dec_and_test(&c->refcount)) { + int i; - i = c - h->cmd_pool; - clear_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)); + i = c - h->cmd_pool; + clear_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + } } #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index d00c29e9cad26d..4fd91436709fe6 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -297,6 +297,8 @@ struct offline_device_entry { */ #define SA5_DOORBELL 0x20 #define SA5_REQUEST_PORT_OFFSET 0x40 +#define SA5_REQUEST_PORT64_LO_OFFSET 0xC0 +#define SA5_REQUEST_PORT64_HI_OFFSET 0xC4 #define SA5_REPLY_INTR_MASK_OFFSET 0x34 #define SA5_REPLY_PORT_OFFSET 0x44 #define SA5_INTR_STATUS 0x30 diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index f7be8540985410..387a5aa6a360c3 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -405,6 +405,7 @@ struct CommandList { long cmdindex; struct completion *waiting; void *scsi_cmd; + atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); /* Max S/G elements in I/O accelerator command */ From eac8a68ccbcf4e25cb1d98e7c8fcbf5060fb6279 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:57 -0500 Subject: [PATCH 228/889] hpsa: do not request device rescan on every ioaccel path error The original reasoning behind doing this was faulty. An error of some sort would be encountered, accelerated i/o would be disabled for that logical drive, the command would be kicked back out to the SCSI midlayer for a retry, and since i/o accelerator mode was disabled, it would get retried down the RAID path. However, something needs to turn ioaccellerator mode back on, and this rescan request was what did that. However, it was racy, and extremely bad for performance to rescan all devices, so, don't do that. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 ++------------ drivers/scsi/hpsa.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8ddc5cec5b5f3c..8b27b61e544500 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1667,21 +1667,19 @@ static void process_ioaccel2_completion(struct ctlr_info *h, c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { dev->offload_enabled = 0; - h->drv_req_rescan = 1; /* schedule controller for a rescan */ cmd->result = DID_SOFT_ERROR << 16; cmd_free(h, c); cmd->scsi_done(cmd); return; } raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2); - /* If error found, disable Smart Path, schedule a rescan, - * and force a retry on the standard path. + /* If error found, disable Smart Path, + * force a retry on the standard path. */ if (raid_retry) { dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n", "HP SSD Smart Path"); dev->offload_enabled = 0; /* Disable Smart Path */ - h->drv_req_rescan = 1; /* schedule controller rescan */ cmd->result = DID_SOFT_ERROR << 16; } cmd_free(h, c); @@ -6689,9 +6687,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) int i; char *event_type; - /* Clear the driver-requested rescan flag */ - h->drv_req_rescan = 0; - /* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) && @@ -6737,9 +6732,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) */ static int hpsa_ctlr_needs_rescan(struct ctlr_info *h) { - if (h->drv_req_rescan) - return 1; - if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return 0; @@ -6785,7 +6777,6 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { scsi_host_get(h->scsi_host); - h->drv_req_rescan = 0; hpsa_ack_ctlr_events(h); hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); @@ -7031,7 +7022,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Enable Accelerated IO path at driver layer */ h->acciopath_status = 1; - h->drv_req_rescan = 0; h->lockup_detector_enabled = 1; /* Turn the interrupts on so we can service requests */ diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 4fd91436709fe6..43cd022d8673dd 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -236,7 +236,6 @@ struct ctlr_info { spinlock_t offline_device_lock; struct list_head offline_device_list; int acciopath_status; - int drv_req_rescan; /* flag for driver to request rescan event */ int raid_offload_debug; int lockup_detector_enabled; }; From b4f8452612a246edc1d870d98bb2f30e1ee80ff7 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:50:58 -0500 Subject: [PATCH 229/889] hpsa: factor out hpsa_ciss_submit function Factor out the bottom part of the queuecommand function which is the part that builds commands for submitting down the "normal' RAID stack path of a Smart Array. Need to factor this out to improve how commands that were initially sent down one of the "ioaccellerated" paths but which have some sort of error condition are retried down the "normal" path. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 124 +++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8b27b61e544500..f576e66a769902 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3919,68 +3919,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, dev->scsi3addr); } -/* Running in struct Scsi_Host->host_lock less mode */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +/* Submit commands down the "normal" RAID stack path */ +static int hpsa_ciss_submit(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd, + unsigned char scsi3addr[]) { - struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; - struct CommandList *c; - int rc = 0; - - /* Get the ptr to our adapter structure out of cmd->host. */ - h = sdev_to_hba(cmd->device); - dev = cmd->device->hostdata; - if (!dev) { - cmd->result = DID_NO_CONNECT << 16; - cmd->scsi_done(cmd); - return 0; - } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - - if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return 0; - } - c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* Fill in the command list header */ - /* save c in case we have to abort it */ cmd->host_scribble = (unsigned char *) c; - c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; - - /* Call alternate submit routine for I/O accelerated commands. - * Retries always go down the normal I/O path. - */ - if (likely(cmd->retries == 0 && - cmd->request->cmd_type == REQ_TYPE_FS && - h->acciopath_status)) { - if (dev->offload_enabled) { - rc = hpsa_scsi_ioaccel_raid_map(h, c); - if (rc == 0) - return 0; /* Sent on ioaccel path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } else if (dev->ioaccel_handle) { - rc = hpsa_scsi_ioaccel_direct_map(h, c); - if (rc == 0) - return 0; /* Sent on direct map path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } - } - c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); c->Header.tag = cpu_to_le64((u64) c->cmdindex << DIRECT_LOOKUP_SHIFT); @@ -4109,6 +4055,68 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } +/* Running in struct Scsi_Host->host_lock less mode */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct ctlr_info *h; + struct hpsa_scsi_dev_t *dev; + unsigned char scsi3addr[8]; + struct CommandList *c; + int rc = 0; + + /* Get the ptr to our adapter structure out of cmd->host. */ + h = sdev_to_hba(cmd->device); + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); + + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + return 0; + } + c = cmd_alloc(h); + if (c == NULL) { /* trouble... */ + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + + /* Call alternate submit routine for I/O accelerated commands. + * Retries always go down the normal I/O path. + */ + if (likely(cmd->retries == 0 && + cmd->request->cmd_type == REQ_TYPE_FS && + h->acciopath_status)) { + + cmd->host_scribble = (unsigned char *) c; + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + + if (dev->offload_enabled) { + rc = hpsa_scsi_ioaccel_raid_map(h, c); + if (rc == 0) + return 0; /* Sent on ioaccel path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } else if (dev->ioaccel_handle) { + rc = hpsa_scsi_ioaccel_direct_map(h, c); + if (rc == 0) + return 0; /* Sent on direct map path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + } + return hpsa_ciss_submit(h, c, cmd, scsi3addr); +} + static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) { unsigned long flags; From 9344f722c6555b4f51385aa2d4f3ab1723d6c365 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:50:58 -0500 Subject: [PATCH 230/889] hpsa: use workqueue to resubmit failed ioaccel commands Instead of kicking the commands all the way back to the mid layer, use a driver defined work queue. This enables having a mechanism for the driver to be able to resubmit the commands down the "normal" raid path without turning off the ioaccel feature entirely whenever an error is encountered on the ioaccel path, and prevent excessive rescanning of devices. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 69 +++++++++++++++++++++++++++++------------ drivers/scsi/hpsa_cmd.h | 1 + 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f576e66a769902..cfd76136d0d88f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -190,6 +190,7 @@ static struct board_type products[] = { }; static int number_of_controllers; +static struct workqueue_struct *hpsa_wq; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); @@ -246,6 +247,7 @@ static void hpsa_flush_cache(struct ctlr_info *h); static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, u8 *scsi3addr); +static void hpsa_command_resubmit_worker(struct work_struct *work); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -1649,7 +1651,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev) { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - int raid_retry = 0; /* check for good status */ if (likely(c2->error_data.serv_response == 0 && @@ -1666,24 +1667,22 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (is_logical_dev_addr_mode(dev->scsi3addr) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { - dev->offload_enabled = 0; - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - } - raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2); - /* If error found, disable Smart Path, - * force a retry on the standard path. - */ - if (raid_retry) { - dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n", - "HP SSD Smart Path"); - dev->offload_enabled = 0; /* Disable Smart Path */ - cmd->result = DID_SOFT_ERROR << 16; + if (c2->error_data.status == + IOACCEL2_STATUS_SR_IOACCEL_DISABLED) + dev->offload_enabled = 0; + goto retry_cmd; } + + if (handle_ioaccel_mode2_error(h, c, cmd, c2)) + goto retry_cmd; + cmd_free(h, c); cmd->scsi_done(cmd); + return; + +retry_cmd: + INIT_WORK(&c->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), hpsa_wq, &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1751,9 +1750,9 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, cp); - cmd->scsi_done(cmd); + INIT_WORK(&cp->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), + hpsa_wq, &cp->work); return; } } @@ -4055,6 +4054,31 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } +static void hpsa_command_resubmit_worker(struct work_struct *work) +{ + struct scsi_cmnd *cmd; + struct hpsa_scsi_dev_t *dev; + struct CommandList *c = + container_of(work, struct CommandList, work); + + cmd = c->scsi_cmd; + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return; + } + if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + /* + * If we get here, it means dma mapping failed. Try + * again via scsi mid layer, which will then get + * SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } +} + /* Running in struct Scsi_Host->host_lock less mode */ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { @@ -7544,12 +7568,19 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) */ static int __init hpsa_init(void) { + hpsa_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!hpsa_wq) { + pr_warn(HPSA "Failed to allocate work queue\n"); + return -ENOMEM; + } return pci_register_driver(&hpsa_pci_driver); } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); + if (hpsa_wq) + destroy_workqueue(hpsa_wq); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 387a5aa6a360c3..ba983440f75352 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -405,6 +405,7 @@ struct CommandList { long cmdindex; struct completion *waiting; void *scsi_cmd; + struct work_struct work; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 18b71338ff7bdfb98848fa9fe69cc19618e18c3b Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:50:59 -0500 Subject: [PATCH 231/889] hpsa: optimize cmd_alloc function by remembering last allocation Empirically, this improves performance slightly (~2% max IOPS) by allowing cmd_alloc to remember where it left off searching for free commands between calls instead of always starting its search at command 0. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +++- drivers/scsi/hpsa.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cfd76136d0d88f..67352f95037d57 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4674,7 +4674,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; int refcount; - unsigned long offset = 0; + unsigned long offset; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -4687,6 +4687,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. */ + offset = h->last_allocation; /* benighly racy */ for (;;) { i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); if (unlikely(i == h->nr_cmds)) { @@ -4704,6 +4705,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) h->cmd_pool_bits + (i / BITS_PER_LONG)); break; /* it's ours now. */ } + h->last_allocation = i; /* benignly racy */ /* Zero out all of commandlist except the last field, refcount */ memset(c, 0, offsetof(struct CommandList, refcount)); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 43cd022d8673dd..1f0a973530f8f8 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -120,6 +120,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_allocation; atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 From ef2ae3f68ee4b350970d7f0fc50f6512e4cdcd89 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:50:59 -0500 Subject: [PATCH 232/889] hpsa: hpsa performance optimization Count passthru cmds with atomics, not a spin locked int Do not use function pointers in fast path command submission Fix lockup detection to use reference counting Fix fail_all_outstanding_cmds to use reference counting Since we changed the command allocator to use reference counting as the authoritative indicator of whether a command is allocated, fail_all_outstanding_cmds needs to use the reference count not h->cmd_pool_bits for this purpose. Fix hpsa_drain_accel_commands to use the reference count as the authoritative indicator of whether a command is allocated instead of the h->cmd_pool_bits bitmap. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 75 +++++++++++++++------------------------------ drivers/scsi/hpsa.h | 16 ++++------ 2 files changed, 30 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 67352f95037d57..4cd517927145e4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -856,19 +856,21 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { + dial_down_lockup_detection_during_fw_flash(h, c); + atomic_inc(&h->commands_outstanding); switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); break; case CMD_IOACCEL2: set_ioaccel2_performant_mode(h, c); + writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; default: set_performant_mode(h, c); + h->access.submit_command(h, c); } - dial_down_lockup_detection_during_fw_flash(h, c); - atomic_inc(&h->commands_outstanding); - h->access.submit_command(h, c); } static inline int is_hba_lunid(unsigned char scsi3addr[]) @@ -5125,35 +5127,6 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, (void) check_for_unit_attention(h, c); } -static int increment_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return -1; - } - h->passthru_count++; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return 0; -} - -static void decrement_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count <= 0) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - /* not expecting to get here. */ - dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n"); - return; - } - h->passthru_count--; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); -} - /* * ioctl */ @@ -5176,16 +5149,16 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) case CCISS_GETDRIVVER: return hpsa_getdrivver_ioctl(h, argp); case CCISS_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; case CCISS_BIG_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_big_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; default: return -ENOTTY; @@ -6627,16 +6600,17 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) /* Called when controller lockup detected. */ static void fail_all_outstanding_cmds(struct ctlr_info *h) { - int i; - struct CommandList *c = NULL; + int i, refcount; + struct CommandList *c; for (i = 0; i < h->nr_cmds; i++) { - if (!test_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG))) - continue; c = h->cmd_pool + i; - c->err_info->CommandStatus = CMD_HARDWARE_ERR; - finish_cmd(c); + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) { + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + finish_cmd(c); + } + cmd_free(h, c); } } @@ -6673,9 +6647,7 @@ static void controller_lockup_detected(struct ctlr_info *h) dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", lockup_detected); pci_disable_device(h->pdev); - spin_lock_irqsave(&h->lock, flags); fail_all_outstanding_cmds(h); - spin_unlock_irqrestore(&h->lock, flags); } static void detect_controller_lockup(struct ctlr_info *h) @@ -6944,7 +6916,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->lock); spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); - spin_lock_init(&h->passthru_count_lock); + atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); @@ -7548,18 +7520,19 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) { struct CommandList *c = NULL; int i, accel_cmds_out; + int refcount; do { /* wait for all outstanding ioaccel commands to drain out */ accel_cmds_out = 0; for (i = 0; i < h->nr_cmds; i++) { - if (!test_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG))) - continue; c = h->cmd_pool + i; - accel_cmds_out += is_accelerated_cmd(c); + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) /* Command is allocated */ + accel_cmds_out += is_accelerated_cmd(c); + cmd_free(h, c); } if (accel_cmds_out <= 0) - break; + break; msleep(100); } while (1); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1f0a973530f8f8..1bda072d7f08c0 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -170,8 +170,7 @@ struct ctlr_info { /* cap concurrent passthrus at some reasonable maximum */ #define HPSA_MAX_CONCURRENT_PASSTHRUS (10) - spinlock_t passthru_count_lock; /* protects passthru_count */ - int passthru_count; + atomic_t passthru_cmds_avail; /* * Performant mode completion buffers @@ -355,10 +354,7 @@ static void SA5_submit_command_no_read(struct ctlr_info *h, static void SA5_submit_command_ioaccel2(struct ctlr_info *h, struct CommandList *c) { - if (c->cmd_type == CMD_IOACCEL2) - writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); - else - writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); } /* @@ -400,19 +396,19 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) unsigned long register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ - if (!(h->msi_vector || h->msix_vector)) { + if (unlikely(!(h->msi_vector || h->msix_vector))) { /* flush the controller write of the reply queue by reading * outbound doorbell status register. */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); /* Do a read in order to flush the write to the controller * (as per spec.) */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); } - if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { + if ((((u32) rq->head[rq->current_entry]) & 1) == rq->wraparound) { register_value = rq->head[rq->current_entry]; rq->current_entry++; atomic_dec(&h->commands_outstanding); From aa4ca0c7b0fca46731a51624f359cb789c53107c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:00 -0500 Subject: [PATCH 233/889] hpsa: remove unused fifo_full function Now that the passthru commands share the same command pool as the main i/o path, and the total size of the pool is less than or equal to the number of commands that will fit in the hardware fifo, there is no need to check to see if we are exceeding the hardware fifo's depth. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1bda072d7f08c0..2b5704f21cd45c 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -32,7 +32,6 @@ struct access_method { void (*submit_command)(struct ctlr_info *h, struct CommandList *c); void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); - unsigned long (*fifo_full)(struct ctlr_info *h); bool (*intr_pending)(struct ctlr_info *h); unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; @@ -423,14 +422,6 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) return register_value; } -/* - * Returns true if fifo is full. - * - */ -static unsigned long SA5_fifo_full(struct ctlr_info *h) -{ - return atomic_read(&h->commands_outstanding) >= h->max_commands; -} /* * returns value read from hardware. * returns FIFO_EMPTY if there is nothing to read @@ -520,7 +511,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) static struct access_method SA5_access = { SA5_submit_command, SA5_intr_mask, - SA5_fifo_full, SA5_intr_pending, SA5_completed, }; @@ -528,7 +518,6 @@ static struct access_method SA5_access = { static struct access_method SA5_ioaccel_mode1_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_ioaccel_mode1_intr_pending, SA5_ioaccel_mode1_completed, }; @@ -536,7 +525,6 @@ static struct access_method SA5_ioaccel_mode1_access = { static struct access_method SA5_ioaccel_mode2_access = { SA5_submit_command_ioaccel2, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -544,7 +532,6 @@ static struct access_method SA5_ioaccel_mode2_access = { static struct access_method SA5_performant_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -552,7 +539,6 @@ static struct access_method SA5_performant_access = { static struct access_method SA5_performant_access_no_read = { SA5_submit_command_no_read, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; From 81aee30b58e9e574ed4d85cfb319c88f89429408 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:00 -0500 Subject: [PATCH 234/889] hpsa: do not wait for aborted commands to complete after abort After an abort command completes successfully there is no need or sense in trying to wait for the aborted command to complete. It will have already completed (either normally, or as aborted) before the abort command completes. Trying to wait for it to complete later doesn't make sense -- it would only be waiting for the command to be re-used for something else and for *that* to complete, which would be crazy. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4cd517927145e4..1c89e11789255b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4572,7 +4572,7 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) { - int i, rc; + int rc; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; struct CommandList *abort; /* pointer to command to be aborted */ @@ -4641,26 +4641,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); - - /* If the abort(s) above completed and actually aborted the - * command, then the command to be aborted should already be - * completed. If not, wait around a bit more to see if they - * manage to complete normally. - */ -#define ABORT_COMPLETE_WAIT_SECS 30 - for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - refcount = atomic_read(&abort->refcount); - if (refcount < 2) { - cmd_free(h, abort); - return SUCCESS; - } else { - msleep(100); - } - } - dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", - msg, ABORT_COMPLETE_WAIT_SECS); cmd_free(h, abort); - return FAILED; + return SUCCESS; } /* From 5b0420d18b5c4b1a69194f6414f13f890a3d62af Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:01 -0500 Subject: [PATCH 235/889] hpsa: allow interrupt coalescing count and time to be adjusted in sysfs Note: Rob says that empirically, default values appear to be optimal, so it is not clear that allowing this to be adjusted is wise. We may wish to drop this patch. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 88 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1c89e11789255b..59457c69599bc0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -248,6 +248,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, u8 *scsi3addr); static void hpsa_command_resubmit_worker(struct work_struct *work); +static void print_cfg_table(struct device *dev, struct CfgTable *tb); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -402,6 +403,85 @@ static ssize_t host_store_rescan(struct device *dev, return count; } +static ssize_t host_store_hpsa_intcoal_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int len; + unsigned int value; + char tmpbuf[8]; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%u", &value) != 1) + return -EINVAL; + /* the device policies the values written, so no need here */ + + h = shost_to_hba(shost); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(value, &h->cfgtable->HostWrite.CoalIntDelay); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); + return count; +} + +static ssize_t host_store_hpsa_intcoal_count(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int len; + unsigned int value; + char tmpbuf[8]; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%u", &value) != 1) + return -EINVAL; + /* the device policies the values written, so no need here */ + + h = shost_to_hba(shost); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(value, &h->cfgtable->HostWrite.CoalIntCount); + print_cfg_table(&h->pdev->dev, h->cfgtable); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); + return count; +} + +static ssize_t host_show_hpsa_intcoal_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int value; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + value = readl(&h->cfgtable->HostWrite.CoalIntDelay); + return snprintf(buf, 20, "%u\n", value); +} + +static ssize_t host_show_hpsa_intcoal_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int value; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + value = readl(&h->cfgtable->HostWrite.CoalIntCount); + return snprintf(buf, 20, "%u\n", value); +} + + static ssize_t host_show_firmware_revision(struct device *dev, struct device_attribute *attr, char *buf) { @@ -660,6 +740,8 @@ static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL); static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static DEVICE_ATTR(hpsa_intcoal_delay, S_IWUSR|S_IRUGO, host_show_hpsa_intcoal_delay, host_store_hpsa_intcoal_delay); +static DEVICE_ATTR(hpsa_intcoal_count, S_IWUSR|S_IRUGO, host_show_hpsa_intcoal_count, host_store_hpsa_intcoal_count); static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO, host_show_hp_ssd_smart_path_enabled, NULL); static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH, @@ -691,6 +773,8 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_firmware_revision, &dev_attr_commands_outstanding, &dev_attr_transport_mode, + &dev_attr_hpsa_intcoal_delay, + &dev_attr_hpsa_intcoal_count, &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, @@ -5857,7 +5941,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) */ static void print_cfg_table(struct device *dev, struct CfgTable *tb) { -#ifdef HPSA_DEBUG int i; char temp_name[17]; @@ -5887,7 +5970,6 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb) dev_info(dev, " Server Name = %s\n", temp_name); dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat))); -#endif /* HPSA_DEBUG */ } static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) @@ -7281,6 +7363,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_warn(&h->pdev->dev, "unable to get board into" @@ -7356,6 +7439,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); hpsa_wait_for_mode_change_ack(h); + print_cfg_table(&h->pdev->dev, h->cfgtable); } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) From 883f1999058dda2c6df3708e371ea3e7c9536cfa Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:02 -0500 Subject: [PATCH 236/889] hpsa: fix race when updating raid map data. When enabling io accelerator paths for a logical drive make sure to update the raid map data prior to setting the ioaccel_enabled flag for that logical drive, and when disabling ioaccelerator path for a logical drive, do not update the raid map data at all. One of the reasons that the ioaccel_enabled flag might not be set is because getting the raid map data failed, in which case, updating the raid map data is certainly the wrong thing to do. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 59457c69599bc0..8a2400067cfff6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1086,12 +1086,22 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, /* Raid level changed. */ h->dev[entry]->raid_level = new_entry->raid_level; - /* Raid offload parameters changed. */ + /* Raid offload parameters changed. Careful about the ordering. */ + if (new_entry->offload_config && new_entry->offload_enabled) { + /* if drive is newly offload_enabled, we want to copy the + * raid map data first. If previously offload_enabled and + * offload_config were set, raid map data had better be + * the same as it was before. if raid map data is changed + * then it had better be the case that + * h->dev[entry]->offload_enabled is currently 0. + */ + h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; + wmb(); /* ensure raid map updated prior to ->offload_enabled */ + } h->dev[entry]->offload_config = new_entry->offload_config; - h->dev[entry]->offload_enabled = new_entry->offload_enabled; - h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; - h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->offload_enabled = new_entry->offload_enabled; dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", scsi_device_type(new_entry->devtype), hostno, new_entry->bus, From e4fc4a7b38a2edce0415bb452ed6a91687dff281 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:02 -0500 Subject: [PATCH 237/889] hpsa: allow commands to be completed on specified reply queue This is to enable fixing a race between command completions and abort completions on different reply queues in a subsequent patch. We want to be able to specify which reply queue an abort completion should occur on so that it cannot race the completion of the command it is trying to abort. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 54 +++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8a2400067cfff6..5d6d46151fdcb6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -863,25 +863,35 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) * set bit 0 for pull model, bits 3-1 for block fetch * register number */ -static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) +#define DEFAULT_REPLY_QUEUE (-1) +static void set_performant_mode(struct ctlr_info *h, struct CommandList *c, + int reply_queue) { if (likely(h->transMethod & CFGTBL_Trans_Performant)) { c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); - if (likely(h->msix_vector > 0)) + if (unlikely(!h->msix_vector)) + return; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) c->Header.ReplyQueue = raw_smp_processor_id() % h->nreply_queues; + else + c->Header.ReplyQueue = reply_queue % h->nreply_queues; } } static void set_ioaccel1_performant_mode(struct ctlr_info *h, - struct CommandList *c) + struct CommandList *c, + int reply_queue) { struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex]; /* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - cp->ReplyQueue = smp_processor_id() % h->nreply_queues; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->ReplyQueue = smp_processor_id() % h->nreply_queues; + else + cp->ReplyQueue = reply_queue % h->nreply_queues; /* Set the bits in the address sent down to include: * - performant mode bit (bit 0) * - pull count (bits 1-3) @@ -892,14 +902,18 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h, } static void set_ioaccel2_performant_mode(struct ctlr_info *h, - struct CommandList *c) + struct CommandList *c, + int reply_queue) { struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex]; /* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - cp->reply_queue = smp_processor_id() % h->nreply_queues; + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->reply_queue = smp_processor_id() % h->nreply_queues; + else + cp->reply_queue = reply_queue % h->nreply_queues; /* Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 * - pull count (bits 0-3) @@ -937,26 +951,32 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; } -static void enqueue_cmd_and_start_io(struct ctlr_info *h, - struct CommandList *c) +static void __enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c, int reply_queue) { dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); switch (c->cmd_type) { case CMD_IOACCEL1: - set_ioaccel1_performant_mode(h, c); + set_ioaccel1_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); break; case CMD_IOACCEL2: - set_ioaccel2_performant_mode(h, c); + set_ioaccel2_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; default: - set_performant_mode(h, c); + set_performant_mode(h, c, reply_queue); h->access.submit_command(h, c); } } +static void enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c) +{ + __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); +} + static inline int is_hba_lunid(unsigned char scsi3addr[]) { return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0; @@ -2013,16 +2033,22 @@ static int hpsa_map_one(struct pci_dev *pdev, return 0; } -static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c) +static inline void __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, int reply_queue) { DECLARE_COMPLETION_ONSTACK(wait); c->waiting = &wait; - enqueue_cmd_and_start_io(h, c); + __enqueue_cmd_and_start_io(h, c, reply_queue); wait_for_completion(&wait); } +static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c) +{ + __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE); +} + static u32 lockup_detected(struct ctlr_info *h) { int cpu; From 11a7e51cf7da187a79ab306e58428f039e6f537d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:03 -0500 Subject: [PATCH 238/889] hpsa: fix completion race in abort handler The following race was possible in theory: 1. Abort command is sent to hardware. 2. Command to be aborted simultaneously completes on another reply queue. 3. Hardware receives abort command, decides command has already completed and indicates this to the driver via another different reply queue. 4. driver processes abort completion finds that the hardware does not know about the command, concludes that therefore the command cannot complete, returns SUCCESS indicating to the mid-layer that the scsi_cmnd may be re-used. 5. Command from step 2 is processed and completed back to scsi mid layer (after we already promised that would never happen.) Fix by forcing aborts to complete on the same reply queue as the command they are aborting. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5d6d46151fdcb6..489851fe3eef59 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4543,7 +4543,7 @@ static void hpsa_get_tag(struct ctlr_info *h, } static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, - struct CommandList *abort, int swizzle) + struct CommandList *abort, int swizzle, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -4561,7 +4561,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); - hpsa_scsi_do_simple_cmd_core(h, c); + __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", __func__, tagupper, taglower); @@ -4595,7 +4595,8 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, */ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort) + unsigned char *scsi3addr, struct CommandList *abort, + __attribute__((unused)) int reply_queue) { int rc = IO_OK; struct scsi_cmnd *scmd; /* scsi command within request being aborted */ @@ -4671,7 +4672,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, * make this true someday become false. */ static int hpsa_send_abort_both_ways(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort) + unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, @@ -4679,10 +4680,20 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, * Change abort to physical device reset. */ if (abort->cmd_type == CMD_IOACCEL2) - return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort); + return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, + abort, reply_queue); + + return hpsa_send_abort(h, scsi3addr, abort, 0, reply_queue) && + hpsa_send_abort(h, scsi3addr, abort, 1, reply_queue); +} - return hpsa_send_abort(h, scsi3addr, abort, 0) && - hpsa_send_abort(h, scsi3addr, abort, 1); +/* Find out which reply queue a command was meant to return on */ +static int hpsa_extract_reply_queue(struct ctlr_info *h, + struct CommandList *c) +{ + if (c->cmd_type == CMD_IOACCEL2) + return h->ioaccel2_cmd_pool[c->cmdindex].reply_queue; + return c->Header.ReplyQueue; } /* Send an abort for the specified command. @@ -4700,7 +4711,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) char msg[256]; /* For debug messaging. */ int ml = 0; u32 tagupper, taglower; - int refcount; + int refcount, reply_queue; /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); @@ -4738,6 +4749,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } hpsa_get_tag(h, abort, &taglower, &tagupper); + reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); as = (struct scsi_cmnd *) abort->scsi_cmd; if (as != NULL) @@ -4751,7 +4763,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * by the firmware (but not to the scsi mid layer) but we can't * distinguish which. Send the abort down. */ - rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort); + rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); if (rc != 0) { dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", From 992830d296c77f9c435d4a6f20944daaf10f6fdf Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:03 -0500 Subject: [PATCH 239/889] hpsa: fix aborting of reused commands The following race was possible in theory. 1. LLD is requested to abort a scsi command 2. scsi command completes 3. The struct CommandList associated with 2 is made available. 4. new io request to LLD to another LUN re-uses struct CommandList 5. abort handler follows scsi_cmnd->host_scribble and finds struct CommandList and tries to aborts it. Now we have aborted the wrong command. Fix by zeroing the scsi_cmd field of struct CommandList upon completion and making the abort handler check that the scsi_cmd pointer in the CommadList struct matches the scsi_cmnd that it has been asked to abort. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 489851fe3eef59..5b1bd8c10b0553 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1989,6 +1989,21 @@ static void complete_scsi_command(struct CommandList *cp) dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n", cp, ei->CommandStatus); } + + /* Prevent the following race in the abort handler: + * + * 1. LLD is requested to abort a scsi command + * 2. scsi command completes + * 3. The struct CommandList associated with 2 is made available. + * 4. new io request to LLD to another LUN re-uses struct CommandList + * 5. abort handler follows scsi_cmnd->host_scribble and + * finds struct CommandList and tries to aborts it. + * Now we have aborted the wrong command. + * Clear cp->scsi_cmd here so that if this get re-used, the abort + * handler will know it's a different scsi_cmnd. + */ + cp->scsi_cmd = NULL; + cmd_free(h, cp); cmd->scsi_done(cmd); } @@ -4748,6 +4763,15 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return SUCCESS; } + + /* Check that we're aborting the right command. + * It's possible the CommandList already completed and got re-used. + */ + if (abort->scsi_cmd != sc) { + cmd_free(h, abort); + return SUCCESS; + } + hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); From a8118af8cb9e906620b98f50426a38cbf4c3edf3 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:04 -0500 Subject: [PATCH 240/889] hpsa: lay groundwork for handling driver initiated command timeouts Allow driver initiated commands to have a timeout. It does not yet try to do anything with timeouts on such commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 118 ++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5b1bd8c10b0553..9327e0d1a916c3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2048,20 +2048,33 @@ static int hpsa_map_one(struct pci_dev *pdev, return 0; } -static inline void __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c, int reply_queue) +#define NO_TIMEOUT ((unsigned long) -1) +#define DEFAULT_TIMEOUT (30000) /* milliseconds */ +static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, int reply_queue, unsigned long timeout_msecs) { DECLARE_COMPLETION_ONSTACK(wait); c->waiting = &wait; __enqueue_cmd_and_start_io(h, c, reply_queue); - wait_for_completion(&wait); + if (timeout_msecs == NO_TIMEOUT) { + /* TODO: get rid of this no-timeout thing */ + wait_for_completion_io(&wait); + return 0; + } + if (!wait_for_completion_io_timeout(&wait, + msecs_to_jiffies(timeout_msecs))) { + dev_warn(&h->pdev->dev, "Command timed out.\n"); + return -ETIMEDOUT; + } + return 0; } -static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c) +static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, + struct CommandList *c, unsigned long timeout_msecs) { - __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE); + return __hpsa_scsi_do_simple_cmd_core(h, c, + DEFAULT_REPLY_QUEUE, timeout_msecs); } static u32 lockup_detected(struct ctlr_info *h) @@ -2076,25 +2089,29 @@ static u32 lockup_detected(struct ctlr_info *h) return rc; } -static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, - struct CommandList *c) +static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, + struct CommandList *c, unsigned long timeout_msecs) { /* If controller lockup detected, fake a hardware error. */ - if (unlikely(lockup_detected(h))) + if (unlikely(lockup_detected(h))) { c->err_info->CommandStatus = CMD_HARDWARE_ERR; - else - hpsa_scsi_do_simple_cmd_core(h, c); + return 0; + } + return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); } #define MAX_DRIVER_CMD_RETRIES 25 -static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, - struct CommandList *c, int data_direction) +static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, + struct CommandList *c, int data_direction, unsigned long timeout_msecs) { int backoff_time = 10, retry_count = 0; + int rc; do { memset(c->err_info, 0, sizeof(*c->err_info)); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); + if (rc) + break; retry_count++; if (retry_count > 3) { msleep(backoff_time); @@ -2105,6 +2122,9 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, check_for_busy(h, c)) && retry_count <= MAX_DRIVER_CMD_RETRIES); hpsa_pci_unmap(h->pdev, c, 1, data_direction); + if (retry_count > MAX_DRIVER_CMD_RETRIES) + rc = -1; /* FIXME do something better? */ + return rc; } static void hpsa_print_cmd(struct ctlr_info *h, char *txt, @@ -2208,7 +2228,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); @@ -2239,7 +2262,10 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, rc = -1; goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); @@ -2267,7 +2293,11 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) { + dev_warn(&h->pdev->dev, "Failed to send reset command\n"); + goto out; + } /* no unmap needed here because no data xfer. */ ei = c->err_info; @@ -2275,6 +2305,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, hpsa_scsi_interpret_error(h, c); rc = -1; } +out: cmd_free(h, c); return rc; } @@ -2394,15 +2425,18 @@ static int hpsa_get_raid_map(struct ctlr_info *h, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - cmd_free(h, c); - return -ENOMEM; + rc = -ENOMEM; + goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); - cmd_free(h, c); - return -1; + rc = -1; + goto out; } cmd_free(h, c); @@ -2414,6 +2448,9 @@ static int hpsa_get_raid_map(struct ctlr_info *h, } hpsa_debug_map_buff(h, rc, &this_device->raid_map); return rc; +out: + cmd_free(h, c); + return rc; } static int hpsa_bmic_id_physical_device(struct ctlr_info *h, @@ -2567,7 +2604,10 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } if (extended_response) c->Request.CDB[1] = extended_response; - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { @@ -2658,7 +2698,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, { struct CommandList *c; unsigned char *sense, sense_key, asc, ascq; - int ldstat = 0; + int rc, ldstat = 0; u16 cmd_status; u8 scsi_status; #define ASC_LUN_NOT_READY 0x04 @@ -2669,7 +2709,11 @@ static int hpsa_volume_offline(struct ctlr_info *h, if (!c) return 0; (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) { + cmd_free(h, c); + return 0; + } sense = c->err_info->SenseInfo; sense_key = sense[2]; asc = sense[12]; @@ -4464,7 +4508,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_core(h, c); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + if (rc) + goto do_it_again; /* no unmap needed here because no data xfer. */ if (c->err_info->CommandStatus == CMD_SUCCESS) @@ -4475,7 +4521,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, (c->err_info->SenseInfo[2] == NO_SENSE || c->err_info->SenseInfo[2] == UNIT_ATTENTION)) break; - +do_it_again: dev_warn(&h->pdev->dev, "waiting %d secs " "for device to become ready.\n", waittime); rc = 1; /* device not ready. */ @@ -4576,7 +4622,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); - __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue); + (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", __func__, tagupper, taglower); @@ -5091,7 +5137,9 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); + rc = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + if (rc) + rc = -EIO; if (iocommand.buf_size > 0) hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -5222,7 +5270,11 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); + status = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + if (status) { + status = -EIO; + goto cleanup0; + } if (sg_used) hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -7196,6 +7248,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) { char *flush_buf; struct CommandList *c; + int rc; /* Don't bother trying to flush the cache if locked up */ if (unlikely(lockup_detected(h))) @@ -7213,7 +7266,10 @@ static void hpsa_flush_cache(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) { goto out; } - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_TODEVICE); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_TODEVICE, NO_TIMEOUT); + if (rc) + goto out; if (c->err_info->CommandStatus != 0) out: dev_warn(&h->pdev->dev, From 5d38124b2948c9353a2b51c0a46a23d19430bff8 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:04 -0500 Subject: [PATCH 241/889] hpsa: do not send aborts to logical devices that do not support aborts Instead of relying on what the Smart Array claims for supporting logical drives, simply try an abort and see how it responds at device discovery time. This way devices that do support aborts (e.g. MSA2000) can work and we do not waste time trying to send aborts to logical drives that do not support them (important for high IOPS devices.) Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 67 ++++++++++++++++++++++++++++++++++++++++----- drivers/scsi/hpsa.h | 2 +- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9327e0d1a916c3..e6fe49d345b916 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2757,6 +2757,49 @@ static int hpsa_volume_offline(struct ctlr_info *h, return 0; } +/* Find out if a logical device supports aborts by simply trying one. + * Smart Array may claim not to support aborts on logical drives, but + * if a MSA2000 * is connected, the drives on that will be presented + * by the Smart Array as logical drives, and aborts may be sent to + * those devices successfully. So the simplest way to find out is + * to simply try an abort and see how the device responds. + */ +static int hpsa_device_supports_aborts(struct ctlr_info *h, + unsigned char *scsi3addr) +{ + struct CommandList *c; + struct ErrorInfo *ei; + int rc = 0; + + u64 tag = (u64) -1; /* bogus tag */ + + /* Assume that physical devices support aborts */ + if (!is_logical_dev_addr_mode(scsi3addr)) + return 1; + + c = cmd_alloc(h); + if (!c) + return -ENOMEM; + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); + (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); + /* no unmap needed here because no data xfer. */ + ei = c->err_info; + switch (ei->CommandStatus) { + case CMD_INVALID: + rc = 0; + break; + case CMD_UNABORTABLE: + case CMD_ABORT_FAILED: + rc = 1; + break; + default: + rc = 0; + break; + } + cmd_free(h, c); + return rc; +} + static int hpsa_update_device_info(struct ctlr_info *h, unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, unsigned char *is_OBDR_device) @@ -2821,8 +2864,11 @@ static int hpsa_update_device_info(struct ctlr_info *h, strncmp(obdr_sig, OBDR_TAPE_SIG, OBDR_SIG_LEN) == 0); } - kfree(inq_buff); + this_device->supports_aborts = + hpsa_device_supports_aborts(h, scsi3addr); + if (this_device->supports_aborts < 0) + this_device->supports_aborts = 0; return 0; bail_out: @@ -4618,7 +4664,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, } /* fill_cmd can't fail here, no buffer to map */ - (void) fill_cmd(c, HPSA_ABORT_MSG, h, abort, + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, 0, 0, scsi3addr, TYPE_MSG); if (swizzle) swizzle_abort_tag(&c->Request.CDB[4]); @@ -4810,6 +4856,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } + /* Don't bother trying the abort if we know it won't work. */ + if (abort->cmd_type != CMD_IOACCEL2 && + abort->cmd_type != CMD_IOACCEL1 && !dev->supports_aborts) { + cmd_free(h, abort); + return FAILED; + } + /* Check that we're aborting the right command. * It's possible the CommandList already completed and got re-used. */ @@ -5381,7 +5434,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, int cmd_type) { int pci_dir = XFER_NONE; - struct CommandList *a; /* for commands to be aborted */ + u64 tag; /* for commands to be aborted */ u32 tupper, tlower; c->cmd_type = CMD_IOCTL_PEND; @@ -5498,11 +5551,11 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = 0x00; break; case HPSA_ABORT_MSG: - a = buff; /* point to command to be aborted */ + memcpy(&tag, buff, sizeof(tag)); dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx", - a->Header.tag, c->Header.tag); - tlower = (u32) (a->Header.tag >> 32); - tupper = (u32) (a->Header.tag & 0x0ffffffffULL); + tag, c->Header.tag); + tlower = (u32) (tag >> 32); + tupper = (u32) (tag & 0x0ffffffffULL); c->Request.CDBLen = 16; c->Request.type_attr_dir = TYPE_ATTR_DIR(cmd_type, diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 2b5704f21cd45c..03a28dc6e54337 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -53,7 +53,7 @@ struct hpsa_scsi_dev_t { * offload request to mirror drive */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ - + int supports_aborts; }; struct reply_queue_buffer { From 3e92bd5ae224991a31f08986b6eccebc5edbd9e7 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:05 -0500 Subject: [PATCH 242/889] hpsa: remember whether devices support aborts across rescans While rescanning devices only test whether devices support aborts the first time we encounter a device rather than every time. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e6fe49d345b916..02d1b0e4845b81 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2812,6 +2812,8 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; + unsigned long flags; + int rc, entry; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) @@ -2865,10 +2867,25 @@ static int hpsa_update_device_info(struct ctlr_info *h, OBDR_SIG_LEN) == 0); } kfree(inq_buff); - this_device->supports_aborts = - hpsa_device_supports_aborts(h, scsi3addr); - if (this_device->supports_aborts < 0) - this_device->supports_aborts = 0; + + /* + * See if this device supports aborts. If we already know + * the device, we already know if it supports aborts, otherwise + * we have to find out if it supports aborts by trying one. + */ + spin_lock_irqsave(&h->devlock, flags); + rc = hpsa_scsi_find_entry(this_device, h->dev, h->ndevices, &entry); + if ((rc == DEVICE_SAME || rc == DEVICE_UPDATED) && + entry >= 0 && entry < h->ndevices) { + this_device->supports_aborts = h->dev[entry]->supports_aborts; + spin_unlock_irqrestore(&h->devlock, flags); + } else { + spin_unlock_irqrestore(&h->devlock, flags); + this_device->supports_aborts = + hpsa_device_supports_aborts(h, scsi3addr); + if (this_device->supports_aborts < 0) + this_device->supports_aborts = 0; + } return 0; bail_out: From 27ed6bee50f0e28978c2c7734a3559a5973ae8cc Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:06 -0500 Subject: [PATCH 243/889] hpsa: do not send two aborts with swizzled tags. Some Smart Arrays required aborts to be sent with tags in the wrong endian byte order. To avoid having to know about this, we would send two aborts with tags with each endian order. On high IOPS devices, this turns out to be not such a hot idea. So we now have a list of the devices that got the tag backwards, and we only send it one way. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 52 ++++++++++++++++++++++++++------------------- drivers/scsi/hpsa.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 02d1b0e4845b81..428d01898f4f5e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -575,24 +575,31 @@ static u32 soft_unresettable_controller[] = { 0x409D0E11, /* Smart Array 6400 EM */ }; -static int ctlr_is_hard_resettable(u32 board_id) +static u32 needs_abort_tags_swizzled[] = { + 0x324a103C, /* Smart Array P712m */ + 0x324b103C, /* SmartArray P711m */ +}; + +static int board_id_in_array(u32 a[], int nelems, u32 board_id) { int i; - for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) - if (unresettable_controller[i] == board_id) - return 0; - return 1; + for (i = 0; i < nelems; i++) + if (a[i] == board_id) + return 1; + return 0; } -static int ctlr_is_soft_resettable(u32 board_id) +static int ctlr_is_hard_resettable(u32 board_id) { - int i; + return !board_id_in_array(unresettable_controller, + ARRAY_SIZE(unresettable_controller), board_id); +} - for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++) - if (soft_unresettable_controller[i] == board_id) - return 0; - return 1; +static int ctlr_is_soft_resettable(u32 board_id) +{ + return !board_id_in_array(soft_unresettable_controller, + ARRAY_SIZE(soft_unresettable_controller), board_id); } static int ctlr_is_resettable(u32 board_id) @@ -601,6 +608,12 @@ static int ctlr_is_resettable(u32 board_id) ctlr_is_soft_resettable(board_id); } +static int ctlr_needs_abort_tags_swizzled(u32 board_id) +{ + return board_id_in_array(needs_abort_tags_swizzled, + ARRAY_SIZE(needs_abort_tags_swizzled), board_id); +} + static ssize_t host_show_resettable(struct device *dev, struct device_attribute *attr, char *buf) { @@ -4667,7 +4680,7 @@ static void hpsa_get_tag(struct ctlr_info *h, } static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, - struct CommandList *abort, int swizzle, int reply_queue) + struct CommandList *abort, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -4683,7 +4696,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, /* fill_cmd can't fail here, no buffer to map */ (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, 0, 0, scsi3addr, TYPE_MSG); - if (swizzle) + if (h->needs_abort_tags_swizzled) swizzle_abort_tag(&c->Request.CDB[4]); (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); @@ -4789,12 +4802,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, return rc; /* success */ } -/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to - * tell which kind we're dealing with, so we send the abort both ways. There - * shouldn't be any collisions between swizzled and unswizzled tags due to the - * way we construct our tags but we check anyway in case the assumptions which - * make this true someday become false. - */ static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { @@ -4806,9 +4813,7 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, if (abort->cmd_type == CMD_IOACCEL2) return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort, reply_queue); - - return hpsa_send_abort(h, scsi3addr, abort, 0, reply_queue) && - hpsa_send_abort(h, scsi3addr, abort, 1, reply_queue); + return hpsa_send_abort(h, scsi3addr, abort, reply_queue); } /* Find out which reply queue a command was meant to return on */ @@ -6545,6 +6550,9 @@ static int hpsa_pci_init(struct ctlr_info *h) h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); + h->needs_abort_tags_swizzled = + ctlr_needs_abort_tags_swizzled(h->board_id); + pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 03a28dc6e54337..283b7891c9d4a3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -237,6 +237,7 @@ struct ctlr_info { int acciopath_status; int raid_offload_debug; int lockup_detector_enabled; + int needs_abort_tags_swizzled; }; struct offline_device_entry { From 6f690537c5f70778ee09621498705220ac302d80 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:06 -0500 Subject: [PATCH 244/889] hpsa: decrement h->commands_outstanding in fail_all_outstanding_cmds Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 428d01898f4f5e..0948d164b207b7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6875,6 +6875,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) if (refcount > 1) { c->err_info->CommandStatus = CMD_HARDWARE_ERR; finish_cmd(c); + atomic_dec(&h->commands_outstanding); } cmd_free(h, c); } From b90182452ff778117497ef6b674f04c70f1efdf7 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:07 -0500 Subject: [PATCH 245/889] hpsa: flush work queue hpsa_wq in fail_all_outstanding_cmds This is so that fail_all_outstanding_cmds will not call finish_cmd() to operate on a partially constructed command. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0948d164b207b7..9ee1705f7e9508 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6869,6 +6869,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) int i, refcount; struct CommandList *c; + flush_workqueue(hpsa_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); From 4ef6f5c33c433884da7db3829e895271def67d31 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:07 -0500 Subject: [PATCH 246/889] hpsa: use per controller not per driver work queue for command resubmission This is so that the fail_all_outstanding_cmds() does not get stuck waiting for work items on other controllers when flushing the work queue. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ++++++++++++------------ drivers/scsi/hpsa.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9ee1705f7e9508..24762868e76d35 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -190,7 +190,6 @@ static struct board_type products[] = { }; static int number_of_controllers; -static struct workqueue_struct *hpsa_wq; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); @@ -1811,7 +1810,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, retry_cmd: INIT_WORK(&c->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), hpsa_wq, &c->work); + queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1881,7 +1880,7 @@ static void complete_scsi_command(struct CommandList *cp) dev->offload_enabled = 0; INIT_WORK(&cp->work, hpsa_command_resubmit_worker); queue_work_on(raw_smp_processor_id(), - hpsa_wq, &cp->work); + h->resubmit_wq, &cp->work); return; } } @@ -6869,7 +6868,7 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) int i, refcount; struct CommandList *c; - flush_workqueue(hpsa_wq); /* ensure all cmds are fully built */ + flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); @@ -7186,6 +7185,12 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); + h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!h->resubmit_wq) { + dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); + rc = -ENOMEM; + goto clean1; + } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { @@ -7318,6 +7323,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) free_irqs(h); clean2: clean1: + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); if (h->lockup_detected) free_percpu(h->lockup_detected); kfree(h); @@ -7397,9 +7404,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) h->remove_in_progress = 1; cancel_delayed_work(&h->monitor_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); - hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); + destroy_workqueue(h->resubmit_wq); iounmap(h->vaddr); iounmap(h->transtable); iounmap(h->cfgtable); @@ -7817,19 +7824,12 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) */ static int __init hpsa_init(void) { - hpsa_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); - if (!hpsa_wq) { - pr_warn(HPSA "Failed to allocate work queue\n"); - return -ENOMEM; - } return pci_register_driver(&hpsa_pci_driver); } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); - if (hpsa_wq) - destroy_workqueue(hpsa_wq); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 283b7891c9d4a3..978c23fcbcf5fc 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -238,6 +238,7 @@ struct ctlr_info { int raid_offload_debug; int lockup_detector_enabled; int needs_abort_tags_swizzled; + struct workqueue_struct *resubmit_wq; }; struct offline_device_entry { From 3dc75043e0df40ec83a5b79f9d4575e04e5ca115 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:08 -0500 Subject: [PATCH 247/889] hpsa: always use extended report physical LUNs for physical devices The extended report physical luns gives information that is needed for ioaccellerator modes, but there's no sense in doing it two different ways unnecessarily. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 48 +++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 24762868e76d35..341146e02a9781 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2594,7 +2594,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, } static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, - struct ReportLUNdata *buf, int bufsize, + void *buf, int bufsize, int extended_response) { int rc = IO_OK; @@ -2626,11 +2626,12 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, hpsa_scsi_interpret_error(h, c); rc = -1; } else { - if (buf->extended_response_flag != extended_response) { + struct ReportLUNdata *rld = buf; + if (rld->extended_response_flag != extended_response) { dev_err(&h->pdev->dev, "report luns requested format %u, got %u\n", extended_response, - buf->extended_response_flag); + rld->extended_response_flag); rc = -1; } } @@ -2640,10 +2641,10 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, - struct ReportLUNdata *buf, - int bufsize, int extended_response) + struct ReportExtendedLUNdata *buf, int bufsize) { - return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response); + return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, + HPSA_REPORT_PHYS_EXTENDED); } static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h, @@ -3027,7 +3028,6 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, { struct ReportExtendedLUNdata *physicals = NULL; int responsesize = 24; /* size of physical extended response */ - int extended = 2; /* flag forces reporting 'other dev info'. */ int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize; u32 nphysicals = 0; /* number of reported physical devs */ int found = 0; /* found match (1) or not (0) */ @@ -3074,8 +3074,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, physicals = kzalloc(reportsize, GFP_KERNEL); if (physicals == NULL) return 0; - if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals, - reportsize, extended)) { + if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) { dev_err(&h->pdev->dev, "Can't lookup %s device handle: report physical LUNs failed.\n", "HP SSD Smart Path"); @@ -3116,34 +3115,21 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, * Returns 0 on success, -1 otherwise. */ static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportphyslunsize, int reportloglunsize, - struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode, + struct ReportExtendedLUNdata *physdev, u32 *nphysicals, struct ReportLUNdata *logdev, u32 *nlogicals) { - int physical_entry_size = 8; - - *physical_mode = 0; - - /* For I/O accelerator mode we need to read physical device handles */ - if (h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2) { - *physical_mode = HPSA_REPORT_PHYS_EXTENDED; - physical_entry_size = 24; - } - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize, - *physical_mode)) { + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; } - *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / - physical_entry_size; + *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24; if (*nphysicals > HPSA_MAX_PHYS_LUN) { dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded." " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, *nphysicals - HPSA_MAX_PHYS_LUN); *nphysicals = HPSA_MAX_PHYS_LUN; } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) { + if (hpsa_scsi_do_report_log_luns(h, logdev, sizeof(*logdev))) { dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } @@ -3232,7 +3218,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) struct ReportLUNdata *logdev_list = NULL; u32 nphysicals = 0; u32 nlogicals = 0; - int physical_mode = 0; u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; @@ -3263,10 +3248,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, - sizeof(*physdev_list), sizeof(*logdev_list), - (struct ReportLUNdata *) physdev_list, &nphysicals, - &physical_mode, logdev_list, &nlogicals)) + if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, + logdev_list, &nlogicals)) goto out; /* We might see up to the maximum number of logical and physical disks @@ -3363,7 +3346,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; } - if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) { + if (h->transMethod & CFGTBL_Trans_io_accel1 || + h->transMethod & CFGTBL_Trans_io_accel2) { memcpy(&this_device->ioaccel_handle, &lunaddrbytes[20], sizeof(this_device->ioaccel_handle)); From 5d757aa2479816387b664bf7b6b0ba2f0a8ef5b4 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:08 -0500 Subject: [PATCH 248/889] hpsa: add masked physical devices into h->dev[] array This is so that we can store the ioaccel handle for those devices so that when we need to abort commands sent down ioaccel2 path, we can look up the 8-byte LUN ID in h->dev[] instead of having to do i/o to the controller each time. We add an expose_state field to h->dev[] elements to indicate how the device is exposed to the scsi mid layer: Not at all, without an upper level driver (no_uld_attach) or normally exposed. Since masked physical devices are now present in h->dev[] array it is perfectly possible to do echo scsi add-single-device 2 2 0 0 > /proc/scsi/scsi and bring them online. This should not be the case for masked physical devices.. Change the values for the expose_status field of hpsa_scsi_dev_t to make sense. HPSA_DO_NOT_EXPOSE 0x0 HPSA_SG_ATTACH 0x1 HPSA_ULD_ATTACH 0x2 HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 82 +++++++++++++++++++++++++++++++---------- drivers/scsi/hpsa.h | 5 +++ drivers/scsi/hpsa_cmd.h | 3 ++ 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 341146e02a9781..09c68d58407bf6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -217,6 +217,7 @@ static int hpsa_change_queue_type(struct scsi_device *sdev, int type); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); static int hpsa_slave_alloc(struct scsi_device *sdev); +static int hpsa_slave_configure(struct scsi_device *sdev); static void hpsa_slave_destroy(struct scsi_device *sdev); static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); @@ -809,6 +810,7 @@ static struct scsi_host_template hpsa_driver_template = { .eh_device_reset_handler = hpsa_eh_device_reset_handler, .ioctl = hpsa_ioctl, .slave_alloc = hpsa_slave_alloc, + .slave_configure = hpsa_slave_configure, .slave_destroy = hpsa_slave_destroy, #ifdef CONFIG_COMPAT .compat_ioctl = hpsa_compat_ioctl, @@ -1521,20 +1523,23 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, sh = h->scsi_host; /* Notify scsi mid layer of any removed devices */ for (i = 0; i < nremoved; i++) { - struct scsi_device *sdev = - scsi_device_lookup(sh, removed[i]->bus, - removed[i]->target, removed[i]->lun); - if (sdev != NULL) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* We don't expect to get here. - * future cmds to this device will get selection - * timeout as if the device was gone. - */ - dev_warn(&h->pdev->dev, "didn't find c%db%dt%dl%d " - " for removal.", hostno, removed[i]->bus, - removed[i]->target, removed[i]->lun); + if (removed[i]->expose_state & HPSA_SCSI_ADD) { + struct scsi_device *sdev = + scsi_device_lookup(sh, removed[i]->bus, + removed[i]->target, removed[i]->lun); + if (sdev != NULL) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* We don't expect to get here. + * future cmds to this device will get selection + * timeout as if the device was gone. + */ + dev_warn(&h->pdev->dev, + "didn't find c%db%dt%dl%d for removal.", + hostno, removed[i]->bus, + removed[i]->target, removed[i]->lun); + } } kfree(removed[i]); removed[i] = NULL; @@ -1542,6 +1547,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* Notify scsi mid layer of any added devices */ for (i = 0; i < nadded; i++) { + if (!(added[i]->expose_state & HPSA_SCSI_ADD)) + continue; if (scsi_add_device(sh, added[i]->bus, added[i]->target, added[i]->lun) == 0) continue; @@ -1588,8 +1595,27 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(&h->devlock, flags); sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); - if (sd != NULL) + if (sd && (sd->expose_state & HPSA_SCSI_ADD)) sdev->hostdata = sd; + else + sdev->hostdata = NULL; + spin_unlock_irqrestore(&h->devlock, flags); + return 0; +} + +/* configure scsi device based on internal per-device structure */ +static int hpsa_slave_configure(struct scsi_device *sdev) +{ + struct hpsa_scsi_dev_t *sd; + unsigned long flags; + struct ctlr_info *h; + + h = sdev_to_hba(sdev); + spin_lock_irqsave(&h->devlock, flags); + sd = sdev->hostdata; + if (sd && !(sd->expose_state & HPSA_ULD_ATTACH)) + sdev->no_uld_attach = 1; + spin_unlock_irqrestore(&h->devlock, flags); return 0; } @@ -3289,10 +3315,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) /* Figure out where the LUN ID info is coming from */ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, i, nphysicals, nlogicals, physdev_list, logdev_list); - /* skip masked physical devices. */ - if (lunaddrbytes[3] & 0xC0 && - i < nphysicals + (raid_ctlr_position == 0)) - continue; + + /* skip masked non-disk devices */ + if (MASKED_DEVICE(lunaddrbytes)) + if (i < nphysicals + (raid_ctlr_position == 0) && + NON_DISK_PHYS_DEV(lunaddrbytes)) + continue; /* Get device type, vendor, model, device id */ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, @@ -3317,6 +3345,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) *this_device = *tmpdevice; + /* do not expose masked devices */ + if (MASKED_DEVICE(lunaddrbytes) && + i < nphysicals + (raid_ctlr_position == 0)) { + if (h->hba_mode_enabled) + dev_warn(&h->pdev->dev, + "Masked physical device detected\n"); + this_device->expose_state = HPSA_DO_NOT_EXPOSE; + } else { + this_device->expose_state = + HPSA_SG_ATTACH | HPSA_ULD_ATTACH; + } + switch (this_device->devtype) { case TYPE_ROM: /* We don't *really* support actual CD-ROM devices, @@ -3358,6 +3398,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) case TYPE_MEDIUM_CHANGER: ncurrent++; break; + case TYPE_ENCLOSURE: + if (h->hba_mode_enabled) + ncurrent++; + break; case TYPE_RAID: /* Only present the Smartarray HBA as a RAID controller. * If it's a RAID controller other than the HBA itself diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 978c23fcbcf5fc..fa9caba34ae167 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -54,6 +54,11 @@ struct hpsa_scsi_dev_t { */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ int supports_aborts; +#define HPSA_DO_NOT_EXPOSE 0x0 +#define HPSA_SG_ATTACH 0x1 +#define HPSA_ULD_ATTACH 0x2 +#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) + u8 expose_state; }; struct reply_queue_buffer { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index ba983440f75352..4870ffff203daa 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -240,9 +240,12 @@ struct ReportLUNdata { struct ext_report_lun_entry { u8 lunid[8]; +#define MASKED_DEVICE(x) ((x)[3] & 0xC0) u8 wwid[8]; u8 device_type; u8 device_flags; +#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01) +#define PHYS_IOACCEL(x) ((x)[17] & 0x08) u8 lun_count; /* multi-lun device, how many luns */ u8 redundant_paths; u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ From e82f7483c288b69b58163390a4dffa1b4f1bee94 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:09 -0500 Subject: [PATCH 249/889] hpsa: avoid unnecessary io in hpsa_get_pdisk_of_ioaccel2() THIS PATCH IS PROBLEMATIC - DO NOT SUBMIT UPSTREAM AS IS. The problem is that h->dev[] does not contain data for unexposed disks, which is what we need for getting the physical disk of an io by matching up the ioaccel handle. A later patch gets this data and puts it in h->dev[] so this patch eventually works, but not at this point in the stack. Below is the original commit message. Instead of doing CISS_REPORT_PHYSICAL to get the LUNID for the physical disk in hpsa_get_pdisk_of_ioaccel2(), just get it out of h->dev[] where we already have it cached. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 93 +++++++-------------------------------------- 1 file changed, 14 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 09c68d58407bf6..751bead013f1c7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3052,88 +3052,23 @@ static int add_ext_target_dev(struct ctlr_info *h, static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr) { - struct ReportExtendedLUNdata *physicals = NULL; - int responsesize = 24; /* size of physical extended response */ - int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize; - u32 nphysicals = 0; /* number of reported physical devs */ - int found = 0; /* found match (1) or not (0) */ - u32 find; /* handle we need to match */ + struct io_accel2_cmd *c2 = + &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex]; + unsigned long flags; int i; - struct scsi_cmnd *scmd; /* scsi command within request being aborted */ - struct hpsa_scsi_dev_t *d; /* device of request being aborted */ - struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */ - u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */ - u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */ - - if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2) - return 0; /* no match */ - - /* point to the ioaccel2 device handle */ - c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex]; - if (c2a == NULL) - return 0; /* no match */ - - scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd; - if (scmd == NULL) - return 0; /* no match */ - - d = scmd->device->hostdata; - if (d == NULL) - return 0; /* no match */ - - it_nexus = cpu_to_le32((u32) d->ioaccel_handle); - scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus); - find = c2a->scsi_nexus; - - if (h->raid_offload_debug > 0) - dev_info(&h->pdev->dev, - "%s: scsi_nexus:0x%08x device id: 0x%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n", - __func__, scsi_nexus, - d->device_id[0], d->device_id[1], d->device_id[2], - d->device_id[3], d->device_id[4], d->device_id[5], - d->device_id[6], d->device_id[7], d->device_id[8], - d->device_id[9], d->device_id[10], d->device_id[11], - d->device_id[12], d->device_id[13], d->device_id[14], - d->device_id[15]); - - /* Get the list of physical devices */ - physicals = kzalloc(reportsize, GFP_KERNEL); - if (physicals == NULL) - return 0; - if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) { - dev_err(&h->pdev->dev, - "Can't lookup %s device handle: report physical LUNs failed.\n", - "HP SSD Smart Path"); - kfree(physicals); - return 0; - } - nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) / - responsesize; - - /* find ioaccel2 handle in list of physicals: */ - for (i = 0; i < nphysicals; i++) { - struct ext_report_lun_entry *entry = &physicals->LUN[i]; - - /* handle is in bytes 28-31 of each lun */ - if (entry->ioaccel_handle != find) - continue; /* didn't match */ - found = 1; - memcpy(scsi3addr, entry->lunid, 8); - if (h->raid_offload_debug > 0) - dev_info(&h->pdev->dev, - "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%8phN\n", - __func__, find, - entry->ioaccel_handle, scsi3addr); - break; /* found it */ - } - - kfree(physicals); - if (found) - return 1; - else - return 0; + spin_lock_irqsave(&h->devlock, flags); + for (i = 0; i < h->ndevices; i++) + if (h->dev[i]->ioaccel_handle == c2->scsi_nexus) { + memcpy(scsi3addr, h->dev[i]->scsi3addr, + sizeof(h->dev[i]->scsi3addr)); + spin_unlock_irqrestore(&h->devlock, flags); + return 1; + } + spin_unlock_irqrestore(&h->devlock, flags); + return 0; } + /* * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, * logdev. The number of luns in physdev and logdev are returned in From 46d1360cd7119cd0dfea5bc4068378d60e85c309 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:10 -0500 Subject: [PATCH 250/889] hpsa: handle descriptor format sense data where needed In hba mode, we could get sense data in descriptor format so we need to handle that. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 82 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 751bead013f1c7..61d2204782112e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -262,13 +262,53 @@ static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh) return (struct ctlr_info *) *priv; } +/* extract sense key, asc, and ascq from sense data. -1 means invalid. */ +static void decode_sense_data(const u8 *sense_data, int sense_data_len, + int *sense_key, int *asc, int *ascq) +{ + if (sense_data_len < 1) { + *sense_key = -1; + *ascq = -1; + *asc = -1; + return; + } + + switch (sense_data[0]) { + case 0x70: /* old format sense data */ + *sense_key = (sense_data_len > 2) ? sense_data[2] & 0x0f : -1; + *ascq = (sense_data_len > 13) ? sense_data[13] : -1; + *asc = (sense_data_len > 12) ? sense_data[12] : -1; + break; + case 0x72: /* descriptor format sense data */ + *sense_key = (sense_data_len > 1) ? sense_data[1] & 0x0f : -1; + *ascq = (sense_data_len > 2) ? sense_data[2] : -1; + *asc = (sense_data_len > 3) ? sense_data[3] : -1; + break; + default: + *sense_key = -1; + *ascq = -1; + *asc = -1; + break; + } +} + static int check_for_unit_attention(struct ctlr_info *h, struct CommandList *c) { - if (c->err_info->SenseInfo[2] != UNIT_ATTENTION) + int sense_key, asc, ascq; + int sense_len; + + if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo)) + sense_len = sizeof(c->err_info->SenseInfo); + else + sense_len = c->err_info->SenseLen; + + decode_sense_data(c->err_info->SenseInfo, sense_len, + &sense_key, &asc, &ascq); + if (sense_key != UNIT_ATTENTION || asc == -1) return 0; - switch (c->err_info->SenseInfo[12]) { + switch (asc) { case STATE_CHANGED: dev_warn(&h->pdev->dev, HPSA "%d: a state change " "detected, command retried\n", h->ctlr); @@ -1846,9 +1886,9 @@ static void complete_scsi_command(struct CommandList *cp) struct ErrorInfo *ei; struct hpsa_scsi_dev_t *dev; - unsigned char sense_key; - unsigned char asc; /* additional sense code */ - unsigned char ascq; /* additional sense code qualifier */ + int sense_key; + int asc; /* additional sense code */ + int ascq; /* additional sense code qualifier */ unsigned long sense_data_size; ei = cp->err_info; @@ -1915,14 +1955,9 @@ static void complete_scsi_command(struct CommandList *cp) switch (ei->CommandStatus) { case CMD_TARGET_STATUS: - if (ei->ScsiStatus) { - /* Get sense key */ - sense_key = 0xf & ei->SenseInfo[2]; - /* Get additional sense code */ - asc = ei->SenseInfo[12]; - /* Get addition sense code qualifier */ - ascq = ei->SenseInfo[13]; - } + if (ei->ScsiStatus) + decode_sense_data(ei->SenseInfo, sense_data_size, + &sense_key, &asc, &ascq); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { if (sense_key == ABORTED_COMMAND) { cmd->result |= DID_SOFT_ERROR << 16; @@ -2186,14 +2221,20 @@ static void hpsa_scsi_interpret_error(struct ctlr_info *h, { const struct ErrorInfo *ei = cp->err_info; struct device *d = &cp->h->pdev->dev; - const u8 *sd = ei->SenseInfo; + int sense_key, asc, ascq, sense_len; switch (ei->CommandStatus) { case CMD_TARGET_STATUS: + if (ei->SenseLen > sizeof(ei->SenseInfo)) + sense_len = sizeof(ei->SenseInfo); + else + sense_len = ei->SenseLen; + decode_sense_data(ei->SenseInfo, sense_len, + &sense_key, &asc, &ascq); hpsa_print_cmd(h, "SCSI status", cp); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) dev_warn(d, "SCSI Status = 02, Sense key = %02x, ASC = %02x, ASCQ = %02x\n", - sd[2] & 0x0f, sd[12], sd[13]); + sense_key, asc, ascq); else dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus); if (ei->ScsiStatus == 0) @@ -2736,7 +2777,8 @@ static int hpsa_volume_offline(struct ctlr_info *h, unsigned char scsi3addr[]) { struct CommandList *c; - unsigned char *sense, sense_key, asc, ascq; + unsigned char *sense; + int sense_key, asc, ascq, sense_len; int rc, ldstat = 0; u16 cmd_status; u8 scsi_status; @@ -2754,9 +2796,11 @@ static int hpsa_volume_offline(struct ctlr_info *h, return 0; } sense = c->err_info->SenseInfo; - sense_key = sense[2]; - asc = sense[12]; - ascq = sense[13]; + if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo)) + sense_len = sizeof(c->err_info->SenseInfo); + else + sense_len = c->err_info->SenseLen; + decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq); cmd_status = c->err_info->CommandStatus; scsi_status = c->err_info->ScsiStatus; cmd_free(h, c); From 0aed4e950e9ad9a67b62ff4453d809a69b92e3b6 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:10 -0500 Subject: [PATCH 251/889] hpsa: print CDBs instead of kernel virtual addresses for uncommon errors Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 61d2204782112e..0e6814322cf59e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1998,9 +1998,8 @@ static void complete_scsi_command(struct CommandList *cp) case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ break; case CMD_DATA_OVERRUN: - dev_warn(&h->pdev->dev, "cp %p has" - " completed with data overrun " - "reported\n", cp); + dev_warn(&h->pdev->dev, + "CDB %16phN data overrun\n", cp->Request.CDB); break; case CMD_INVALID: { /* print_bytes(cp, sizeof(*cp), 1, 0); @@ -2016,34 +2015,38 @@ static void complete_scsi_command(struct CommandList *cp) break; case CMD_PROTOCOL_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p has " - "protocol error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n", + cp->Request.CDB); break; case CMD_HARDWARE_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n", + cp->Request.CDB); break; case CMD_CONNECTION_LOST: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n", + cp->Request.CDB); break; case CMD_ABORTED: cmd->result = DID_ABORT << 16; - dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n", - cp, ei->ScsiStatus); + dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", + cp->Request.CDB, ei->ScsiStatus); break; case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n", + cp->Request.CDB); break; case CMD_UNSOLICITED_ABORT: cmd->result = DID_SOFT_ERROR << 16; /* retry the command */ - dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited " - "abort\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n", + cp->Request.CDB); break; case CMD_TIMEOUT: cmd->result = DID_TIME_OUT << 16; - dev_warn(&h->pdev->dev, "cp %p timedout\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN timedout\n", + cp->Request.CDB); break; case CMD_UNABORTABLE: cmd->result = DID_ERROR << 16; From 43953a1cc790b03058f5e14308cfc9c6a548f471 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:11 -0500 Subject: [PATCH 252/889] hpsa: handle Command Status TMF function status It's possible for CommandStatus to have value 0x0D "TMF Function Status", which we should handle. We will get this from a P1224 when aborting a non-existent tag, for example. The "ScsiStatus" field of the errinfo field will contain the TMF function status value. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 ++++++++++++++++++++++++++++++++--------- drivers/scsi/hpsa_cmd.h | 9 +++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0e6814322cf59e..8775dce4f165c1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1879,6 +1879,33 @@ static void process_ioaccel2_completion(struct ctlr_info *h, queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } +/* Returns 0 on success, < 0 otherwise. */ +static int hpsa_evaluate_tmf_status(struct ctlr_info *h, + struct CommandList *cp) +{ + u8 tmf_status = cp->err_info->ScsiStatus; + + switch (tmf_status) { + case CISS_TMF_COMPLETE: + /* CISS_TMF_COMPLETE never happens, instead, + * ei->CommandStatus == 0 for this case. + */ + case CISS_TMF_SUCCESS: + return 0; + case CISS_TMF_INVALID_FRAME: + case CISS_TMF_NOT_SUPPORTED: + case CISS_TMF_FAILED: + case CISS_TMF_WRONG_LUN: + case CISS_TMF_OVERLAPPED_TAG: + break; + default: + dev_warn(&h->pdev->dev, "Unknown TMF status: %02x\n", + tmf_status); + break; + } + return -tmf_status; +} + static void complete_scsi_command(struct CommandList *cp) { struct scsi_cmnd *cmd; @@ -1907,8 +1934,6 @@ static void complete_scsi_command(struct CommandList *cp) if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); - cmd->result |= ei->ScsiStatus; - scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { cmd_free(h, cp); @@ -1916,16 +1941,6 @@ static void complete_scsi_command(struct CommandList *cp) return; } - /* copy the sense data */ - if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) - sense_data_size = SCSI_SENSE_BUFFERSIZE; - else - sense_data_size = sizeof(ei->SenseInfo); - if (ei->SenseLen < sense_data_size) - sense_data_size = ei->SenseLen; - - memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); - /* For I/O accelerator commands, copy over some fields to the normal * CISS header used below for error handling. */ @@ -1955,6 +1970,15 @@ static void complete_scsi_command(struct CommandList *cp) switch (ei->CommandStatus) { case CMD_TARGET_STATUS: + cmd->result |= ei->ScsiStatus; + /* copy the sense data */ + if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) + sense_data_size = SCSI_SENSE_BUFFERSIZE; + else + sense_data_size = sizeof(ei->SenseInfo); + if (ei->SenseLen < sense_data_size) + sense_data_size = ei->SenseLen; + memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); if (ei->ScsiStatus) decode_sense_data(ei->SenseInfo, sense_data_size, &sense_key, &asc, &ascq); @@ -2052,6 +2076,10 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "Command unabortable\n"); break; + case CMD_TMF_STATUS: + if (hpsa_evaluate_tmf_status(h, cp)) /* TMF failed? */ + cmd->result = DID_ERROR << 16; + break; case CMD_IOACCEL_DISABLED: /* This only handles the direct pass-through case since RAID * offload is handled above. Just attempt a retry. @@ -2878,6 +2906,9 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, case CMD_ABORT_FAILED: rc = 1; break; + case CMD_TMF_STATUS: + rc = hpsa_evaluate_tmf_status(h, c); + break; default: rc = 0; break; @@ -4717,6 +4748,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, switch (ei->CommandStatus) { case CMD_SUCCESS: break; + case CMD_TMF_STATUS: + rc = hpsa_evaluate_tmf_status(h, c); + break; case CMD_UNABORTABLE: /* Very common, don't make noise. */ rc = -1; break; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 4870ffff203daa..8354629e134a28 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -42,8 +42,17 @@ #define CMD_UNSOLICITED_ABORT 0x000A #define CMD_TIMEOUT 0x000B #define CMD_UNABORTABLE 0x000C +#define CMD_TMF_STATUS 0x000D #define CMD_IOACCEL_DISABLED 0x000E +/* TMF function status values */ +#define CISS_TMF_COMPLETE 0x00 +#define CISS_TMF_INVALID_FRAME 0x02 +#define CISS_TMF_NOT_SUPPORTED 0x04 +#define CISS_TMF_FAILED 0x05 +#define CISS_TMF_SUCCESS 0x08 +#define CISS_TMF_WRONG_LUN 0x09 +#define CISS_TMF_OVERLAPPED_TAG 0x0a /* Unit Attentions ASC's as defined for the MSA2012sa */ #define POWER_OR_RESET 0x29 From cb83191038eea0aefeec76190e50a32633925143 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:11 -0500 Subject: [PATCH 253/889] hpsa: do not use a void pointer for scsi_cmd field of struct CommandList There's no reason for it to be a void *, it should be a struct scsi_cmnd * Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- drivers/scsi/hpsa_cmd.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8775dce4f165c1..70bd561fda339c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1919,7 +1919,7 @@ static void complete_scsi_command(struct CommandList *cp) unsigned long sense_data_size; ei = cp->err_info; - cmd = (struct scsi_cmnd *) cp->scsi_cmd; + cmd = cp->scsi_cmd; h = cp->h; dev = cmd->device->hostdata; @@ -4785,7 +4785,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, unsigned char *psa = &phys_scsi3addr[0]; /* Get a pointer to the hpsa logical device. */ - scmd = (struct scsi_cmnd *) abort->scsi_cmd; + scmd = abort->scsi_cmd; dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata); if (dev == NULL) { dev_warn(&h->pdev->dev, @@ -4939,7 +4939,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); - as = (struct scsi_cmnd *) abort->scsi_cmd; + as = abort->scsi_cmd; if (as != NULL) ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", as->cmnd[0], as->serial_number); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 8354629e134a28..84f0e5395c0158 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -416,7 +416,7 @@ struct CommandList { int cmd_type; long cmdindex; struct completion *waiting; - void *scsi_cmd; + struct scsi_cmnd *scsi_cmd; struct work_struct work; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 74f2ccf29670a057b3a138fa1422292c79fee2bc Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:12 -0500 Subject: [PATCH 254/889] hpsa: check for controller lockup If the controller is locked up, sending further commands isn't possible, so report the abort as failed immediately. Returning failed from the device reset handler will get the device kicked offline, which is fine if the controller is locked up anyhow. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 70bd561fda339c..a67e198f7cd2a8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4665,6 +4665,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) h = sdev_to_hba(scsicmd->device); if (h == NULL) /* paranoia */ return FAILED; + + if (lockup_detected(h)) + return FAILED; + dev = scsicmd->device->hostdata; if (!dev) { dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: " @@ -4891,6 +4895,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) "ABORT REQUEST FAILED, Controller lookup failed.\n")) return FAILED; + if (lockup_detected(h)) + return FAILED; + /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) From 892f32bb3d6a95ed9113fe5a738b7f4772a91a46 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:12 -0500 Subject: [PATCH 255/889] hpsa: Clean up host, channel, target, lun prints We had a mix of formats (2300, c2b3t0l0, C2B3T0L0) to to format used by the scsi midlayer and upper layer (2:3:0:0) so you can easily follow the information from hpsa to scsi midlayer to sd upper layer. Also add this information: - product ID - vendor ID - RAID level - SSD Smath Path capable and enabled - exposure level (sg-only) Example: hpsa 0000:04:00.0: added scsi 2:0:0:0: Direct-Access HP LOGICAL VOLUME RAID-0 SSDSmartPathCap+ En+ Exp=4 scsi 2:0:0:0: Direct-Access HP LOGICAL VOLUME 10.0 PQ: 0 ANSI: 5 sd 2:0:0:0: [sdr] 12501713072 512-byte logical blocks: (6.40 TB/5.82 TiB) sd 2:0:0:0: [sdr] 4096-byte physical blocks sd 2:0:0:0: [sdr] Attached SCSI disk sd 2:0:0:0: Attached scsi generic sg20 type 0 Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 110 +++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a67e198f7cd2a8..90386010c2097c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1139,14 +1139,17 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, added[*nadded] = device; (*nadded)++; - /* initially, (before registering with scsi layer) we don't - * know our hostno and we don't want to print anything first - * time anyway (the scsi layer's inquiries will show that info) - */ - /* if (hostno != -1) */ - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d added.\n", - scsi_device_type(device->devtype), hostno, - device->bus, device->target, device->lun); + dev_info(&h->pdev->dev, + "added scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, device->bus, device->target, device->lun, + scsi_device_type(device->devtype), + device->vendor, + device->model, + device->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[device->raid_level], + device->offload_config ? '+' : '-', + device->offload_enabled ? '+' : '-', + device->expose_state); return 0; } @@ -1177,9 +1180,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; h->dev[entry]->offload_enabled = new_entry->offload_enabled; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); + dev_info(&h->pdev->dev, + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, new_entry->bus, new_entry->target, new_entry->lun, + scsi_device_type(new_entry->devtype), + new_entry->vendor, + new_entry->model, + new_entry->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[new_entry->raid_level], + new_entry->offload_config ? '+' : '-', + new_entry->offload_enabled ? '+' : '-', + new_entry->expose_state); } /* Replace an entry from h->dev[] array. */ @@ -1205,9 +1216,17 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, h->dev[entry] = new_entry; added[*nadded] = new_entry; (*nadded)++; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); + dev_info(&h->pdev->dev, + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, new_entry->bus, new_entry->target, new_entry->lun, + scsi_device_type(new_entry->devtype), + new_entry->vendor, + new_entry->model, + new_entry->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[new_entry->raid_level], + new_entry->offload_config ? '+' : '-', + new_entry->offload_enabled ? '+' : '-', + new_entry->expose_state); } /* Remove an entry from h->dev[] array. */ @@ -1227,9 +1246,17 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, for (i = entry; i < h->ndevices-1; i++) h->dev[i] = h->dev[i+1]; h->ndevices--; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d removed.\n", - scsi_device_type(sd->devtype), hostno, sd->bus, sd->target, - sd->lun); + dev_info(&h->pdev->dev, + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, sd->bus, sd->target, sd->lun, + scsi_device_type(sd->devtype), + sd->vendor, + sd->model, + sd->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[sd->raid_level], + sd->offload_config ? '+' : '-', + sd->offload_enabled ? '+' : '-', + sd->expose_state); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1518,9 +1545,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, */ if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); - dev_info(&h->pdev->dev, "c%db%dt%dl%d: temporarily offline\n", - h->scsi_host->host_no, - sd[i]->bus, sd[i]->target, sd[i]->lun); + dev_info(&h->pdev->dev, + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, + scsi_device_type(sd[i]->devtype), + sd[i]->vendor, + sd[i]->model, + sd[i]->raid_level > RAID_UNKNOWN ? + "RAID-?" : + raid_label[sd[i]->raid_level], + sd[i]->offload_config ? '+' : '-', + sd[i]->offload_enabled ? '+' : '-', + sd[i]->expose_state); continue; } @@ -1576,7 +1612,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * timeout as if the device was gone. */ dev_warn(&h->pdev->dev, - "didn't find c%db%dt%dl%d for removal.", + "didn't find scsi %d:%d:%d:%d for removal.", hostno, removed[i]->bus, removed[i]->target, removed[i]->lun); } @@ -1592,8 +1628,9 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (scsi_add_device(sh, added[i]->bus, added[i]->target, added[i]->lun) == 0) continue; - dev_warn(&h->pdev->dev, "scsi_add_device c%db%dt%dl%d failed, " - "device not added.\n", hostno, added[i]->bus, + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d addition failed, device not added.\n", + hostno, added[i]->bus, added[i]->target, added[i]->lun); /* now we have to remove it from h->dev, * since it didn't get added to scsi mid layer @@ -4675,14 +4712,26 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) "device lookup failed.\n"); return FAILED; } - dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n", - h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + dev_warn(&h->pdev->dev, + "resetting scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun, + scsi_device_type(dev->devtype), + dev->vendor, + dev->model, + dev->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[dev->raid_level], + dev->offload_config ? '+' : '-', + dev->offload_enabled ? '+' : '-', + dev->expose_state); + /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN); if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) return SUCCESS; - dev_warn(&h->pdev->dev, "resetting device failed.\n"); + dev_warn(&h->pdev->dev, + "resetting scsi %d:%d:%d:%d failed\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun); return FAILED; } @@ -4799,7 +4848,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, if (h->raid_offload_debug > 0) dev_info(&h->pdev->dev, - "Reset as abort: Abort requested on C%d:B%d:T%d:L%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + "Reset as abort: scsi %d:%d:%d:%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun, scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3], scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); @@ -4904,7 +4953,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; memset(msg, 0, sizeof(msg)); - ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%llu ", + ml += sprintf(msg+ml, "Aborting command on scsi %d:%d:%d:%llu ", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun); @@ -4951,7 +5000,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", as->cmnd[0], as->serial_number); dev_dbg(&h->pdev->dev, "%s\n", msg); - dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", + dev_warn(&h->pdev->dev, "Aborting command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); /* * Command is in flight, or possibly already completed @@ -4960,8 +5009,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); if (rc != 0) { - dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); - dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", + dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); cmd_free(h, abort); From 279cc764984638c6cec04e2742a08a6f9ca0fdbb Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:13 -0500 Subject: [PATCH 256/889] hpsa: mark masked devices as masked in output Otherwise it can seems as though there is a discrepancy between the driver's output and the output of lsscsi when the driver claims to have "added" a device but then does not actually call scsi_add_device() for it because it is masked. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 90386010c2097c..3d6124be7da149 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1140,7 +1140,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "added scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), device->vendor, From f5e9e3d92e70f6dd9d9d1590c1f91a9f7ba1cce5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:14 -0500 Subject: [PATCH 257/889] hpsa: limit number of concurrent abort requests If all available commands are outstanding and the abort handler is invoked, the abort handler may not be able to allocate a command and may busy-wait excessivly. Reserve a small number of commands for the abort handler and limit the number of concurrent abort requests to the number of reserved commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++++++++++++++++++++++ drivers/scsi/hpsa.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3d6124be7da149..40fbdf8e8bd0ae 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4922,6 +4922,18 @@ static int hpsa_extract_reply_queue(struct ctlr_info *h, return c->Header.ReplyQueue; } +/* + * Limit concurrency of abort commands to prevent + * over-subscription of commands + */ +static inline int wait_for_available_abort_cmd(struct ctlr_info *h) +{ +#define ABORT_CMD_WAIT_MSECS 5000 + return !wait_event_timeout(h->abort_cmd_wait_queue, + atomic_dec_if_positive(&h->abort_cmds_available) >= 0, + msecs_to_jiffies(ABORT_CMD_WAIT_MSECS)); +} + /* Send an abort for the specified command. * If the device and controller support it, * send a task abort request. @@ -5008,7 +5020,15 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * by the firmware (but not to the scsi mid layer) but we can't * distinguish which. Send the abort down. */ + if (wait_for_available_abort_cmd(h)) { + dev_warn(&h->pdev->dev, + "Timed out waiting for an abort command to become available.\n"); + cmd_free(h, abort); + return FAILED; + } rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); + atomic_inc(&h->abort_cmds_available); + wake_up_all(&h->abort_cmd_wait_queue); if (rc != 0) { dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", h->scsi_host->host_no, @@ -7284,6 +7304,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); + atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { @@ -7334,6 +7355,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); + init_waitqueue_head(&h->abort_cmd_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index fa9caba34ae167..3a6a2eb3011e29 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -244,6 +244,8 @@ struct ctlr_info { int lockup_detector_enabled; int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; + atomic_t abort_cmds_available; + wait_queue_head_t abort_cmd_wait_queue; }; struct offline_device_entry { From 1c7f4d3cfc8a7edfaa67332c0125a1b835787416 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:14 -0500 Subject: [PATCH 258/889] hpsa: separate lockup detection and device rescanning Piggybacking device rescanning functionality onto the lockup detection thread is not a good idea because if the controller locks up during device rescanning, then the thread could get stuck, then the lockup isn't detected. Use separate work queues for device rescanning and lockup detection. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 +++++++++++++++++++++++++-------- drivers/scsi/hpsa.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 40fbdf8e8bd0ae..d48807b73ac576 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7158,15 +7158,11 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } - -static void hpsa_monitor_ctlr_worker(struct work_struct *work) +static void hpsa_rescan_ctlr_worker(struct work_struct *work) { unsigned long flags; struct ctlr_info *h = container_of(to_delayed_work(work), - struct ctlr_info, monitor_ctlr_work); - detect_controller_lockup(h); - if (lockup_detected(h)) - return; + struct ctlr_info, rescan_ctlr_work); if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { scsi_host_get(h->scsi_host); @@ -7174,13 +7170,30 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); } - spin_lock_irqsave(&h->lock, flags); if (h->remove_in_progress) { spin_unlock_irqrestore(&h->lock, flags); return; } - schedule_delayed_work(&h->monitor_ctlr_work, + schedule_delayed_work(&h->rescan_ctlr_work, + h->heartbeat_sample_interval); + spin_unlock_irqrestore(&h->lock, flags); +} + +static void hpsa_monitor_ctlr_worker(struct work_struct *work) +{ + unsigned long flags; + struct ctlr_info *h = container_of(to_delayed_work(work), + struct ctlr_info, monitor_ctlr_work); + detect_controller_lockup(h); + if (lockup_detected(h)) + return; + + spin_lock_irqsave(&h->lock, flags); + if (h->remove_in_progress) + spin_unlock_irqrestore(&h->lock, flags); + else + schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); spin_unlock_irqrestore(&h->lock, flags); } @@ -7437,6 +7450,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); + INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker); + schedule_delayed_work(&h->rescan_ctlr_work, + h->heartbeat_sample_interval); return 0; clean4: @@ -7525,6 +7541,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) spin_lock_irqsave(&h->lock, flags); h->remove_in_progress = 1; cancel_delayed_work(&h->monitor_ctlr_work); + cancel_delayed_work(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 3a6a2eb3011e29..42ddd998a8584b 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -198,6 +198,7 @@ struct ctlr_info { atomic_t firmware_flash_in_progress; u32 *lockup_detected; struct delayed_work monitor_ctlr_work; + struct delayed_work rescan_ctlr_work; int remove_in_progress; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; From a33a564d0a1bf86a3bd1633bee02249ce196ff84 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:15 -0500 Subject: [PATCH 259/889] hpsa: factor out hpsa_init_cmd function Factor out hpsa_cmd_init from cmd_alloc(). We also need this for resubmitting commands down the default RAID path when they have returned from the ioaccel paths with errors. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d48807b73ac576..e8ca1531e83392 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4319,6 +4319,26 @@ static int hpsa_ciss_submit(struct ctlr_info *h, return 0; } +static inline void hpsa_cmd_init(struct ctlr_info *h, int index, + struct CommandList *c) +{ + dma_addr_t cmd_dma_handle, err_dma_handle; + + /* Zero out all of commandlist except the last field, refcount */ + memset(c, 0, offsetof(struct CommandList, refcount)); + c->Header.tag = cpu_to_le64((u64) (index << DIRECT_LOOKUP_SHIFT)); + cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c); + c->err_info = h->errinfo_pool + index; + memset(c->err_info, 0, sizeof(*c->err_info)); + err_dma_handle = h->errinfo_pool_dhandle + + index * sizeof(*c->err_info); + c->cmdindex = index; + c->busaddr = (u32) cmd_dma_handle; + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); + c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); + c->h = h; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -5050,10 +5070,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) static struct CommandList *cmd_alloc(struct ctlr_info *h) { struct CommandList *c; - int i; - union u64bit temp64; - dma_addr_t cmd_dma_handle, err_dma_handle; - int refcount; + int refcount, i; unsigned long offset; /* There is some *extremely* small but non-zero chance that that @@ -5086,24 +5103,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } h->last_allocation = i; /* benignly racy */ - - /* Zero out all of commandlist except the last field, refcount */ - memset(c, 0, offsetof(struct CommandList, refcount)); - c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT)); - cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); - c->err_info = h->errinfo_pool + i; - memset(c->err_info, 0, sizeof(*c->err_info)); - err_dma_handle = h->errinfo_pool_dhandle - + i * sizeof(*c->err_info); - - c->cmdindex = i; - - c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); - c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); - - c->h = h; + hpsa_cmd_init(h, i, c); return c; } From 267acb646e35bac7e72c898fec3bf2e4350ef60f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:15 -0500 Subject: [PATCH 260/889] hpsa: reinitialize commands on resubmitting failed ioaccel commands In particular, reinitialize the cmd_type and busaddr fields as these will not be correct for submitting down the RAID stack path after ioaccel command completion. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e8ca1531e83392..6760854c160942 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4353,6 +4353,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } + hpsa_cmd_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* * If we get here, it means dma mapping failed. Try From 38850a7f7423298efc39903173999a66f5bfc3ec Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:16 -0500 Subject: [PATCH 261/889] hpsa: fully initialize commands once at driver load not every time This saves time when submitting commands. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6760854c160942..48c91bb332c22a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4268,7 +4268,6 @@ static int hpsa_ciss_submit(struct ctlr_info *h, /* Fill in the request block... */ c->Request.Timeout = 0; - memset(c->Request.CDB, 0, sizeof(c->Request.CDB)); BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB)); c->Request.CDBLen = cmd->cmd_len; memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); @@ -4319,7 +4318,7 @@ static int hpsa_ciss_submit(struct ctlr_info *h, return 0; } -static inline void hpsa_cmd_init(struct ctlr_info *h, int index, +static void hpsa_cmd_init(struct ctlr_info *h, int index, struct CommandList *c) { dma_addr_t cmd_dma_handle, err_dma_handle; @@ -4339,6 +4338,26 @@ static inline void hpsa_cmd_init(struct ctlr_info *h, int index, c->h = h; } +static void hpsa_preinitialize_commands(struct ctlr_info *h) +{ + int i; + + for (i = 0; i < h->nr_cmds; i++) { + struct CommandList *c = h->cmd_pool + i; + hpsa_cmd_init(h, i, c); + } +} + +static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, + struct CommandList *c) +{ + dma_addr_t cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c); + + memset(c->Request.CDB, 0, sizeof(c->Request.CDB)); + memset(c->err_info, 0, sizeof(*c->err_info)); + c->busaddr = (u32) cmd_dma_handle; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -4353,7 +4372,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } - hpsa_cmd_init(c->h, c->cmdindex, c); + hpsa_cmd_partial_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* * If we get here, it means dma mapping failed. Try @@ -4473,10 +4492,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) h->acciopath_status)) { cmd->host_scribble = (unsigned char *) c; - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; if (dev->offload_enabled) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; rc = hpsa_scsi_ioaccel_raid_map(h, c); if (rc == 0) return 0; /* Sent on ioaccel path */ @@ -4485,6 +4505,9 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; rc = hpsa_scsi_ioaccel_direct_map(h, c); if (rc == 0) return 0; /* Sent on direct map path */ @@ -5104,7 +5127,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } h->last_allocation = i; /* benignly racy */ - hpsa_cmd_init(h, i, c); + hpsa_cmd_partial_init(h, i, c); return c; } @@ -6818,6 +6841,7 @@ static int hpsa_allocate_cmd_pool(struct ctlr_info *h) dev_err(&h->pdev->dev, "out of memory in %s", __func__); return -ENOMEM; } + hpsa_preinitialize_commands(h); return 0; } From 4ddd6b0266e2f1f81ed1c5e319f995b9498cdef5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:16 -0500 Subject: [PATCH 262/889] hpsa: allow lockup detected to be viewed via sysfs --- drivers/scsi/hpsa.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 48c91bb332c22a..43c8df72746795 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -383,6 +383,30 @@ static ssize_t host_show_lockup_detector(struct device *dev, return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); } +static u32 lockup_detected(struct ctlr_info *h); +static ssize_t host_show_lockup_detected(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, ld, c, cpu; + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + ld = lockup_detected(h); + + c = sprintf(buf, "ld=%d: ", ld); + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < num_online_cpus(); i++) { + u32 *lockup_detected; + lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); + ld = *lockup_detected; + cpu = cpumask_next(cpu, cpu_online_mask); + c += sprintf(buf + c, "%d,", ld); + } + c += sprintf(buf + c, "\n"); + return c; +} + static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -812,6 +836,8 @@ static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, host_show_lockup_detector, host_store_lockup_detector); +static DEVICE_ATTR(lockup_detected, S_IRUGO, + host_show_lockup_detected, NULL); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -832,6 +858,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, &dev_attr_lockup_detector, + &dev_attr_lockup_detected, NULL, }; From 42dc1ff2b71541fb69eda0453bc3405f541d879d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:17 -0500 Subject: [PATCH 263/889] hpsa: try resubmitting down raid path on task set full Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 43c8df72746795..73d5e535a89d51 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1858,8 +1858,7 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL: - /* Make scsi midlayer do unlimited retries */ - cmd->result = DID_IMM_RETRY << 16; + retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED: dev_warn(&h->pdev->dev, From 51795decd640d4bea6bd907137fbe6a3b71dbf9b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:18 -0500 Subject: [PATCH 264/889] hpsa: factor out hpsa_ioaccel_submit function Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 73d5e535a89d51..4d0e029a8ca4f0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4384,6 +4384,41 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, c->busaddr = (u32) cmd_dma_handle; } +static int hpsa_ioaccel_submit(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd, + unsigned char *scsi3addr) +{ + struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; + int rc = IO_ACCEL_INELIGIBLE; + + cmd->host_scribble = (unsigned char *) c; + + if (dev->offload_enabled) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + rc = hpsa_scsi_ioaccel_raid_map(h, c); + if (rc == 0) + return 0; /* Sent on ioaccel path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } else if (dev->ioaccel_handle) { + hpsa_cmd_init(h, c->cmdindex, c); + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + rc = hpsa_scsi_ioaccel_direct_map(h, c); + if (rc == 0) + return 0; /* Sent on direct map path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + return rc; +} + static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; @@ -4516,32 +4551,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (likely(cmd->retries == 0 && cmd->request->cmd_type == REQ_TYPE_FS && h->acciopath_status)) { - - cmd->host_scribble = (unsigned char *) c; - - if (dev->offload_enabled) { - hpsa_cmd_init(h, c->cmdindex, c); - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; - rc = hpsa_scsi_ioaccel_raid_map(h, c); - if (rc == 0) - return 0; /* Sent on ioaccel path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } else if (dev->ioaccel_handle) { - hpsa_cmd_init(h, c->cmdindex, c); - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; - rc = hpsa_scsi_ioaccel_direct_map(h, c); - if (rc == 0) - return 0; /* Sent on direct map path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } + rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); + if (rc == 0) + return 0; + if (rc < 0) + return SCSI_MLQUEUE_HOST_BUSY; } return hpsa_ciss_submit(h, c, cmd, scsi3addr); } From 04ea1cebb856744e36a9821e77d90ec40fbe21e5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:18 -0500 Subject: [PATCH 265/889] hpsa: try resubmitting down ioaccelerated path on task set full Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4d0e029a8ca4f0..85e5e79c412d7d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4433,6 +4433,28 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } + if (c->cmd_type == CMD_IOACCEL2) { + struct ctlr_info *h = c->h; + struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + int rc; + + if (c2->error_data.serv_response == + IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) { + rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); + if (rc == 0) + return; + if (rc < 0) { + /* + * If we get here, it means dma mapping failed. + * Try again via scsi mid layer, which will + * then get SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } + /* if rc > 0, fall thru and resubmit down CISS path */ + } + } hpsa_cmd_partial_init(c->h, c->cmdindex, c); if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { /* From 2fffb29846570e84c1149e50bf11ee642663d1e8 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:19 -0500 Subject: [PATCH 266/889] hpsa: get queue depth for physical devices Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 49 ++++++++++++++++++++++++++++++++--------- drivers/scsi/hpsa.h | 1 + drivers/scsi/hpsa_cmd.h | 4 ++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 85e5e79c412d7d..8618a0c1dde641 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1700,10 +1700,14 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(&h->devlock, flags); sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); - if (sd && (sd->expose_state & HPSA_SCSI_ADD)) + if (sd && (sd->expose_state & HPSA_SCSI_ADD)) { sdev->hostdata = sd; - else + if (sd->queue_depth) + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), + sd->queue_depth); + } else { sdev->hostdata = NULL; + } spin_unlock_irqrestore(&h->devlock, flags); return 0; } @@ -3305,6 +3309,31 @@ static int hpsa_hba_mode_enabled(struct ctlr_info *h) return hba_mode_enabled; } +/* get physical drive ioaccel handle and queue depth */ +void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev, + u8 *lunaddrbytes, + struct bmic_identify_physical_device *id_phys) +{ + int rc; + struct ext_report_lun_entry *rle = + (struct ext_report_lun_entry *) lunaddrbytes; + + dev->ioaccel_handle = rle->ioaccel_handle; + memset(id_phys, 0, sizeof(*id_phys)); + rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, + GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, + sizeof(*id_phys)); + if (!rc) + /* Reserve space for FW operations */ +#define DRIVE_CMDS_RESERVED_FOR_FW 2 + dev->queue_depth = + le16_to_cpu(id_phys->current_queue_depth_limit) - + DRIVE_CMDS_RESERVED_FOR_FW; + else + dev->queue_depth = 7; /* conservative */ +} + static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) { /* the idea here is we could get notified @@ -3319,6 +3348,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) */ struct ReportExtendedLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; + struct bmic_identify_physical_device *id_phys = NULL; u32 nphysicals = 0; u32 nlogicals = 0; u32 ndev_allocated = 0; @@ -3333,8 +3363,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); + id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); - if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { + if (!currentsd || !physdev_list || !logdev_list || + !tmpdevice || !id_phys) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } @@ -3465,9 +3497,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) } if (h->transMethod & CFGTBL_Trans_io_accel1 || h->transMethod & CFGTBL_Trans_io_accel2) { - memcpy(&this_device->ioaccel_handle, - &lunaddrbytes[20], - sizeof(this_device->ioaccel_handle)); + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); ncurrent++; } break; @@ -3503,6 +3534,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) kfree(currentsd); kfree(physdev_list); kfree(logdev_list); + kfree(id_phys); } /* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci @@ -4710,10 +4742,7 @@ static int hpsa_register_scsi(struct ctlr_info *h) HPSA_CMDS_RESERVED_FOR_ABORTS - HPSA_CMDS_RESERVED_FOR_DRIVER - HPSA_MAX_CONCURRENT_PASSTHRUS; - if (h->hba_mode_enabled) - sh->cmd_per_lun = 7; - else - sh->cmd_per_lun = sh->can_queue; + sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 42ddd998a8584b..e9e6954fe188e4 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -46,6 +46,7 @@ struct hpsa_scsi_dev_t { unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ + u16 queue_depth; u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 84f0e5395c0158..7df234649ce5a8 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -250,6 +250,10 @@ struct ReportLUNdata { struct ext_report_lun_entry { u8 lunid[8]; #define MASKED_DEVICE(x) ((x)[3] & 0xC0) +#define GET_BMIC_BUS(lunid) ((lunid)[7] & 0x3F) +#define GET_BMIC_LEVEL_TWO_TARGET(lunid) ((lunid)[6]) +#define GET_BMIC_DRIVE_NUMBER(lunid) (((GET_BMIC_BUS((lunid)) - 1) << 8) + \ + GET_BMIC_LEVEL_TWO_TARGET((lunid))) u8 wwid[8]; u8 device_type; u8 device_flags; From 5e212db41b94e8f6d7b082aa91d4337d70c20cea Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:19 -0500 Subject: [PATCH 267/889] hpsa: honor queue depth of physical devices When using the ioaccel submission methods, requests destined for RAID volumes are sometimes diverted to physical devices. The OS has no or limited knowledge of these physical devices, so it is up to the driver to avoid pushing the device too hard. It is better to honor the physical device queue limit rather than making the device spew zillions of TASK SET FULL responses. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 ++++++++++++++ drivers/scsi/hpsa.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8618a0c1dde641..db821b397949ff 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1705,6 +1705,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) if (sd->queue_depth) scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), sd->queue_depth); + atomic_set(&sd->ioaccel_cmds_out, 0); } else { sdev->hostdata = NULL; } @@ -1914,6 +1915,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + atomic_dec(&dev->ioaccel_cmds_out); + /* check for good status */ if (likely(c2->error_data.serv_response == 0 && c2->error_data.status == 0)) { @@ -2014,6 +2017,7 @@ static void complete_scsi_command(struct CommandList *cp) */ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; + atomic_dec(&dev->ioaccel_cmds_out); cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; cp->Header.tag = c->tag; @@ -4425,6 +4429,13 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd->host_scribble = (unsigned char *) c; + /* Try to honor the device's queue depth */ + atomic_inc(&dev->ioaccel_cmds_out); + if (atomic_read(&dev->ioaccel_cmds_out) > dev->queue_depth) { + atomic_dec(&dev->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + if (dev->offload_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; @@ -4434,6 +4445,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); + atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { @@ -4445,9 +4457,11 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); + atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } + atomic_dec(&dev->ioaccel_cmds_out); return rc; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index e9e6954fe188e4..deb0944e7096bd 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -47,6 +47,10 @@ struct hpsa_scsi_dev_t { unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ u16 queue_depth; + atomic_t ioaccel_cmds_out; /* Only used for physical devices + * counts commands sent to physical + * device via "ioaccel" path. + */ u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ From 0c19dff0aeb5a421350a64e62aaf7b559491b081 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:20 -0500 Subject: [PATCH 268/889] hpsa: use cancel_delayed_work_sync where needed Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index db821b397949ff..cf1cdae0278080 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7670,8 +7670,8 @@ static void hpsa_remove_one(struct pci_dev *pdev) /* Get rid of any controller monitoring work items */ spin_lock_irqsave(&h->lock, flags); h->remove_in_progress = 1; - cancel_delayed_work(&h->monitor_ctlr_work); - cancel_delayed_work(&h->rescan_ctlr_work); + cancel_delayed_work_sync(&h->monitor_ctlr_work); + cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); From 0282c414614a0a230d66625e5a07430fd0a8115f Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:20 -0500 Subject: [PATCH 269/889] hpsa: try to fix ioaccel command accounting code Need to count ioaccel commands to physical disks for RAID volumes not for logical disks. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 135 ++++++++++++++++++++++++++++++++-------- drivers/scsi/hpsa.h | 10 +++ drivers/scsi/hpsa_cmd.h | 10 +++ 3 files changed, 129 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cf1cdae0278080..4a97b3235aaa81 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -246,7 +246,7 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h); static void hpsa_flush_cache(struct ctlr_info *h); static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr); + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk); static void hpsa_command_resubmit_worker(struct work_struct *work); static void print_cfg_table(struct device *dev, struct CfgTable *tb); @@ -1501,6 +1501,60 @@ static void hpsa_show_volume_status(struct ctlr_info *h, } } +/* Figure the list of physical drive pointers for a logical drive with + * raid offload configured. + */ +static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices, + struct hpsa_scsi_dev_t *logical_drive) +{ + struct raid_map_data *map = &logical_drive->raid_map; + struct raid_map_disk_data *dd = &map->data[0]; + int i, j; + int nraid_map_entries = logical_drive->raid_map.data_disks_per_row + + logical_drive->raid_map.metadata_disks_per_row; + + for (i = 0; i < nraid_map_entries; i++) { + logical_drive->phys_disk[i] = NULL; + if (!logical_drive->offload_config) + continue; + for (j = 0; j < ndevices; j++) { + if (dev[j]->devtype != TYPE_DISK) + continue; + if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) + continue; + if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { + logical_drive->phys_disk[i] = dev[j]; + break; + } + } + + /* + * This can happen if a physical drive is removed and + * the logical drive is degraded. In that case, the RAID + * map data will refer to a physical disk which isn't actually + * present. And in that case offload_enabled should already + * be 0, but we'll turn it off here just in case + */ + if (!logical_drive->phys_disk[i]) + logical_drive->offload_enabled = 0; + } +} + +static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices) +{ + int i; + + for (i = 0; i < ndevices; i++) { + if (dev[i]->devtype != TYPE_DISK) + continue; + if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) + continue; + hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]); + } +} + static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, struct hpsa_scsi_dev_t *sd[], int nsds) { @@ -1915,7 +1969,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - atomic_dec(&dev->ioaccel_cmds_out); + atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ if (likely(c2->error_data.serv_response == 0 && @@ -2017,7 +2071,7 @@ static void complete_scsi_command(struct CommandList *cp) */ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; - atomic_dec(&dev->ioaccel_cmds_out); + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; cp->Header.tag = c->tag; @@ -3530,6 +3584,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } + hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent); adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); @@ -3653,7 +3708,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex]; @@ -3666,13 +3721,17 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE; /* TODO: implement chaining support */ - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX); - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } c->cmd_type = CMD_IOACCEL1; @@ -3681,9 +3740,18 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, (c->cmdindex * sizeof(*cp)); BUG_ON(c->busaddr & 0x0000007F); + /* Try to honor the device's queue depth */ + atomic_inc(&phys_disk->ioaccel_cmds_out); + if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { last_sg = scsi_sg_count(cmd) - 1; @@ -3744,7 +3812,7 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, - cmd->cmnd, cmd->cmd_len, dev->scsi3addr); + cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } /* @@ -3871,7 +3939,7 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -3882,11 +3950,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, u32 len; u32 total_len = 0; - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } + c->cmd_type = CMD_IOACCEL2; /* Adjust the DMA address to point to the accelerated command buffer */ c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle + @@ -3896,9 +3969,18 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, memset(cp, 0, sizeof(*cp)); cp->IU_type = IOACCEL2_IU_TYPE; + /* Try to honor the device's queue depth */ + atomic_inc(&phys_disk->ioaccel_cmds_out); + if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES); @@ -3964,14 +4046,22 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, */ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { + /* Try to honor the device's queue depth */ + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } if (h->transMethod & CFGTBL_Trans_io_accel1) return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); else return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); } static void raid_map_helper(struct raid_map_data *map, @@ -4267,6 +4357,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; } + c->phys_disk = dev->phys_disk[map_index]; + disk_handle = dd[map_index].ioaccel_handle; disk_block = map->disk_starting_blk + (first_row * map->strip_size) + (first_row_offset - (first_column * map->strip_size)); @@ -4312,7 +4404,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, cdb_len = 10; } return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len, - dev->scsi3addr); + dev->scsi3addr, + dev->phys_disk[map_index]); } /* Submit commands down the "normal" RAID stack path */ @@ -4429,13 +4522,6 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd->host_scribble = (unsigned char *) c; - /* Try to honor the device's queue depth */ - atomic_inc(&dev->ioaccel_cmds_out); - if (atomic_read(&dev->ioaccel_cmds_out) > dev->queue_depth) { - atomic_dec(&dev->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } - if (dev->offload_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; @@ -4445,7 +4531,6 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); - atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->ioaccel_handle) { @@ -4457,11 +4542,9 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ cmd_free(h, c); - atomic_dec(&dev->ioaccel_cmds_out); return SCSI_MLQUEUE_HOST_BUSY; } } - atomic_dec(&dev->ioaccel_cmds_out); return rc; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index deb0944e7096bd..cff0aaf48229ba 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -64,6 +64,16 @@ struct hpsa_scsi_dev_t { #define HPSA_ULD_ATTACH 0x2 #define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) u8 expose_state; + + /* Pointers from logical drive map indices to the phys drives that + * make those logical drives. Note, multiple logical drives may + * share physical drives. You can have for instance 5 physical + * drives with 3 logical drives each using those same 5 physical + * disks. We need these pointers for counting i/o's out to physical + * devices in order to honor physical device queue depth limits. + */ + struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; + int nphysical_disks; }; struct reply_queue_buffer { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 7df234649ce5a8..0bbe7c1acb44b1 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -422,6 +422,16 @@ struct CommandList { struct completion *waiting; struct scsi_cmnd *scsi_cmd; struct work_struct work; + + /* For commands using either of the two "ioaccel" paths to + * bypass the RAID stack and go directly to the physical disk + * phys_disk is a pointer to the hpsa_scsi_dev_t to which the + * i/o is destined. We need to store that here because the command + * may potentially encounter TASK SET FULL and need to be resubmitted + * For "normal" i/o's not using the "ioaccel" paths, phys_disk is + * not used. + */ + struct hpsa_scsi_dev_t *phys_disk; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 22cd3c7218b7da6245a3fd135ddba866314c588c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:21 -0500 Subject: [PATCH 270/889] hpsa: fix hpsa_figure_phys_disk_ptrs to handle layout_map_count other than 1 Squash this patch with hpsa-try-to-fix-ioaccel-cmd-accounting-code at some point Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4a97b3235aaa81..eae02a4bb09320 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1511,8 +1511,11 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, struct raid_map_data *map = &logical_drive->raid_map; struct raid_map_disk_data *dd = &map->data[0]; int i, j; - int nraid_map_entries = logical_drive->raid_map.data_disks_per_row + - logical_drive->raid_map.metadata_disks_per_row; + int nraid_map_entries = map->row_cnt * map->layout_map_count * + (map->data_disks_per_row + map->metadata_disks_per_row); + + if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) + nraid_map_entries = RAID_MAP_MAX_ENTRIES; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; From e3d59dca699018464ef1ac1fbf13addf9bbf49ab Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:22 -0500 Subject: [PATCH 271/889] hpsa: close race in ioaccel_cmds_out accounting Squash this patch into hpsa-try-to-fix-ioaccel-cmd-accounting-code eventually. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index eae02a4bb09320..73f18420fd8883 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3393,6 +3393,7 @@ void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, DRIVE_CMDS_RESERVED_FOR_FW; else dev->queue_depth = 7; /* conservative */ + atomic_set(&dev->ioaccel_cmds_out, 0); } static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) @@ -3744,8 +3745,8 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, BUG_ON(c->busaddr & 0x0000007F); /* Try to honor the device's queue depth */ - atomic_inc(&phys_disk->ioaccel_cmds_out); - if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; } @@ -3973,8 +3974,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, cp->IU_type = IOACCEL2_IU_TYPE; /* Try to honor the device's queue depth */ - atomic_inc(&phys_disk->ioaccel_cmds_out); - if (atomic_read(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; } From 7c8b2f0252c6d58e077b7b8220f3165f4eaeeea8 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:22 -0500 Subject: [PATCH 272/889] hpsa: guard against overflowing raid map array In the code that translates logical drive LBAs to physical drive LBAs if we overflow the raid map disk data array we will get the wrong answers. We do not expect that to happen, but best to be on the safe side and guard against it anyway. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 73f18420fd8883..fe7ca74d542a17 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4361,6 +4361,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; } + if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES)) + return IO_ACCEL_INELIGIBLE; + c->phys_disk = dev->phys_disk[map_index]; disk_handle = dd[map_index].ioaccel_handle; From b95416d90b9fe823329ced3a43f9377d8774114e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:23 -0500 Subject: [PATCH 273/889] hpsa: fix missing atomic_dec of dev->ioaccel_cmds_out Merge with earlier patches before submitting Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index fe7ca74d542a17..561fe6fdc84101 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2064,6 +2064,8 @@ static void complete_scsi_command(struct CommandList *cp) scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { + if (cp->cmd_type == CMD_IOACCEL1) + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); cmd_free(h, cp); cmd->scsi_done(cmd); return; From 48751f2abb60b7b0a34d55227b114280c6033cde Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:23 -0500 Subject: [PATCH 274/889] hpsa: do not ack controller events on controllers that do not support it Doing so can cause such controllers to lock up. Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 561fe6fdc84101..9d2f0302a63792 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7302,6 +7302,9 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) int i; char *event_type; + if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) + return; + /* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) && From b7d051d09f899e578ef3ccbe1e0678be0830befd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:24 -0500 Subject: [PATCH 275/889] hpsa: fix code that updates h->dev[]->phys_disk[] h->dev[]->phys_disk[] contains a map of the physical disks that make up each logical drive. When a RAID migration occurs, this map can change for a logical drive. We need to make sure it gets updated in a consistent way and that this mapping is not used until after it is finished being updated. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 26 +++++++++++++++++++++++--- drivers/scsi/hpsa.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9d2f0302a63792..19175bc2fa21d9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1163,6 +1163,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, h->dev[n] = device; h->ndevices++; + device->offload_to_be_enabled = device->offload_enabled; + device->offload_enabled = 0; added[*nadded] = device; (*nadded)++; @@ -1202,11 +1204,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, */ h->dev[entry]->raid_map = new_entry->raid_map; h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; - wmb(); /* ensure raid map updated prior to ->offload_enabled */ } h->dev[entry]->offload_config = new_entry->offload_config; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; - h->dev[entry]->offload_enabled = new_entry->offload_enabled; + + /* We can turn off ioaccel offload now, but need to delay turning + * it on until we can update h->dev[entry]->phys_disk[], but we + * can't do that until all the devices are updated. + */ + h->dev[entry]->offload_to_be_enabled = new_entry->offload_enabled; + if (!new_entry->offload_enabled) + h->dev[entry]->offload_enabled = 0; dev_info(&h->pdev->dev, "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", @@ -1241,6 +1249,8 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, new_entry->lun = h->dev[entry]->lun; } + new_entry->offload_to_be_enabled = new_entry->offload_enabled; + new_entry->offload_enabled = 0; h->dev[entry] = new_entry; added[*nadded] = new_entry; (*nadded)++; @@ -1661,6 +1671,14 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* but if it does happen, we just ignore that device */ } } + hpsa_update_log_drive_phys_drive_ptrs(h, h->dev, h->ndevices); + + /* Now that h->dev[]->phys_disk[] is coherent, we can enable + * any logical drives that need it enabled. + */ + for (i = 0; i < h->ndevices; i++) + h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled; + spin_unlock_irqrestore(&h->devlock, flags); /* Monitor devices which are in one of several NOT READY states to be @@ -2775,6 +2793,7 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h, this_device->offload_config = 0; this_device->offload_enabled = 0; + this_device->offload_to_be_enabled = 0; buf = kzalloc(64, GFP_KERNEL); if (!buf) @@ -2798,6 +2817,7 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h, if (hpsa_get_raid_map(h, scsi3addr, this_device)) this_device->offload_enabled = 0; } + this_device->offload_to_be_enabled = this_device->offload_enabled; out: kfree(buf); return; @@ -3102,6 +3122,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->raid_level = RAID_UNKNOWN; this_device->offload_config = 0; this_device->offload_enabled = 0; + this_device->offload_to_be_enabled = 0; this_device->volume_offline = 0; } @@ -3590,7 +3611,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } - hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent); adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index cff0aaf48229ba..4feb728d7ce404 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -54,6 +54,7 @@ struct hpsa_scsi_dev_t { u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ + int offload_to_be_enabled; int offload_to_mirror; /* Send next I/O accelerator RAID * offload request to mirror drive */ From 5e9e5796253f4ab1b35322d29e12cecf49a0bf2a Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:25 -0500 Subject: [PATCH 276/889] hpsa: Add support of HBA mode In set_encrypt_ioaccel2() and in hpsa_scsi_ioaccel_raid_map there were BUG_ONs that looked like this: BUG_ON(!(dev->offload_config && dev->offload_enabled)); But, In hpsa_ack_ctlr_events() we have this, /* Stop sending new RAID offload reqs via the IO accelerator */ scsi_block_requests(h->scsi_host); for (i = 0; i < h->ndevices; i++) h->dev[i]->offload_enabled = 0; hpsa_drain_accel_commands(h); So, we set offload_enabled = 0 for all drives, then do this drain_accel_commands, so that means accel commands could still be in flight, ie. perhaps having just been submitted into hpsa_scsi_ioaccel_raid_map concurrent with ->offload_enabled having just been set to zero. Get queue depth from identify physical bmic for physical disks Set the phys_disk value for a CommandList structure that is submitted. Squash this with an appropriate earlier patch when sent upstream. Signed-off-by: Stephen M. Cameron Signed-off-by: Joe Handzik --- drivers/scsi/hpsa.c | 47 ++++++++++++++++++++++----------------------- drivers/scsi/hpsa.h | 1 + 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 19175bc2fa21d9..6266f8472df64e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1205,6 +1205,11 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->raid_map = new_entry->raid_map; h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; } + if (new_entry->hba_ioaccel_enabled) { + h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; + wmb(); /* set ioaccel_handle *before* hba_ioaccel_eanbled */ + } + h->dev[entry]->hba_ioaccel_enabled = new_entry->hba_ioaccel_enabled; h->dev[entry]->offload_config = new_entry->offload_config; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; @@ -3123,6 +3128,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->offload_config = 0; this_device->offload_enabled = 0; this_device->offload_to_be_enabled = 0; + this_device->hba_ioaccel_enabled = 0; this_device->volume_offline = 0; } @@ -3404,6 +3410,8 @@ void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, (struct ext_report_lun_entry *) lunaddrbytes; dev->ioaccel_handle = rle->ioaccel_handle; + if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle) + dev->hba_ioaccel_enabled = 1; memset(id_phys, 0, sizeof(*id_phys)); rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, @@ -3564,28 +3572,21 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; case TYPE_DISK: - if (h->hba_mode_enabled) { - /* never use raid mapper in HBA mode */ - this_device->offload_enabled = 0; - ncurrent++; - break; - } else if (h->acciopath_status) { - if (i >= nphysicals) { - ncurrent++; - break; - } - } else { - if (i < nphysicals) - break; + if (i >= nphysicals) { ncurrent++; break; } - if (h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2) { - hpsa_get_ioaccel_drive_info(h, this_device, - lunaddrbytes, id_phys); - ncurrent++; - } + + if (h->hba_mode_enabled) + /* never use raid mapper in HBA mode */ + this_device->offload_enabled = 0; + else if (!(h->transMethod & CFGTBL_Trans_io_accel1 || + h->transMethod & CFGTBL_Trans_io_accel2)) + break; + + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); + ncurrent++; break; case TYPE_TAPE: case TYPE_MEDIUM_CHANGER: @@ -3837,6 +3838,8 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, struct scsi_cmnd *cmd = c->scsi_cmd; struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; + c->phys_disk = dev; + return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } @@ -3852,8 +3855,6 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, struct raid_map_data *map = &dev->raid_map; u64 first_block; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* Are we doing encryption on this device */ if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON)) return; @@ -4152,8 +4153,6 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, #endif int offload_to_mirror; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* check for valid opcode, get LBA and block count */ switch (cmd->cmnd[0]) { case WRITE_6: @@ -4562,7 +4561,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, cmd_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } - } else if (dev->ioaccel_handle) { + } else if (dev->hba_ioaccel_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 4feb728d7ce404..50523dbb9f71f7 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -55,6 +55,7 @@ struct hpsa_scsi_dev_t { int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ int offload_to_be_enabled; + int hba_ioaccel_enabled; int offload_to_mirror; /* Send next I/O accelerator RAID * offload request to mirror drive */ From e1a04321074e5632b0c99046157655113bfdc6c1 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Tue, 28 Oct 2014 11:51:25 -0500 Subject: [PATCH 277/889] hpsa: add ioaccel sg chaining for the ioaccel2 path Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 113 ++++++++++++++++++++++++++++++++++++++++---- drivers/scsi/hpsa.h | 1 + 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6266f8472df64e..3cf73bbb9c85a2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1815,6 +1815,46 @@ static void hpsa_slave_destroy(struct scsi_device *sdev) /* nothing to do. */ } +static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h) +{ + int i; + + if (!h->ioaccel2_cmd_sg_list) + return; + for (i = 0; i < h->nr_cmds; i++) { + kfree(h->ioaccel2_cmd_sg_list[i]); + h->ioaccel2_cmd_sg_list[i] = NULL; + } + kfree(h->ioaccel2_cmd_sg_list); + h->ioaccel2_cmd_sg_list = NULL; +} + +static int hpsa_allocate_ioaccel2_sg_chain_blocks(struct ctlr_info *h) +{ + int i; + + if (h->chainsize <= 0) + return 0; + + h->ioaccel2_cmd_sg_list = + kzalloc(sizeof(*h->ioaccel2_cmd_sg_list) * h->nr_cmds, + GFP_KERNEL); + if (!h->ioaccel2_cmd_sg_list) + return -ENOMEM; + for (i = 0; i < h->nr_cmds; i++) { + h->ioaccel2_cmd_sg_list[i] = + kmalloc(sizeof(*h->ioaccel2_cmd_sg_list[i]) * + h->maxsgentries, GFP_KERNEL); + if (!h->ioaccel2_cmd_sg_list[i]) + goto clean; + } + return 0; + +clean: + hpsa_free_ioaccel2_sg_chain_blocks(h); + return -ENOMEM; +} + static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -1853,6 +1893,39 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) return -ENOMEM; } +static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h, + struct io_accel2_cmd *cp, struct CommandList *c) +{ + struct ioaccel2_sg_element *chain_block; + u64 temp64; + u32 chain_size; + + chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex]; + chain_size = le32_to_cpu(cp->data_len); + temp64 = pci_map_single(h->pdev, chain_block, chain_size, + PCI_DMA_TODEVICE); + if (dma_mapping_error(&h->pdev->dev, temp64)) { + /* prevent subsequent unmapping */ + cp->sg->address = 0; + return -1; + } + cp->sg->address = (u64) cpu_to_le64(temp64); + return 0; +} + +static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h, + struct io_accel2_cmd *cp) +{ + struct ioaccel2_sg_element *chain_sg; + u64 temp64; + u32 chain_size; + + chain_sg = cp->sg; + temp64 = le64_to_cpu(chain_sg->address); + chain_size = le32_to_cpu(cp->data_len); + pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE); +} + static int hpsa_map_sg_chain_block(struct ctlr_info *h, struct CommandList *c) { @@ -1995,6 +2068,9 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + if (c2->sg[0].chain_indicator == IOACCEL2_CHAIN) + hpsa_unmap_ioaccel2_sg_chain_block(h, c2); + atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ @@ -3977,10 +4053,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, u32 len; u32 total_len = 0; - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { - atomic_dec(&phys_disk->ioaccel_cmds_out); - return IO_ACCEL_INELIGIBLE; - } + BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); if (fixup_ioaccel_cdb(cdb, &cdb_len)) { atomic_dec(&phys_disk->ioaccel_cmds_out); @@ -4010,8 +4083,18 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } if (use_sg) { - BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES); curr_sg = cp->sg; + if (use_sg > h->ioaccel_maxsg) { + addr64 = h->ioaccel2_cmd_sg_list[c->cmdindex]->address; + curr_sg->address = cpu_to_le64(addr64); + curr_sg->length = 0; + curr_sg->reserved[0] = 0; + curr_sg->reserved[1] = 0; + curr_sg->reserved[2] = 0; + curr_sg->chain_indicator = 0x80; + + curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex]; + } scsi_for_each_sg(cmd, sg, use_sg, i) { addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); @@ -4056,14 +4139,23 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; memcpy(cp->cdb, cdb, sizeof(cp->cdb)); - /* fill in sg elements */ - cp->sg_count = (u8) use_sg; - cp->data_len = cpu_to_le32(total_len); cp->err_ptr = cpu_to_le64(c->busaddr + offsetof(struct io_accel2_cmd, error_data)); cp->err_len = cpu_to_le32((u32) sizeof(cp->error_data)); + /* fill in sg elements */ + if (use_sg > h->ioaccel_maxsg) { + cp->sg_count = 1; + if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + scsi_dma_unmap(cmd); + return -1; + } + } else { + cp->sg_count = (u8) use_sg; + } + enqueue_cmd_and_start_io(h, c); return 0; } @@ -7208,6 +7300,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_irqs_and_disable_msix(h); hpsa_free_sg_chain_blocks(h); + hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); kfree(h->ioaccel1_blockFetchTable); kfree(h->blockFetchTable); @@ -7795,6 +7888,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) iounmap(h->cfgtable); hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); + hpsa_free_ioaccel2_sg_chain_blocks(h); pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct CommandList), h->cmd_pool, h->cmd_pool_dhandle); @@ -8103,6 +8197,9 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) (h->ioaccel2_blockFetchTable == NULL)) goto clean_up; + if (hpsa_allocate_ioaccel2_sg_chain_blocks(h)) + goto clean_up; + memset(h->ioaccel2_cmd_pool, 0, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool)); return 0; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 50523dbb9f71f7..109e6e70ea5be0 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -162,6 +162,7 @@ struct ctlr_info { u8 max_cmd_sg_entries; int chainsize; struct SGDescriptor **cmd_sg_list; + struct ioaccel2_sg_element **ioaccel2_cmd_sg_list; /* pointers to command and error info pool */ struct CommandList *cmd_pool; From edb8a8f8d168a0805c18e86bacc86cf58880c142 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Tue, 28 Oct 2014 11:51:26 -0500 Subject: [PATCH 278/889] hpsa: unmap ioaccel2 commands before, not after adding to resubmit workqueue The command could get thrown onto a work queue before we'd hit the unmap. Squash with the appropriate earlier patch (likely the larger scatter gather command support patch). Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3cf73bbb9c85a2..0626d08f5799a8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2068,9 +2068,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - if (c2->sg[0].chain_indicator == IOACCEL2_CHAIN) - hpsa_unmap_ioaccel2_sg_chain_block(h, c2); - atomic_dec(&c->phys_disk->ioaccel_cmds_out); /* check for good status */ @@ -2139,6 +2136,7 @@ static void complete_scsi_command(struct CommandList *cp) struct ctlr_info *h; struct ErrorInfo *ei; struct hpsa_scsi_dev_t *dev; + struct io_accel2_cmd *c2; int sense_key; int asc; /* additional sense code */ @@ -2149,12 +2147,17 @@ static void complete_scsi_command(struct CommandList *cp) cmd = cp->scsi_cmd; h = cp->h; dev = cmd->device->hostdata; + c2 = &h->ioaccel2_cmd_pool[cp->cmdindex]; scsi_dma_unmap(cmd); /* undo the DMA mappings */ if ((cp->cmd_type == CMD_SCSI) && (cp->Header.SGTotal > h->max_cmd_sg_entries)) hpsa_unmap_sg_chain_block(h, cp); + if ((cp->cmd_type == CMD_IOACCEL2) && + (c2->sg[0].chain_indicator == IOACCEL2_CHAIN)) + hpsa_unmap_ioaccel2_sg_chain_block(h, c2); + cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ From 9f9effed49487df078fa6cdd211cbdb9072dd515 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Tue, 28 Oct 2014 11:51:26 -0500 Subject: [PATCH 279/889] hpsa: add more ioaccel2 error handling, including underrun statuses. Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 ++++++++++++++++++++++++++++----- drivers/scsi/hpsa_cmd.h | 6 ++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0626d08f5799a8..cd6ecdfcc6dd0c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1975,6 +1975,7 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, { int data_len; int retry = 0; + u32 ioaccel2_resid = 0; switch (c2->error_data.serv_response) { case IOACCEL2_SERV_RESPONSE_COMPLETE: @@ -2033,11 +2034,33 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, } break; case IOACCEL2_SERV_RESPONSE_FAILURE: - /* don't expect to get here. */ - dev_warn(&h->pdev->dev, - "unexpected delivery or target failure, status = 0x%02x\n", - c2->error_data.status); - retry = 1; + switch (c2->error_data.status) { + case IOACCEL2_STATUS_SR_IO_ERROR: + case IOACCEL2_STATUS_SR_IO_ABORTED: + case IOACCEL2_STATUS_SR_OVERRUN: + retry = 1; + break; + case IOACCEL2_STATUS_SR_UNDERRUN: + cmd->result = (DID_OK << 16); /* host byte */ + cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + ioaccel2_resid = c2->error_data.resid_cnt[3] << 24; + ioaccel2_resid |= c2->error_data.resid_cnt[2] << 16; + ioaccel2_resid |= c2->error_data.resid_cnt[1] << 8; + ioaccel2_resid |= c2->error_data.resid_cnt[0]; + scsi_set_resid(cmd, ioaccel2_resid); + break; + case IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE: + case IOACCEL2_STATUS_SR_INVALID_DEVICE: + case IOACCEL2_STATUS_SR_IOACCEL_DISABLED: + /* We will get an event from ctlr to trigger rescan */ + retry = 1; + break; + default: + retry = 1; + dev_warn(&h->pdev->dev, + "unexpected delivery or target failure, status = 0x%02x\n", + c2->error_data.status); + } break; case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: break; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 0bbe7c1acb44b1..2984d236fb888f 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -526,6 +526,12 @@ struct io_accel2_scsi_response { #define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28 #define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40 #define IOACCEL2_STATUS_SR_IOACCEL_DISABLED 0x0E +#define IOACCEL2_STATUS_SR_IO_ERROR 0x01 +#define IOACCEL2_STATUS_SR_IO_ABORTED 0x02 +#define IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE 0x03 +#define IOACCEL2_STATUS_SR_INVALID_DEVICE 0x04 +#define IOACCEL2_STATUS_SR_UNDERRUN 0x51 +#define IOACCEL2_STATUS_SR_OVERRUN 0x75 u8 data_present; /* low 2 bits */ #define IOACCEL2_NO_DATAPRESENT 0x000 #define IOACCEL2_RESPONSE_DATAPRESENT 0x001 From 5d9be877d6b1b36ec42a262c615ee7ab2d5c949b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:27 -0500 Subject: [PATCH 280/889] hpsa bump driver version again --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cd6ecdfcc6dd0c..ef551d9d63d4e0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.6-0" +#define HPSA_DRIVER_VERSION "3.4.8-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" From 1bb073542807bdfcc95f3a1e20c196dc935ebec0 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:27 -0500 Subject: [PATCH 281/889] hpsa: do not check cmd_alloc return value - it cannnot return NULL cmd_alloc can no longer return NULL, so don't check for NULL any more (which is unreachable code). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 77 +++++++++------------------------------------ 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ef551d9d63d4e0..92aed65da59157 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2584,11 +2584,6 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } - if (fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD)) { rc = -1; @@ -2618,11 +2613,6 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } - if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize, page, scsi3addr, TYPE_CMD)) { rc = -1; @@ -2640,7 +2630,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, out: cmd_free(h, c); return rc; - } +} static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, u8 reset_type) @@ -2650,10 +2640,6 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } /* fill_cmd can't fail here, no data buffer to map. */ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, @@ -2783,10 +2769,7 @@ static int hpsa_get_raid_map(struct ctlr_info *h, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } + if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { @@ -2959,10 +2942,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, struct ErrorInfo *ei; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -1; - } + /* address the controller */ memset(scsi3addr, 0, sizeof(scsi3addr)); if (fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h, @@ -3076,8 +3056,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, #define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02 c = cmd_alloc(h); - if (!c) - return 0; + (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (rc) { @@ -3150,8 +3129,7 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, return 1; c = cmd_alloc(h); - if (!c) - return -ENOMEM; + (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); /* no unmap needed here because no data xfer. */ @@ -4767,10 +4745,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } + if (unlikely(lockup_detected(h))) { cmd->result = DID_ERROR << 16; cmd_free(h, c); @@ -5017,11 +4992,6 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, struct CommandList *c; c = cmd_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "out of memory in " - "wait_for_device_to_become_ready.\n"); - return IO_ERROR; - } /* Send test unit ready until device ready, or give up. */ while (count < HPSA_TUR_RETRY_LIMIT) { @@ -5160,10 +5130,6 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, u32 tagupper, taglower; c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return -ENOMEM; - } /* fill_cmd can't fail here, no buffer to map */ (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag, @@ -5424,6 +5390,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track * which ones are free or in use. Lock must be held when calling this. * cmd_free() is the complement. + * This function never gives up and returns NULL. If it hangs, + * another thread must call cmd_free() to free some tags. */ static struct CommandList *cmd_alloc(struct ctlr_info *h) { @@ -5654,10 +5622,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) } } c = cmd_alloc(h); - if (c == NULL) { - rc = -ENOMEM; - goto out_kfree; - } + /* Fill in the command type */ c->cmd_type = CMD_IOCTL_PEND; /* Fill in Command Header */ @@ -5792,10 +5757,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) sg_used++; } c = cmd_alloc(h); - if (c == NULL) { - status = -ENOMEM; - goto cleanup1; - } + c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; c->Header.SGList = (u8) sg_used; @@ -5907,14 +5869,13 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) } } -static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, +static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, u8 reset_type) { struct CommandList *c; c = cmd_alloc(h); - if (!c) - return -ENOMEM; + /* fill_cmd can't fail here, no data buffer to map */ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, RAID_CTLR_LUNID, TYPE_MSG); @@ -5925,7 +5886,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, * the command either. This is the last command we will send before * re-initializing everything, so it doesn't matter and won't leak. */ - return 0; + return; } static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, @@ -7254,11 +7215,7 @@ static int hpsa_request_irq(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { - if (hpsa_send_host_reset(h, RAID_CTLR_LUNID, - HPSA_RESET_TYPE_CONTROLLER)) { - dev_warn(&h->pdev->dev, "Resetting array controller failed.\n"); - return -EIO; - } + hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { @@ -7846,10 +7803,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) return; c = cmd_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - goto out_of_memory; - } + if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, RAID_CTLR_LUNID, TYPE_CMD)) { goto out; @@ -7863,7 +7817,6 @@ static void hpsa_flush_cache(struct ctlr_info *h) dev_warn(&h->pdev->dev, "error flushing cache on controller\n"); cmd_free(h, c); -out_of_memory: kfree(flush_buf); } From 0e268eeb304644a0a26cd4d934715d68e10e47cf Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:28 -0500 Subject: [PATCH 282/889] hpsa: hpsa-return-ENOMEM-on-memory-allocation-failure fill_cmd can only fail if pci_map_single fails. return -ENOMEM not 1 from ioaccel2_alloc_cmds_and_bft on allocation failure hpsa return ENOMEM not -1 from hpsa_alloc_ioaccel_cmd_and_bft on alloc failure hpsa: return -ENOMEM not -EFAULT from hpsa_passthru_ioctl on kmalloc failure Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 92aed65da59157..193baf993920ab 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2773,9 +2773,9 @@ static int hpsa_get_raid_map(struct ctlr_info *h, if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { - dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - rc = -ENOMEM; - goto out; + dev_warn(&h->pdev->dev, "hpsa_get_raid_map fill_cmd failed\n"); + cmd_free(h, c); + return -1; } rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, NO_TIMEOUT); @@ -5609,7 +5609,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) if (iocommand.buf_size > 0) { buff = kmalloc(iocommand.buf_size, GFP_KERNEL); if (buff == NULL) - return -EFAULT; + return -ENOMEM; if (iocommand.Request.Type.Direction & XFER_WRITE) { /* Copy the data into the buffer we created */ if (copy_from_user(buff, iocommand.buf, @@ -8149,7 +8149,7 @@ static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); kfree(h->ioaccel1_blockFetchTable); - return 1; + return -ENOMEM; } static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) @@ -8189,7 +8189,7 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); kfree(h->ioaccel2_blockFetchTable); - return 1; + return -ENOMEM; } static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) From 068cc0e95e6b4525f10effc9a32f504bdbeef525 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:29 -0500 Subject: [PATCH 283/889] hpsa: pass error from pci_set_consistent_dma_mask intact from hpsa_message Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 193baf993920ab..b989fe43757ec4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6270,7 +6270,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { iounmap(vaddr); - return -ENOMEM; + return err; } cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64); From cd9315cac3731241450153ce6bdc4d589ba39b5c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:29 -0500 Subject: [PATCH 284/889] hpsa: trivial message and comment clean ups Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b989fe43757ec4..8f447da34ad120 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6547,7 +6547,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become ready " + "Failed waiting for board to become ready " "after hard reset\n"); goto unmap_cfgtable; } @@ -6658,7 +6658,7 @@ static void hpsa_disable_interrupt_mode(struct ctlr_info *h) } /* If MSI/MSI-X is supported by the kernel we will try to enable it on - * controllers that are capable. If not, we use IO-APIC mode. + * controllers that are capable. If not, we use legacy INTx mode. */ static void hpsa_interrupt_mode(struct ctlr_info *h) { @@ -6676,7 +6676,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - dev_info(&h->pdev->dev, "MSIX\n"); + dev_info(&h->pdev->dev, "MSI-X capable controller\n"); h->msix_vector = MAX_REPLY_QUEUES; if (h->msix_vector > num_online_cpus()) h->msix_vector = num_online_cpus(); @@ -6697,7 +6697,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) } single_msi_mode: if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { - dev_info(&h->pdev->dev, "MSI\n"); + dev_info(&h->pdev->dev, "MSI capable controller\n"); if (!pci_enable_msi(h->pdev)) h->msi_vector = 1; else @@ -6871,7 +6871,7 @@ static void hpsa_find_board_params(struct ctlr_info *h) static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) { if (!check_signature(h->cfgtable->Signature, "CISS", 4)) { - dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); + dev_err(&h->pdev->dev, "not a valid CISS config table\n"); return false; } return true; @@ -6963,7 +6963,7 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) h->transMethod = CFGTBL_Trans_Simple; return 0; error: - dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + dev_err(&h->pdev->dev, "failed to enter simple mode\n"); return -ENODEV; } @@ -8037,8 +8037,8 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { - dev_warn(&h->pdev->dev, "unable to get board into" - " performant mode\n"); + dev_err(&h->pdev->dev, + "performant mode problem - transport not active\n"); return; } /* Change the access methods to the performant access methods */ From 9736fc468b2d7836c35fee5f87d05252bd060177 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:30 -0500 Subject: [PATCH 285/889] hpsa: detect and report failures changing controller transport modes Detect failues when attempting to change controller to use simple or performant transport modes (mode change ack) rather than just proceeding ahead after timeouts. Return values are added to: hpsa_put_ctlr_into_performant_mode hpsa_wait_for_mode_change_ack and all their callers check/propagate the result. More consistency in printing errors and whether dev_err is used. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8f447da34ad120..328e3ed12c2c0a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -239,7 +239,7 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr, int wait_for_ready); static inline void finish_cmd(struct CommandList *c); -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h); +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h); #define BOARD_NOT_READY 0 #define BOARD_READY 1 static void hpsa_drain_accel_commands(struct ctlr_info *h); @@ -489,7 +489,7 @@ static ssize_t host_store_hpsa_intcoal_delay(struct device *dev, writel(value, &h->cfgtable->HostWrite.CoalIntDelay); print_cfg_table(&h->pdev->dev, h->cfgtable); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + (void) hpsa_wait_for_mode_change_ack(h); print_cfg_table(&h->pdev->dev, h->cfgtable); return count; } @@ -516,7 +516,7 @@ static ssize_t host_store_hpsa_intcoal_count(struct device *dev, writel(value, &h->cfgtable->HostWrite.CoalIntCount); print_cfg_table(&h->pdev->dev, h->cfgtable); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + (void) hpsa_wait_for_mode_change_ack(h); print_cfg_table(&h->pdev->dev, h->cfgtable); return count; } @@ -6904,7 +6904,7 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } -static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) +static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6915,13 +6915,16 @@ static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) - break; + goto done; /* delay and try again */ msleep(20); } + return -ENODEV; +done: + return 0; } -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6936,12 +6939,16 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) - break; + goto done; /* delay and try again */ usleep_range(10000, 20000); } + return -ENODEV; +done: + return 0; } +/* return -ENODEV or other reason on error, 0 on success */ static int hpsa_enter_simple_mode(struct ctlr_info *h) { u32 trans_support; @@ -6956,7 +6963,8 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) + goto error; print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) goto error; @@ -7941,7 +7949,8 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) +/* return -ENODEV or other reason on error, 0 on success */ +static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) { int i; unsigned long register_value; @@ -8033,13 +8042,17 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - doorbell timeout\n"); + return -ENODEV; + } print_cfg_table(&h->pdev->dev, h->cfgtable); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_err(&h->pdev->dev, "performant mode problem - transport not active\n"); - return; + return -ENODEV; } /* Change the access methods to the performant access methods */ h->access = access; @@ -8047,7 +8060,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) if (!((trans_support & CFGTBL_Trans_io_accel1) || (trans_support & CFGTBL_Trans_io_accel2))) - return; + return 0; if (trans_support & CFGTBL_Trans_io_accel1) { /* Set up I/O accelerator mode */ @@ -8109,8 +8122,13 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) writel(bft2[i], &h->ioaccel2_bft2_regs[i]); } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - enabling ioaccel mode\n"); + return -ENODEV; + } print_cfg_table(&h->pdev->dev, h->cfgtable); + return 0; } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) From 223e72a5f1c8b61db2ec86b79c287f0eab41baaf Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:30 -0500 Subject: [PATCH 286/889] hpsa: rename free_irqs to hpsa_free_irqs and move before hpsa_request_irq replace calls to hpsa_free_irqs_and_disable_msix with two calls to hpsa_free_irqs and hpsa_disable_interrupt_mode on failure of request_irq, free the irqs that we did get Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 74 +++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 328e3ed12c2c0a..3b426c4353adc9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7181,7 +7181,27 @@ static void hpsa_irq_affinity_hints(struct ctlr_info *h) } } -static int hpsa_request_irq(struct ctlr_info *h, +/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */ +static void hpsa_free_irqs(struct ctlr_info *h) +{ + int i; + + if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { + /* Single reply queue, only one irq to free */ + i = h->intr_mode; + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + return; + } + + for (i = 0; i < h->msix_vector; i++) { + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + } +} + +/* returns 0 on success; cleans up and returns -Enn on error */ +static int hpsa_request_irqs(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) { @@ -7214,8 +7234,9 @@ static int hpsa_request_irq(struct ctlr_info *h, } } if (rc) { - dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", + dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", h->intr[h->intr_mode], h->devname); + hpsa_free_irqs(h); return -ENODEV; } return 0; @@ -7241,38 +7262,6 @@ static int hpsa_kdump_soft_reset(struct ctlr_info *h) return 0; } -static void free_irqs(struct ctlr_info *h) -{ - int i; - - if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { - /* Single reply queue, only one irq to free */ - i = h->intr_mode; - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - return; - } - - for (i = 0; i < h->msix_vector; i++) { - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - } -} - -static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) -{ - free_irqs(h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) { - if (h->pdev->msix_enabled) - pci_disable_msix(h->pdev); - } else if (h->msi_vector) { - if (h->pdev->msi_enabled) - pci_disable_msi(h->pdev); - } -#endif /* CONFIG_PCI_MSI */ -} - static void hpsa_free_reply_queues(struct ctlr_info *h) { int i; @@ -7289,7 +7278,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { - hpsa_free_irqs_and_disable_msix(h); + hpsa_free_irqs(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); @@ -7302,6 +7291,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) iounmap(h->transtable); if (h->cfgtable) iounmap(h->cfgtable); + hpsa_disable_interrupt_mode(h); pci_disable_device(h->pdev); pci_release_regions(h->pdev); kfree(h); @@ -7686,7 +7676,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) + if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) goto clean2; dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, @@ -7722,8 +7712,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irqs(h); - rc = hpsa_request_irq(h, hpsa_msix_discard_completions, + hpsa_free_irqs(h); + rc = hpsa_request_irqs(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { dev_warn(&h->pdev->dev, @@ -7786,7 +7776,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - free_irqs(h); + hpsa_free_irqs(h); clean2: clean1: if (h->resubmit_wq) @@ -7839,7 +7829,8 @@ static void hpsa_shutdown(struct pci_dev *pdev) */ hpsa_flush_cache(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); - hpsa_free_irqs_and_disable_msix(h); + hpsa_free_irqs(h); + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } static void hpsa_free_device_info(struct ctlr_info *h) @@ -7868,7 +7859,10 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ + + /* includes hpsa_free_irqs and hpsa_disable_interrupt_mode */ hpsa_shutdown(pdev); + destroy_workqueue(h->resubmit_wq); iounmap(h->vaddr); iounmap(h->transtable); From 99656b9b031557d212d25de292b9e6bb59fbdbc3 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:31 -0500 Subject: [PATCH 287/889] hpsa: make hpsa_pci_init disable interrupts and pci_disable_device on critical failures Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3b426c4353adc9..94c184d5d9203a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7014,17 +7014,18 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_request_regions(h->pdev, HPSA); if (err) { dev_err(&h->pdev->dev, - "cannot obtain PCI resources, aborting\n"); - return err; + "failed to obtain PCI resources\n"); + goto clean1; /* pci */ } hpsa_interrupt_mode(h); err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); if (err) - goto err_out_free_res; + goto clean2; /* intmode+region, pci */ h->vaddr = remap_pci_mem(h->paddr, 0x250); if (!h->vaddr) { + dev_err(&h->pdev->dev, "failed to remap PCI mem\n"); err = -ENOMEM; - goto err_out_free_res; + goto clean2; /* intmode+region, pci */ } err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); if (err) @@ -7052,8 +7053,11 @@ static int hpsa_pci_init(struct ctlr_info *h) iounmap(h->cfgtable); if (h->vaddr) iounmap(h->vaddr); - pci_disable_device(h->pdev); +clean2: + hpsa_disable_interrupt_mode(h); pci_release_regions(h->pdev); +clean1: + pci_disable_device(h->pdev); return err; } From c4ec99539f4f535ee842edbc32358bce97895b91 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:32 -0500 Subject: [PATCH 288/889] hpsa: avoid unneccesary calls to resource freeing functions in hpsa_init_one If hpsa_allocate_cmd_pool failed, we were calling two functions unnecessarily: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); This didn't cause any problem, as those functions can tolerate being called when what they free hasn't been allocated (relevant pointers would be NULL) but it is potentially confusing. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 94c184d5d9203a..ae565d164e246e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7685,8 +7685,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - if (hpsa_allocate_cmd_pool(h)) - goto clean4; + rc = hpsa_allocate_cmd_pool(h); + if (rc) + goto clean2_and_free_irqs; if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); @@ -7780,6 +7781,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); +clean2_and_free_irqs: hpsa_free_irqs(h); clean2: clean1: From 26a52386df2df26bf486ff3a4b9c1eaae5308c6d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:32 -0500 Subject: [PATCH 289/889] hpsa: add hpsa_free_cfgtables function to undo what hpsa_find_cfgtables does Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ae565d164e246e..abb994d420ca2a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6790,6 +6790,15 @@ static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, return 0; } +static void hpsa_free_cfgtables(struct ctlr_info *h) +{ + iounmap(h->transtable); + iounmap(h->cfgtable); +} + +/* Find and map CISS config table and transfer table ++ * several items must be unmapped (freed) later ++ * */ static int hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; @@ -6814,8 +6823,11 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) h->transtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index)+cfg_offset+trans_offset, sizeof(*h->transtable)); - if (!h->transtable) + if (!h->transtable) { + dev_err(&h->pdev->dev, "Failed mapping transfer table\n"); + hpsa_free_cfgtables(h); return -ENOMEM; + } return 0; } @@ -7289,15 +7301,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) kfree(h->ioaccel1_blockFetchTable); kfree(h->blockFetchTable); hpsa_free_reply_queues(h); - if (h->vaddr) - iounmap(h->vaddr); - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - hpsa_disable_interrupt_mode(h); + hpsa_free_cfgtables(h); /* pci_init 4 */ + iounmap(h->vaddr); /* pci_init 3 */ + hpsa_disable_interrupt_mode(h); /* pci_init 2 */ pci_disable_device(h->pdev); - pci_release_regions(h->pdev); + pci_release_regions(h->pdev); /* pci_init 2 */ kfree(h); } From 7a2432f6fbc0b821566ab44f8a636a6391cec0ee Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:33 -0500 Subject: [PATCH 290/889] hpsa: report failure to ioremap config table Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron make hpsa_remove_one use hpsa_pci_free_init instead of individually releasing various things Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index abb994d420ca2a..abb4a446f80fb0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6813,8 +6813,10 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); - if (!h->cfgtable) + if (!h->cfgtable) { + dev_err(&h->pdev->dev, "Failed mapping cfgtable\n"); return -ENOMEM; + } rc = write_driver_ver_to_cfgtable(h->cfgtable); if (rc) return rc; @@ -7016,7 +7018,7 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_enable_device(h->pdev); if (err) { - dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); + dev_err(&h->pdev->dev, "failed to enable PCI device\n"); return err; } @@ -7041,34 +7043,31 @@ static int hpsa_pci_init(struct ctlr_info *h) } err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); if (err) - goto err_out_free_res; + goto clean3; /* vaddr, intmode+region, pci */ err = hpsa_find_cfgtables(h); if (err) - goto err_out_free_res; + goto clean3; /* vaddr, intmode+region, pci */ hpsa_find_board_params(h); if (!hpsa_CISS_signature_present(h)) { err = -ENODEV; - goto err_out_free_res; + goto clean4; /* cfgtables, vaddr, intmode+region, pci */ } hpsa_set_driver_support_bits(h); hpsa_p600_dma_prefetch_quirk(h); err = hpsa_enter_simple_mode(h); if (err) - goto err_out_free_res; + goto clean4; /* cfgtables, vaddr, intmode+region, pci */ return 0; -err_out_free_res: - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - if (h->vaddr) - iounmap(h->vaddr); -clean2: +clean4: /* cfgtables, vaddr, intmode+region, pci */ + hpsa_free_cfgtables(h); +clean3: /* vaddr, intmode+region, pci */ + iounmap(h->vaddr); +clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); pci_release_regions(h->pdev); -clean1: +clean1: /* pci */ pci_disable_device(h->pdev); return err; } @@ -7681,7 +7680,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean1; + goto clean2; } } @@ -7792,6 +7791,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean2_and_free_irqs: hpsa_free_irqs(h); clean2: + hpsa_free_pci_init(h); clean1: if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); @@ -7874,13 +7874,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) spin_unlock_irqrestore(&h->lock, flags); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ - /* includes hpsa_free_irqs and hpsa_disable_interrupt_mode */ + /* includes hpsa_free_irqs */ + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ hpsa_shutdown(pdev); destroy_workqueue(h->resubmit_wq); - iounmap(h->vaddr); - iounmap(h->transtable); - iounmap(h->cfgtable); hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); @@ -7896,8 +7894,10 @@ static void hpsa_remove_one(struct pci_dev *pdev) kfree(h->ioaccel1_blockFetchTable); kfree(h->ioaccel2_blockFetchTable); kfree(h->hba_inquiry_data); - pci_disable_device(pdev); - pci_release_regions(pdev); + + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ + hpsa_free_pci_init(h); + free_percpu(h->lockup_detected); kfree(h); } From c81b59c39cc44c11cf7b23aadb89e75e7b164e79 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:33 -0500 Subject: [PATCH 291/889] hpsa: rename hpsa_alloc_ioaccel_cmd_and_bft to hpsa_alloc_ioaccel1_cmd_and_bft in order to differentiate it from hpsa_alloc_ioaccel2_cmd_and_bft Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index abb4a446f80fb0..ce1cf8c8a9ed2e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8139,7 +8139,8 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) return 0; } -static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) +/* Allocate ioaccel1 mode command blocks and block fetch table */ +static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) { h->ioaccel_maxsg = readl(&(h->cfgtable->io_accel_max_embedded_sg_count)); @@ -8236,7 +8237,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (trans_support & CFGTBL_Trans_io_accel1) { transMethod |= CFGTBL_Trans_io_accel1 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel_cmd_and_bft(h)) + if (hpsa_alloc_ioaccel1_cmd_and_bft(h)) goto clean_up; } else { if (trans_support & CFGTBL_Trans_io_accel2) { From 3e3a67026282816a6bf0288d1a18303f533bc513 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:34 -0500 Subject: [PATCH 292/889] hpsa: rename hpsa_allocate_cmd_pool to hpsa_alloc_cmd_pool Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ce1cf8c8a9ed2e..19e579d8776b9d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7142,7 +7142,7 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) return rc; } -static int hpsa_allocate_cmd_pool(struct ctlr_info *h) +static int hpsa_alloc_cmd_pool(struct ctlr_info *h) { h->cmd_pool_bits = kzalloc( DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * @@ -7692,7 +7692,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - rc = hpsa_allocate_cmd_pool(h); + rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean2_and_free_irqs; if (hpsa_allocate_sg_chain_blocks(h)) From f64ff78294d09235acacc58dcbad81a3c8176611 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:34 -0500 Subject: [PATCH 293/889] hpsa: rename ioaccel2_alloc_cmds_and_bft to hpsa_alloc_ioaccel2_cmd_and_bft Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 19e579d8776b9d..7fd3a443957c6d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8179,7 +8179,8 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } -static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) +/* Allocate ioaccel2 mode command blocks and block fetch table */ +static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { /* Allocate ioaccel2 mode command blocks and block fetch table */ @@ -8243,7 +8244,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (trans_support & CFGTBL_Trans_io_accel2) { transMethod |= CFGTBL_Trans_io_accel2 | CFGTBL_Trans_enable_directed_msix; - if (ioaccel2_alloc_cmds_and_bft(h)) + if (hpsa_alloc_ioaccel2_cmd_and_bft(h)) goto clean_up; } } From d6bccbf0cc50c6d0536072f229f24977b6c7b374 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:35 -0500 Subject: [PATCH 294/889] hpsa: separate hpsa_free_cmd_pool into three separate function hpsa_free_cmd_pool to free the cmd_pool_bits and cmd_pool hpsa_free_ioaccel1_cmd_and_bft for the ioaccel1 stuff hpsa_free_ioaccel2_cmd_and_bft for the ioaccel2 stuff Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 95 +++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7fd3a443957c6d..89115dec7126f0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -229,6 +229,8 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); +static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, @@ -7142,6 +7144,20 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) return rc; } +static void hpsa_free_cmd_pool(struct ctlr_info *h) +{ + kfree(h->cmd_pool_bits); + if (h->cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct CommandList), + h->cmd_pool, h->cmd_pool_dhandle); + if (h->errinfo_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct ErrorInfo), + h->errinfo_pool, + h->errinfo_pool_dhandle); +} + static int hpsa_alloc_cmd_pool(struct ctlr_info *h) { h->cmd_pool_bits = kzalloc( @@ -7163,28 +7179,6 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h) return 0; } -static void hpsa_free_cmd_pool(struct ctlr_info *h) -{ - kfree(h->cmd_pool_bits); - if (h->cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - if (h->ioaccel2_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), - h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); - if (h->errinfo_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, - h->errinfo_pool_dhandle); - if (h->ioaccel_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct io_accel1_cmd), - h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); -} - static void hpsa_irq_affinity_hints(struct ctlr_info *h) { int i, cpu, rc; @@ -7297,9 +7291,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - kfree(h->ioaccel1_blockFetchTable); - kfree(h->blockFetchTable); - hpsa_free_reply_queues(h); + kfree(h->blockFetchTable); /* perf 2 */ + hpsa_free_reply_queues(h); /* perf 1 */ + hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ + hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ @@ -7788,6 +7783,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); clean2_and_free_irqs: hpsa_free_irqs(h); clean2: @@ -7882,17 +7879,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); hpsa_free_sg_chain_blocks(h); hpsa_free_ioaccel2_sg_chain_blocks(h); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, h->errinfo_pool_dhandle); - hpsa_free_reply_queues(h); - kfree(h->cmd_pool_bits); - kfree(h->blockFetchTable); - kfree(h->ioaccel1_blockFetchTable); - kfree(h->ioaccel2_blockFetchTable); + kfree(h->blockFetchTable); /* perf 2 */ + hpsa_free_reply_queues(h); /* perf 1 */ + hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ + hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ kfree(h->hba_inquiry_data); /* includes hpsa_disable_interrupt_mode - pci_init 2 */ @@ -8139,6 +8130,16 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) return 0; } +/* Free ioaccel1 mode command blocks and block fetch table */ +static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h) +{ + if (h->ioaccel_cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), + h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); + kfree(h->ioaccel1_blockFetchTable); +} + /* Allocate ioaccel1 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) { @@ -8171,14 +8172,20 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) return 0; clean_up: - if (h->ioaccel_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), - h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); - kfree(h->ioaccel1_blockFetchTable); + hpsa_free_ioaccel1_cmd_and_bft(h); return -ENOMEM; } +/* Free ioaccel2 mode command blocks and block fetch table */ +static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) +{ + if (h->ioaccel2_cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), + h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); + kfree(h->ioaccel2_blockFetchTable); +} + /* Allocate ioaccel2 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { @@ -8212,11 +8219,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return 0; clean_up: - if (h->ioaccel2_cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), - h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); - kfree(h->ioaccel2_blockFetchTable); + hpsa_free_ioaccel2_cmd_and_bft(h); return -ENOMEM; } From 9d0dd4222c7982b981a8473535b557e2f89cbcce Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:36 -0500 Subject: [PATCH 295/889] hpsa: fix memory leak in hpsa_alloc_cmd_pool Partial allocation failure wasn't handled correctly Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 89115dec7126f0..a9174894c44132 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7173,10 +7173,13 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h) || (h->cmd_pool == NULL) || (h->errinfo_pool == NULL)) { dev_err(&h->pdev->dev, "out of memory in %s", __func__); - return -ENOMEM; + goto clean_up; } hpsa_preinitialize_commands(h); return 0; +clean_up: + hpsa_free_cmd_pool(h); + return -ENOMEM; } static void hpsa_irq_affinity_hints(struct ctlr_info *h) From 0d26d4d78dd66e9f46288be05f8a8c747dd3e4de Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:36 -0500 Subject: [PATCH 296/889] hpsa: return status not void from hpsa_put_ctlr_into_performant_mode Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 55 ++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a9174894c44132..0888741663ff4d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -228,7 +228,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); @@ -8226,33 +8226,36 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) +/* return -ENODEV on error, 0 on success (or no action) + * allocates numerous items that must be freed later + */ +static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) { u32 trans_support; unsigned long transMethod = CFGTBL_Trans_Performant | CFGTBL_Trans_use_short_tags; - int i; + int i, rc; if (hpsa_simple_mode) - return; + return 0; trans_support = readl(&(h->cfgtable->TransportSupport)); if (!(trans_support & PERFORMANT_MODE)) - return; + return 0; /* Check for I/O accelerator mode support */ if (trans_support & CFGTBL_Trans_io_accel1) { transMethod |= CFGTBL_Trans_io_accel1 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel1_cmd_and_bft(h)) - goto clean_up; - } else { - if (trans_support & CFGTBL_Trans_io_accel2) { - transMethod |= CFGTBL_Trans_io_accel2 | + rc = hpsa_alloc_ioaccel1_cmd_and_bft(h); + if (rc) + return rc; + } else if (trans_support & CFGTBL_Trans_io_accel2) { + transMethod |= CFGTBL_Trans_io_accel2 | CFGTBL_Trans_enable_directed_msix; - if (hpsa_alloc_ioaccel2_cmd_and_bft(h)) - goto clean_up; - } + rc = hpsa_alloc_ioaccel2_cmd_and_bft(h); + if (rc) + return rc; } h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1; @@ -8264,8 +8267,10 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) h->reply_queue[i].head = pci_alloc_consistent(h->pdev, h->reply_queue_size, &(h->reply_queue[i].busaddr)); - if (!h->reply_queue[i].head) - goto clean_up; + if (!h->reply_queue[i].head) { + rc = -ENOMEM; + goto clean1; /* rq, ioaccel */ + } h->reply_queue[i].size = h->max_commands; h->reply_queue[i].wraparound = 1; /* spec: init to 1 */ h->reply_queue[i].current_entry = 0; @@ -8274,15 +8279,23 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) /* Need a block fetch table for performant mode */ h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * sizeof(u32)), GFP_KERNEL); - if (!h->blockFetchTable) - goto clean_up; + if (!h->blockFetchTable) { + rc = -ENOMEM; + goto clean1; /* rq, ioaccel */ + } - hpsa_enter_performant_mode(h, trans_support); - return; + rc = hpsa_enter_performant_mode(h, trans_support); + if (rc) + goto clean2; /* bft, rq, ioaccel */ + return 0; -clean_up: - hpsa_free_reply_queues(h); +clean2: /* bft, rq, ioaccel */ kfree(h->blockFetchTable); +clean1: /* rq, ioaccel */ + hpsa_free_reply_queues(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); + return rc; } static int is_accelerated_cmd(struct CommandList *c) From d128bcf2c20a0578882e0d3aef80f1b787a46c60 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:37 -0500 Subject: [PATCH 297/889] hpsa: clean up error handling in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0888741663ff4d..46d988e8b82697 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7650,19 +7650,19 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!h->resubmit_wq) { dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; - goto clean1; + goto clean1; /* aer/h */ } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { rc = -ENOMEM; - goto clean1; + goto clean1; /* wq/aer/h */ } set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); if (rc != 0) - goto clean1; + goto clean2; /* lockup, wq/aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); h->ctlr = number_of_controllers; @@ -7678,23 +7678,25 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean2; + goto clean3; /* pci, lockup, wq/aer/h */ } } /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) - goto clean2; + rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); + if (rc) + goto clean3; /* pci, lockup, wq/aer/h */ dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean2_and_free_irqs; - if (hpsa_allocate_sg_chain_blocks(h)) - goto clean4; + goto clean4; /* irq, pci, lockup, wq/aer/h */ + rc = hpsa_allocate_sg_chain_blocks(h); + if (rc) + goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ @@ -7704,7 +7706,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->hba_mode_enabled = 0; h->scsi_host = NULL; spin_lock_init(&h->devlock); - hpsa_put_ctlr_into_performant_mode(h); + rc = hpsa_put_ctlr_into_performant_mode(h); + if (rc) + goto clean6; /* sg, cmd, irq, pci, lockup, wq/aer/h */ /* At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -7783,20 +7787,20 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean4: - hpsa_free_sg_chain_blocks(h); +clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_cmd_pool(h); - hpsa_free_ioaccel1_cmd_and_bft(h); - hpsa_free_ioaccel2_cmd_and_bft(h); -clean2_and_free_irqs: +clean4: /* irq, pci, lockup, wq/aer/h */ hpsa_free_irqs(h); -clean2: +clean3: /* pci, lockup, wq/aer/h */ hpsa_free_pci_init(h); -clean1: - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); +clean2: /* lockup, wq/aer/h */ if (h->lockup_detected) free_percpu(h->lockup_detected); +clean1: /* wq/aer/h */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); + /* pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; } From 562ac57c7dacdc30a72eef1d751ce94044f7b456 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:37 -0500 Subject: [PATCH 298/889] hpsa: report allocation failures while allocating SG chain blocks Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 46d988e8b82697..e602b381b377d1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1880,13 +1880,17 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, GFP_KERNEL); - if (!h->cmd_sg_list) + if (!h->cmd_sg_list) { + dev_err(&h->pdev->dev, "Failed to allocate SG list\n"); return -ENOMEM; + } for (i = 0; i < h->nr_cmds; i++) { h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * h->chainsize, GFP_KERNEL); - if (!h->cmd_sg_list[i]) + if (!h->cmd_sg_list[i]) { + dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n"); goto clean; + } } return 0; From e957222bfb62529e93480b674f8f61cee76ca851 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:38 -0500 Subject: [PATCH 299/889] hpsa: rename hpsa_allocate_sg_chain_blocks to hpsa_alloc_sg_chain_blocks Just to match naming of corresponding free functions Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e602b381b377d1..a62164a31b1b23 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1871,7 +1871,7 @@ static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = NULL; } -static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) +static int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -7295,7 +7295,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_irqs(h); - hpsa_free_sg_chain_blocks(h); + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_cmd_pool(h); kfree(h->blockFetchTable); /* perf 2 */ @@ -7698,7 +7698,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean4; /* irq, pci, lockup, wq/aer/h */ - rc = hpsa_allocate_sg_chain_blocks(h); + rc = hpsa_alloc_sg_chain_blocks(h); if (rc) goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); @@ -7888,7 +7888,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) destroy_workqueue(h->resubmit_wq); hpsa_free_device_info(h); - hpsa_free_sg_chain_blocks(h); + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_ioaccel2_sg_chain_blocks(h); kfree(h->blockFetchTable); /* perf 2 */ hpsa_free_reply_queues(h); /* perf 1 */ From faad255f151480ccbaf3d618e533701e7021070c Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:38 -0500 Subject: [PATCH 300/889] hpsa: improve allocation failure messages from hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a62164a31b1b23..071d4766aa6a6f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7638,10 +7638,13 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); h = kzalloc(sizeof(*h), GFP_KERNEL); - if (!h) + if (!h) { + dev_err(&pdev->dev, "Failed to allocate controller head\n"); return -ENOMEM; + } h->pdev = pdev; + h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->offline_device_list); spin_lock_init(&h->lock); @@ -7652,13 +7655,14 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { - dev_warn(&h->pdev->dev, "Failed to allocate work queue\n"); + dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; goto clean1; /* aer/h */ } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { + dev_err(&h->pdev->dev, "Failed to allocate lockup detector\n"); rc = -ENOMEM; goto clean1; /* wq/aer/h */ } From 77c7ff992768406af6b47baecdc747b91984980d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:39 -0500 Subject: [PATCH 301/889] hpsa: fix minor if-statement style issue in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 071d4766aa6a6f..d18321175f170e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7669,7 +7669,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); - if (rc != 0) + if (rc) goto clean2; /* lockup, wq/aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); From 2830f73eac1ba1364c5d584f53947e2d0cc5cf76 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:40 -0500 Subject: [PATCH 302/889] hpsa: fix wrong indent level in hpsa_init_one Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d18321175f170e..011923c48e90ce 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7773,8 +7773,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto reinit_after_soft_reset; } - /* Enable Accelerated IO path at driver layer */ - h->acciopath_status = 1; + /* Enable Accelerated IO path at driver layer */ + h->acciopath_status = 1; h->lockup_detector_enabled = 1; From 82b9e24c1e65d22ccbee568c8b5f327d9259e46d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:40 -0500 Subject: [PATCH 303/889] Add hpsa_free_performant_mode and call it from hpsa_init_one in the proper order (after hpsa_unregister_scsi, which call scsi_remove_host) Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 011923c48e90ce..98f1680c39c154 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -228,9 +228,8 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int min_blocks, int *bucket_map); +static void hpsa_free_performant_mode(struct ctlr_info *h); static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); -static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h); -static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, @@ -7294,20 +7293,17 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { - hpsa_free_irqs(h); - hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_ioaccel2_sg_chain_blocks(h); - hpsa_free_cmd_pool(h); - kfree(h->blockFetchTable); /* perf 2 */ - hpsa_free_reply_queues(h); /* perf 1 */ - hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ - hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ + hpsa_free_irqs(h); /* init_one 4 */ hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); /* pci_init 2 */ - kfree(h); + kfree(h); /* init_one 1 */ } /* Called when controller lockup detected. */ @@ -7782,8 +7778,9 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - if (hpsa_register_scsi(h)) /* hook ourselves into SCSI subsystem */ - goto clean4; + rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ + if (rc) + goto clean7; /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -7795,6 +7792,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; +clean7: /* perf, sg, cmd, irq, pci, lockup, wq/aer/h */ + hpsa_free_performant_mode(h); clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); clean5: /* cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_cmd_pool(h); @@ -7808,7 +7807,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean1: /* wq/aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); - /* pci_disable_pcie_error_reporting(pdev); */ + /* (void) pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; } @@ -7855,7 +7854,7 @@ static void hpsa_shutdown(struct pci_dev *pdev) */ hpsa_flush_cache(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); - hpsa_free_irqs(h); + hpsa_free_irqs(h); /* init_one 4 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } @@ -7884,28 +7883,30 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->monitor_ctlr_work); cancel_delayed_work_sync(&h->rescan_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); - hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ - /* includes hpsa_free_irqs */ + /* includes hpsa_free_irqs - init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ hpsa_shutdown(pdev); - destroy_workqueue(h->resubmit_wq); - hpsa_free_device_info(h); - hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_device_info(h); /* scan */ + + hpsa_unregister_scsi(h); /* init_one "8" */ hpsa_free_ioaccel2_sg_chain_blocks(h); - kfree(h->blockFetchTable); /* perf 2 */ - hpsa_free_reply_queues(h); /* perf 1 */ - hpsa_free_ioaccel1_cmd_and_bft(h); /* perf 1 */ - hpsa_free_ioaccel2_cmd_and_bft(h); /* perf 1 */ - hpsa_free_cmd_pool(h); /* init_one 5 */ - kfree(h->hba_inquiry_data); + kfree(h->hba_inquiry_data); /* init_one "8" */ + hpsa_free_performant_mode(h); /* init_one 7 */ + hpsa_free_sg_chain_blocks(h); /* init_one 6 */ + hpsa_free_cmd_pool(h); /* init_one 5 */ + + /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ - hpsa_free_pci_init(h); + hpsa_free_pci_init(h); /* init_one 3 */ - free_percpu(h->lockup_detected); - kfree(h); + free_percpu(h->lockup_detected); /* init_one 2 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 1 */ + /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ + kfree(h); /* init_one 1 */ } static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev, @@ -8238,6 +8239,15 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) return -ENOMEM; } +/* Free items allocated by hpsa_put_ctlr_into_performant_mode */ +static void hpsa_free_performant_mode(struct ctlr_info *h) +{ + kfree(h->blockFetchTable); + hpsa_free_reply_queues(h); + hpsa_free_ioaccel1_cmd_and_bft(h); + hpsa_free_ioaccel2_cmd_and_bft(h); +} + /* return -ENODEV on error, 0 on success (or no action) * allocates numerous items that must be freed later */ From 938d838351cf647e4dfe15e1969bdc7ba8548a21 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:41 -0500 Subject: [PATCH 304/889] hpsa: shorten the wait for the CISS doorbell mode change acknowledgement Shorten the wait for the CISS configuration table doorbell mode change acknowledgement from 300-600 s to 1 s, which is the value specified in the CISS specification that should be honored by all controllers. Wait using interruptible msleep() rather than uninterruptible usleep_range(), which triggers rt_sched timeout errors if the wait is long. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 98f1680c39c154..dd700fb9dd5caa 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -58,8 +58,11 @@ #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" -/* How long to wait (in milliseconds) for board to go into simple mode */ -#define MAX_CONFIG_WAIT 30000 +/* How long to wait for CISS doorbell communication */ +#define CLEAR_EVENT_WAIT_INTERVAL 20 /* ms for each msleep() call */ +#define MODE_CHANGE_WAIT_INTERVAL 10 /* ms for each msleep() call */ +#define MAX_CLEAR_EVENT_WAIT 30000 /* times 20 ms = 600 s */ +#define MAX_MODE_CHANGE_WAIT 100 /* times 10 ms = 1 s */ #define MAX_IOCTL_CONFIG_WAIT 1000 /*define how many times we will try a command because of bus resets */ @@ -6929,14 +6932,14 @@ static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) u32 doorbell_value; unsigned long flags; /* wait until the clear_event_notify bit 6 is cleared by controller. */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) goto done; /* delay and try again */ - msleep(20); + msleep(CLEAR_EVENT_WAIT_INTERVAL); } return -ENODEV; done: @@ -6953,14 +6956,14 @@ static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right * as we enter this code.) */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) goto done; /* delay and try again */ - usleep_range(10000, 20000); + msleep(MODE_CHANGE_WAIT_INTERVAL); } return -ENODEV; done: From c4e1fcc78fe350a775cbb4fe5d317cccbcc9452e Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:41 -0500 Subject: [PATCH 305/889] hpsa: clean up some error reporting output in abort handler Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index dd700fb9dd5caa..6ce8a32348e80d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5306,11 +5306,18 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); if (WARN(h == NULL, - "ABORT REQUEST FAILED, Controller lookup failed.\n")) + "scsi ?:?:?:? scmd %p ABORT FAILED, Controller lookup failed.\n", + sc)) return FAILED; - if (lockup_detected(h)) + /* if controller locked up, we can guarantee command won't complete */ + if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + h->scsi_host->host_no, sc->device->channel, + sc->device->id, sc->device->lun, sc); return FAILED; + } /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && @@ -5318,9 +5325,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; memset(msg, 0, sizeof(msg)); - ml += sprintf(msg+ml, "Aborting command on scsi %d:%d:%d:%llu ", + ml += sprintf(msg+ml, "scsi %d:%d:%d:%llu scmd %p ABORT ", h->scsi_host->host_no, sc->device->channel, - sc->device->id, sc->device->lun); + sc->device->id, sc->device->lun, sc); /* Find the device of the command to be aborted */ dev = sc->device->hostdata; @@ -5362,11 +5369,12 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); as = abort->scsi_cmd; if (as != NULL) - ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", - as->cmnd[0], as->serial_number); - dev_dbg(&h->pdev->dev, "%s\n", msg); - dev_warn(&h->pdev->dev, "Aborting command on scsi %d:%d:%d:%d\n", - h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + ml += sprintf(msg+ml, + "CDBLen: %d CDB: 0x%02x%02x... SN: 0x%lx ", + as->cmd_len, as->cmnd[0], as->cmnd[1], + as->serial_number); + dev_warn(&h->pdev->dev, "%s BEING SENT\n", msg); + /* * Command is in flight, or possibly already completed * by the firmware (but not to the scsi mid layer) but we can't @@ -5374,7 +5382,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ if (wait_for_available_abort_cmd(h)) { dev_warn(&h->pdev->dev, - "Timed out waiting for an abort command to become available.\n"); + "%s FAILED, timeout waiting for an abort command to become available.\n", + msg); cmd_free(h, abort); return FAILED; } @@ -5382,13 +5391,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) atomic_inc(&h->abort_cmds_available); wake_up_all(&h->abort_cmd_wait_queue); if (rc != 0) { - dev_warn(&h->pdev->dev, "FAILED abort command on scsi %d:%d:%d:%d\n", - h->scsi_host->host_no, - dev->bus, dev->target, dev->lun); + dev_warn(&h->pdev->dev, "%s SENT, FAILED\n", msg); cmd_free(h, abort); return FAILED; } - dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); + dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); cmd_free(h, abort); return SUCCESS; } From 629a66f62ca18930896dbce691f4e2b795261941 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:42 -0500 Subject: [PATCH 306/889] hpsa: try to detect controller lockup in abort handler Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6ce8a32348e80d..f76d0381b0ffb9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -253,6 +253,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk); static void hpsa_command_resubmit_worker(struct work_struct *work); static void print_cfg_table(struct device *dev, struct CfgTable *tb); +static void detect_controller_lockup(struct ctlr_info *h); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -5317,6 +5318,21 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; + } else { + /* good time to check if controller lockup has occurred */ + /* FIXME eh_timeout_handler would be even better. + * for testing, abort is just being used for timeouts, + * so is equivalent */ + detect_controller_lockup(h); + + /* check again in case one just occurred */ + if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, + "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + h->scsi_host->host_no, sc->device->channel, + sc->device->id, sc->device->lun, sc); + return FAILED; + } } /* Check that controller supports some kind of task abort */ From de63c3a95ccfb5c017f6ccbe5c89bd8669bd3fef Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:42 -0500 Subject: [PATCH 307/889] hpsa: Return DID_NO_CONNECT rather than DID_ERR on lockup After a lockup is detected, return DO_NO_CONNECT which results in immediate termination of commands rather than DID_ERR which results in retries Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 35 +++++++++++++++++++++++++++-------- drivers/scsi/hpsa_cmd.h | 5 +++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f76d0381b0ffb9..cf18cce23e13a4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2193,6 +2193,18 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + /* We check for lockup status here as it may be set for + * CMD_SCSI, CMD_IOACCEL1 and CMD_IOACCEL2 commands by + * fail_all_oustanding_cmds() + */ + if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) { + /* DID_NO_CONNECT will prevent a retry */ + cmd->result = DID_NO_CONNECT << 16; + cmd_free(h, cp); + cmd->scsi_done(cmd); + return; + } + if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); @@ -2461,9 +2473,8 @@ static u32 lockup_detected(struct ctlr_info *h) static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, struct CommandList *c, unsigned long timeout_msecs) { - /* If controller lockup detected, fake a hardware error. */ if (unlikely(lockup_detected(h))) { - c->err_info->CommandStatus = CMD_HARDWARE_ERR; + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; return 0; } return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); @@ -4749,14 +4760,14 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; + cmd->result = DID_NO_CONNECT << 16; cmd->scsi_done(cmd); return 0; } c = cmd_alloc(h); if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; + cmd->result = DID_NO_CONNECT << 16; cmd_free(h, c); cmd->scsi_done(cmd); return 0; @@ -7337,18 +7348,25 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) { int i, refcount; struct CommandList *c; + int failcount = 0; flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) { c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); if (refcount > 1) { - c->err_info->CommandStatus = CMD_HARDWARE_ERR; + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; + /* CMD_CTLR_LOCKUP gets finish_cmd to return + * DID_NO_CONNECT which doesn't get retried + */ finish_cmd(c); atomic_dec(&h->commands_outstanding); + failcount++; } cmd_free(h, c); } + dev_warn(&h->pdev->dev, + "failed %d commands in fail_all\n", failcount); } static void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value) @@ -7376,13 +7394,14 @@ static void controller_lockup_detected(struct ctlr_info *h) if (!lockup_detected) { /* no heartbeat, but controller gave us a zero. */ dev_warn(&h->pdev->dev, - "lockup detected but scratchpad register is zero\n"); + "lockup detected after %d but scratchpad register is zero\n", + h->heartbeat_sample_interval / HZ); lockup_detected = 0xffffffff; } set_lockup_detected_for_all_cpus(h, lockup_detected); spin_unlock_irqrestore(&h->lock, flags); - dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", - lockup_detected); + dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x after %d\n", + lockup_detected, h->heartbeat_sample_interval / HZ); pci_disable_device(h->pdev); fail_all_outstanding_cmds(h); } diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 2984d236fb888f..84eb6de9e69c34 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -44,6 +44,11 @@ #define CMD_UNABORTABLE 0x000C #define CMD_TMF_STATUS 0x000D #define CMD_IOACCEL_DISABLED 0x000E +#define CMD_CTLR_LOCKUP 0xffff +/* Note: CMD_CTLR_LOCKUP is not a value defined by the CISS spec + * it is a value defined by the driver that commands can be marked + * with when a controller lockup has been detected by the driver + */ /* TMF function status values */ #define CISS_TMF_COMPLETE 0x00 From c0f47aed8c111a01aa0d6e1322e75af1b87cd110 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:43 -0500 Subject: [PATCH 308/889] hpsa: check for lockup on all simple_cmd submissions Submitting a command to a locked up controller always results in a timeout, so don't do that Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cf18cce23e13a4..d07dbc520c4307 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2454,6 +2454,10 @@ static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, struct CommandList *c, unsigned long timeout_msecs) { + if (unlikely(lockup_detected(h))) { + c->err_info->CommandStatus = CMD_CTLR_LOCKUP; + return 0; + } return __hpsa_scsi_do_simple_cmd_core(h, c, DEFAULT_REPLY_QUEUE, timeout_msecs); } @@ -2470,16 +2474,6 @@ static u32 lockup_detected(struct ctlr_info *h) return rc; } -static int hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, - struct CommandList *c, unsigned long timeout_msecs) -{ - if (unlikely(lockup_detected(h))) { - c->err_info->CommandStatus = CMD_CTLR_LOCKUP; - return 0; - } - return hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); -} - #define MAX_DRIVER_CMD_RETRIES 25 static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, struct CommandList *c, int data_direction, unsigned long timeout_msecs) @@ -2587,6 +2581,9 @@ static void hpsa_scsi_interpret_error(struct ctlr_info *h, case CMD_UNABORTABLE: hpsa_print_cmd(h, "unabortable", cp); break; + case CMD_CTLR_LOCKUP: + hpsa_print_cmd(h, "controller lockup detected", cp); + break; default: hpsa_print_cmd(h, "unknown status", cp); dev_warn(d, "Unknown command status %x\n", @@ -4553,6 +4550,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, } /* Submit commands down the "normal" RAID stack path */ +/* All callers to hpsa_ciss_submit must check lockup_detected + * beforehand, before (opt.) and after calling cmd_alloc + */ static int hpsa_ciss_submit(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, unsigned char scsi3addr[]) @@ -4768,7 +4768,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, c); + cmd_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ cmd->scsi_done(cmd); return 0; } @@ -5696,7 +5696,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - rc = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (rc) rc = -EIO; if (iocommand.buf_size > 0) @@ -5826,7 +5826,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - status = hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c, NO_TIMEOUT); + status = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); if (status) { status = -EIO; goto cleanup0; @@ -7864,6 +7864,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) int rc; /* Don't bother trying to flush the cache if locked up */ + /* FIXME not necessary if do_simple_cmd does the check */ if (unlikely(lockup_detected(h))) return; flush_buf = kzalloc(4, GFP_KERNEL); From 3a5aa6ca2c7c4b63464882dbfa0627a3a4b39c15 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:44 -0500 Subject: [PATCH 309/889] hpsa: Support 64-bit lun values in printks The scsi-mq.2 tree includes 64-bit LUN support in some SCSI structures, causing the compiler to complain that %d is not big enough in some of the hpsa controller:bus:target:lun prints Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d07dbc520c4307..44f11d30aa11f8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5325,7 +5325,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) { dev_warn(&h->pdev->dev, - "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; @@ -5339,7 +5339,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* check again in case one just occurred */ if (lockup_detected(h)) { dev_warn(&h->pdev->dev, - "scsi %d:%d:%d:%d scmd %p ABORT FAILED, lockup detected\n", + "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, sc->device->id, sc->device->lun, sc); return FAILED; From 47e68f16f518ad86c3f29d09c85e160d563862da Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:44 -0500 Subject: [PATCH 310/889] hpsa: fix missing return in hpsa_command_resubmit_worker Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 44f11d30aa11f8..6a179f80e9c37d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4724,6 +4724,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); + return; } /* if rc > 0, fall thru and resubmit down CISS path */ } From a5520400a012c5732d8d7684e4457d9268977fec Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:45 -0500 Subject: [PATCH 311/889] hpsa: fix command leaks in hpsa_resubmit_command_worker Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6a179f80e9c37d..448227d9b1360f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4703,6 +4703,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; + cmd_free(c->h, c); cmd->scsi_done(cmd); return; } @@ -4721,6 +4722,9 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) * If we get here, it means dma mapping failed. * Try again via scsi mid layer, which will * then get SCSI_MLQUEUE_HOST_BUSY. + * + * hpsa_ioaccel_submit will have already freed c + * if it encountered a dma mapping failure. */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); @@ -4735,6 +4739,9 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) * If we get here, it means dma mapping failed. Try * again via scsi mid layer, which will then get * SCSI_MLQUEUE_HOST_BUSY. + * + * hpsa_ciss_submit will have already freed c + * if it encountered a dma mapping failure. */ cmd->result = DID_IMM_RETRY << 16; cmd->scsi_done(cmd); From fddd915a61ee2af9189c1bab465641f6b6893254 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:45 -0500 Subject: [PATCH 312/889] hpsa: fix bad interpretations of hpsa_ioaccel_submit return value Probably squash this with hpsa-factor-out-hpsa_ioaccel_submit before sending upstream, keeping separate for now for benefit of porting to svn. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 448227d9b1360f..05f6ea71bd764e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4717,7 +4717,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); if (rc == 0) return; - if (rc < 0) { + if (rc == SCSI_MLQUEUE_HOST_BUSY) { /* * If we get here, it means dma mapping failed. * Try again via scsi mid layer, which will @@ -4730,7 +4730,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->scsi_done(cmd); return; } - /* if rc > 0, fall thru and resubmit down CISS path */ + /* else, fall thru and resubmit down CISS path */ } } hpsa_cmd_partial_init(c->h, c->cmdindex, c); @@ -4854,7 +4854,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); if (rc == 0) return 0; - if (rc < 0) + if (rc == SCSI_MLQUEUE_HOST_BUSY) return SCSI_MLQUEUE_HOST_BUSY; } return hpsa_ciss_submit(h, c, cmd, scsi3addr); From ddca271b27832a635aaa769a8d292ba5c2105b3a Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:46 -0500 Subject: [PATCH 313/889] hpsa: do not touch phys_disk[] for ioaccel enabled logical drives during rescan The code to update h->dev[]->phys_disk[] was temporarily NULLing out h->dev[]->phys_disk[] even if io's using it might be in flight within queuecommand, causing potential NULL pointer dereference in hpsa_raid_map(). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 05f6ea71bd764e..0d71c216751bda 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1574,6 +1574,15 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, continue; if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) continue; + + /* If offload is currently enabled, the RAID map and + * phys_disk[] assignment *better* not be changing + * and since it isn't changing, we do not need to + * update it. + */ + if (dev[i]->offload_enabled) + continue; + hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]); } } From b9044293f36ecb6133a6597f695185c5f8acf81e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:46 -0500 Subject: [PATCH 314/889] hpsa: make hpsa_change_queue_depth handle reason SCSI_QDEPTH_QFULL Call the .change_queue_depth function in the host template, call scsi_track_queue_full if it gets a reason of SCSI_QDEPTH_QFULL (a TASK SET FULL status), which lets the SCSI midlayer reduce the queue depth. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0d71c216751bda..67390b701aa60d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4938,20 +4938,27 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, return finished; } +/* scsi host template change_queue_depth function */ static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { struct ctlr_info *h = sdev_to_hba(sdev); - if (reason != SCSI_QDEPTH_DEFAULT) - return -ENOTSUPP; + if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { + if (qdepth < 1) + qdepth = 1; + else if (qdepth > h->nr_cmds) + qdepth = h->nr_cmds - HPSA_CMDS_RESERVED_FOR_ABORTS - + HPSA_CMDS_RESERVED_FOR_DRIVER - + HPSA_MAX_CONCURRENT_PASSTHRUS; + - if (qdepth < 1) - qdepth = 1; + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + } else if (reason == SCSI_QDEPTH_QFULL) + scsi_track_queue_full(sdev, qdepth); else - if (qdepth > h->nr_cmds) - qdepth = h->nr_cmds; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + return -ENOTSUPP; + return sdev->queue_depth; } From 45a7229a6eea904fdd5b201f6d74ffb087dfc5b2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:47 -0500 Subject: [PATCH 315/889] hpsa: initialize queue depth of logical drives reasonably Adjust the queue depth for a new device after it is created based on the maximum queue depths of the physical devices that constitute the device. This drops the maximum queue depth from .can_queue of 1024 to something like 174 for single-drive RAID-0, 348 for two-drive RAID-1, etc. It also adjusts for the ratio of data to parity drives. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 64 ++++++++++++++++++++++++++++++++------------- drivers/scsi/hpsa.h | 2 +- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 67390b701aa60d..38e1fcdf6f4c2c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1174,7 +1174,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), @@ -1184,7 +1184,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[device->raid_level], device->offload_config ? '+' : '-', device->offload_enabled ? '+' : '-', - device->expose_state); + device->expose_state, + device->queue_depth); return 0; } @@ -1225,9 +1226,10 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->offload_to_be_enabled = new_entry->offload_enabled; if (!new_entry->offload_enabled) h->dev[entry]->offload_enabled = 0; + h->dev[entry]->queue_depth = new_entry->queue_depth; dev_info(&h->pdev->dev, - "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1236,7 +1238,8 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state); + new_entry->expose_state, + new_entry->queue_depth); } /* Replace an entry from h->dev[] array. */ @@ -1265,7 +1268,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, added[*nadded] = new_entry; (*nadded)++; dev_info(&h->pdev->dev, - "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1274,7 +1277,8 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state); + new_entry->expose_state, + new_entry->queue_depth); } /* Remove an entry from h->dev[] array. */ @@ -1295,7 +1299,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, h->dev[i] = h->dev[i+1]; h->ndevices--; dev_info(&h->pdev->dev, - "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, sd->bus, sd->target, sd->lun, scsi_device_type(sd->devtype), sd->vendor, @@ -1304,7 +1308,8 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, "RAID-?" : raid_label[sd->raid_level], sd->offload_config ? '+' : '-', sd->offload_enabled ? '+' : '-', - sd->expose_state); + sd->expose_state, + sd->queue_depth); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1376,6 +1381,8 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1, return 1; if (dev1->offload_enabled != dev2->offload_enabled) return 1; + if (dev1->queue_depth != dev2->queue_depth) + return 1; return 0; } @@ -1537,6 +1544,7 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) nraid_map_entries = RAID_MAP_MAX_ENTRIES; + logical_drive->queue_depth = 0; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; if (!logical_drive->offload_config) @@ -1548,6 +1556,13 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { logical_drive->phys_disk[i] = dev[j]; + logical_drive->queue_depth = min(h->nr_cmds, + logical_drive->queue_depth + + logical_drive->phys_disk[i]->queue_depth); + dev_info(&h->pdev->dev, + "setting phys_disk[%d] to dev[%d]=%p, qd=%d\n", + i, j, dev[j], + logical_drive->queue_depth); /* ROBROB development only - remove this print */ break; } } @@ -1559,9 +1574,20 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, * present. And in that case offload_enabled should already * be 0, but we'll turn it off here just in case */ - if (!logical_drive->phys_disk[i]) + if (!logical_drive->phys_disk[i]) { logical_drive->offload_enabled = 0; + logical_drive->offload_to_be_enabled = 0; + logical_drive->queue_depth = h->nr_cmds; + } } + if (nraid_map_entries) + /* exclude parity drives from calculation */ + logical_drive->queue_depth = min(h->nr_cmds, + logical_drive->queue_depth * + logical_drive->raid_map.data_disks_per_row / + nraid_map_entries); + else + logical_drive->queue_depth = h->nr_cmds; } static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, @@ -1660,7 +1686,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); dev_info(&h->pdev->dev, - "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, scsi_device_type(sd[i]->devtype), sd[i]->vendor, @@ -1670,7 +1696,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, raid_label[sd[i]->raid_level], sd[i]->offload_config ? '+' : '-', sd[i]->offload_enabled ? '+' : '-', - sd[i]->expose_state); + sd[i]->expose_state, + sd[i]->queue_depth); continue; } @@ -3236,6 +3263,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->offload_to_be_enabled = 0; this_device->hba_ioaccel_enabled = 0; this_device->volume_offline = 0; + this_device->queue_depth = h->nr_cmds; } if (is_OBDR_device) { @@ -4942,16 +4970,16 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { - struct ctlr_info *h = sdev_to_hba(sdev); - if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { + struct hpsa_scsi_dev_t *logical_drive = sdev->hostdata; + + if (!logical_drive) + return -ENODEV; + if (qdepth < 1) qdepth = 1; - else if (qdepth > h->nr_cmds) - qdepth = h->nr_cmds - HPSA_CMDS_RESERVED_FOR_ABORTS - - HPSA_CMDS_RESERVED_FOR_DRIVER - - HPSA_MAX_CONCURRENT_PASSTHRUS; - + else if (qdepth > logical_drive->queue_depth) + qdepth = logical_drive->queue_depth; scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); } else if (reason == SCSI_QDEPTH_QFULL) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 109e6e70ea5be0..a7bb84039f3ce8 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -46,7 +46,7 @@ struct hpsa_scsi_dev_t { unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ - u16 queue_depth; + u16 queue_depth; /* max queue_depth for this device */ atomic_t ioaccel_cmds_out; /* Only used for physical devices * counts commands sent to physical * device via "ioaccel" path. From 01bcad470069997e86ccd6469d4c28e7a604e368 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:48 -0500 Subject: [PATCH 316/889] hpsa: attempt to fix queue depth calculations for logical drives Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 38e1fcdf6f4c2c..4e0ae17d164f7e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1540,11 +1540,12 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, int i, j; int nraid_map_entries = map->row_cnt * map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row); + int qdepth; if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) nraid_map_entries = RAID_MAP_MAX_ENTRIES; - logical_drive->queue_depth = 0; + qdepth = 0; for (i = 0; i < nraid_map_entries; i++) { logical_drive->phys_disk[i] = NULL; if (!logical_drive->offload_config) @@ -1554,17 +1555,13 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) continue; - if (dev[j]->ioaccel_handle == dd[i].ioaccel_handle) { - logical_drive->phys_disk[i] = dev[j]; - logical_drive->queue_depth = min(h->nr_cmds, - logical_drive->queue_depth + - logical_drive->phys_disk[i]->queue_depth); - dev_info(&h->pdev->dev, - "setting phys_disk[%d] to dev[%d]=%p, qd=%d\n", - i, j, dev[j], - logical_drive->queue_depth); /* ROBROB development only - remove this print */ - break; - } + if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) + continue; + + logical_drive->phys_disk[i] = dev[j]; + qdepth = min(h->nr_cmds, qdepth + + logical_drive->phys_disk[i]->queue_depth); + break; } /* @@ -1580,12 +1577,12 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, logical_drive->queue_depth = h->nr_cmds; } } - if (nraid_map_entries) - /* exclude parity drives from calculation */ - logical_drive->queue_depth = min(h->nr_cmds, - logical_drive->queue_depth * - logical_drive->raid_map.data_disks_per_row / - nraid_map_entries); + if (nraid_map_entries) + /* + * This is correct for reads, too high for full stripe writes, + * way too high for partial stripe writes + */ + logical_drive->queue_depth = qdepth; else logical_drive->queue_depth = h->nr_cmds; } From 34139d62e7f9db5adf7245de8fada2b9b05d295b Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:51:48 -0500 Subject: [PATCH 317/889] hpsa: do not print ioaccel2 warning messages about unusual completions. The SCSI midlayer already prints more detail about completions, and has logging level options to filter them if not wanted. These just slow down the system if a lot of errors occur, stressing error handling even more. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4e0ae17d164f7e..5f600a7db05e53 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2025,9 +2025,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, case IOACCEL2_STATUS_SR_TASK_COMP_GOOD: break; case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND: - dev_warn(&h->pdev->dev, - "%s: task complete with check condition.\n", - "HP SSD Smart Path"); cmd->result |= SAM_STAT_CHECK_CONDITION; if (c2->error_data.data_present != IOACCEL2_SENSE_DATA_PRESENT) { @@ -2047,30 +2044,18 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_BUSY: - dev_warn(&h->pdev->dev, - "%s: task complete with BUSY status.\n", - "HP SSD Smart Path"); retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_RES_CON: - dev_warn(&h->pdev->dev, - "%s: task complete with reservation conflict.\n", - "HP SSD Smart Path"); retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL: retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED: - dev_warn(&h->pdev->dev, - "%s: task complete with aborted status.\n", - "HP SSD Smart Path"); retry = 1; break; default: - dev_warn(&h->pdev->dev, - "%s: task complete with unrecognized status: 0x%02x\n", - "HP SSD Smart Path", c2->error_data.status); retry = 1; break; } @@ -2099,9 +2084,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, break; default: retry = 1; - dev_warn(&h->pdev->dev, - "unexpected delivery or target failure, status = 0x%02x\n", - c2->error_data.status); } break; case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: @@ -2109,17 +2091,11 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS: break; case IOACCEL2_SERV_RESPONSE_TMF_REJECTED: - dev_warn(&h->pdev->dev, "task management function rejected.\n"); retry = 1; break; case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN: - dev_warn(&h->pdev->dev, "task management function invalid LUN\n"); break; default: - dev_warn(&h->pdev->dev, - "%s: Unrecognized server response: 0x%02x\n", - "HP SSD Smart Path", - c2->error_data.serv_response); retry = 1; break; } From 58cd18af9ed61bf3e01dd2ea313154ad2f43fc9d Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:49 -0500 Subject: [PATCH 318/889] hpsa: zero the command reference counts on initial allocation Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5f600a7db05e53..d5e8890446b57f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4654,6 +4654,7 @@ static void hpsa_preinitialize_commands(struct ctlr_info *h) for (i = 0; i < h->nr_cmds; i++) { struct CommandList *c = h->cmd_pool + i; hpsa_cmd_init(h, i, c); + atomic_set(&c->refcount, 0); } } From 8fa1da09da2a6a23e36f09f3649a50a1ff95b6f9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:49 -0500 Subject: [PATCH 319/889] hpsa: add support sending aborts to physical devices via the ioaccel2 path Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 133 ++++++++++++++++++++++++++++++++++++++-- drivers/scsi/hpsa.h | 1 + drivers/scsi/hpsa_cmd.h | 4 +- 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d5e8890446b57f..ae9c231f41536e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -987,6 +987,28 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h, IOACCEL1_BUSADDR_CMDTYPE; } +static void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h, + struct CommandList *c, + int reply_queue) +{ + struct hpsa_tmf_struct *cp = (struct hpsa_tmf_struct *) + &h->ioaccel2_cmd_pool[c->cmdindex]; + + /* Tell the controller to post the reply to the queue for this + * processor. This seems to give the best I/O throughput. + */ + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) + cp->reply_queue = smp_processor_id() % h->nreply_queues; + else + cp->reply_queue = reply_queue % h->nreply_queues; + /* Set the bits in the address sent down to include: + * - performant mode bit not used in ioaccel mode 2 + * - pull count (bits 0-3) + * - command type isn't needed for ioaccel2 + */ + c->busaddr |= (h->ioaccel2_blockFetchTable[0]); +} + static void set_ioaccel2_performant_mode(struct ctlr_info *h, struct CommandList *c, int reply_queue) @@ -1051,6 +1073,10 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, set_ioaccel2_performant_mode(h, c, reply_queue); writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; + case IOACCEL2_TMF: + set_ioaccel2_tmf_performant_mode(h, c, reply_queue); + writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); + break; default: set_performant_mode(h, c, reply_queue); h->access.submit_command(h, c); @@ -5211,6 +5237,47 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, return rc; } +static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h, + struct CommandList *command_to_abort, int reply_queue) +{ + struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *) c2; + struct io_accel2_cmd *c2a = + &h->ioaccel2_cmd_pool[command_to_abort->cmdindex]; + struct scsi_cmnd *scmd = + (struct scsi_cmnd *) command_to_abort->scsi_cmd; + struct hpsa_scsi_dev_t *dev = scmd->device->hostdata; + + /* + * We're overlaying struct hpsa_tmf_struct on top of something which + * was allocated as a struct io_accel2_cmd, so we better be sure it + * actually fits, and doesn't overrun the error info space. + */ + BUILD_BUG_ON(sizeof(struct hpsa_tmf_struct) > + sizeof(struct io_accel2_cmd)); + BUG_ON(offsetof(struct io_accel2_cmd, error_data) < + offsetof(struct hpsa_tmf_struct, error_len) + + sizeof(ac->error_len)); + + c->cmd_type = IOACCEL2_TMF; + /* Adjust the DMA address to point to the accelerated command buffer */ + c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle + + (c->cmdindex * sizeof(struct io_accel2_cmd)); + BUG_ON(c->busaddr & 0x0000007F); + + memset(ac, 0, sizeof(*c2)); /* yes this is correct */ + ac->iu_type = IOACCEL2_IU_TMF_TYPE; + ac->reply_queue = reply_queue; + ac->tmf = IOACCEL2_TMF_ABORT; + ac->it_nexus = cpu_to_le32((u32) dev->ioaccel_handle); + memset(ac->lun_id, 0, sizeof(ac->lun_id)); + ac->tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; + ac->abort_tag = c2a->Tag; + ac->error_ptr = cpu_to_le64((u64) c->busaddr + + offsetof(struct io_accel2_cmd, error_data)); + ac->error_len = cpu_to_le32((u32) sizeof(c2->error_data)); +} + /* ioaccel2 path firmware cannot handle abort task requests. * Change abort requests to physical target reset, and send to the * address of the physical disk used for the ioaccel 2 command. @@ -5289,17 +5356,71 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, return rc; /* success */ } +static int hpsa_send_abort_ioaccel2(struct ctlr_info *h, + struct CommandList *abort, int reply_queue) +{ + int rc = IO_OK; + struct CommandList *c; + u32 taglower, tagupper; + struct hpsa_scsi_dev_t *dev; + struct io_accel2_cmd *c2; + + dev = abort->scsi_cmd->device->hostdata; + if (!dev->offload_enabled && !dev->hba_ioaccel_enabled) + return -1; + + c = cmd_alloc(h); + setup_ioaccel2_abort_cmd(c, h, abort, reply_queue); + c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; + (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + hpsa_get_tag(h, abort, &taglower, &tagupper); + dev_dbg(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + __func__, tagupper, taglower); + /* no unmap needed here because no data xfer. */ + + dev_dbg(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: abort service response = 0x%02x.\n", + __func__, tagupper, taglower, c2->error_data.serv_response); + switch (c2->error_data.serv_response) { + case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE: + case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS: + rc = 0; + break; + case IOACCEL2_SERV_RESPONSE_TMF_REJECTED: + case IOACCEL2_SERV_RESPONSE_FAILURE: + case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN: + rc = -1; + break; + default: + dev_warn(&h->pdev->dev, + "%s: Tag:0x%08x:%08x: unknown abort service response x0%02x\n", + __func__, tagupper, taglower, + c2->error_data.serv_response); + rc = -1; + } + cmd_free(h, c); + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, + tagupper, taglower); + return rc; +} + static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, - * but underlying firmware can't handle abort TMF. - * Change abort to physical device reset. + * but not all underlying firmware can handle abort TMF. + * Change abort to physical device reset when abort TMF is unsupported. */ - if (abort->cmd_type == CMD_IOACCEL2) - return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, + if (abort->cmd_type == CMD_IOACCEL2) { + if (HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags) + return hpsa_send_abort_ioaccel2(h, abort, + reply_queue); + else + return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort, reply_queue); + } return hpsa_send_abort(h, scsi3addr, abort, reply_queue); } @@ -6180,7 +6301,7 @@ static inline void finish_cmd(struct CommandList *c) if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI || c->cmd_type == CMD_IOACCEL2)) complete_scsi_command(c); - else if (c->cmd_type == CMD_IOCTL_PEND) + else if (c->cmd_type == CMD_IOCTL_PEND || c->cmd_type == IOACCEL2_TMF) complete(c->waiting); } @@ -6948,6 +7069,8 @@ static void hpsa_find_board_params(struct ctlr_info *h) dev_warn(&h->pdev->dev, "Physical aborts not supported\n"); if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) dev_warn(&h->pdev->dev, "Logical aborts not supported\n"); + if (!(HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags)) + dev_warn(&h->pdev->dev, "HP SSD Smart Path aborts supported\n"); } static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index a7bb84039f3ce8..d3a7b5299ec789 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -231,6 +231,7 @@ struct ctlr_info { #define HPSATMF_PHYS_QRY_TASK (1 << 7) #define HPSATMF_PHYS_QRY_TSET (1 << 8) #define HPSATMF_PHYS_QRY_ASYNC (1 << 9) +#define HPSATMF_IOACCEL_ENABLED (1 << 15) #define HPSATMF_MASK_SUPPORTED (1 << 16) #define HPSATMF_LOG_LUN_RESET (1 << 17) #define HPSATMF_LOG_NEX_RESET (1 << 18) diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 84eb6de9e69c34..cf3093dccd9f87 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -396,6 +396,7 @@ struct ErrorInfo { #define CMD_SCSI 0x03 #define CMD_IOACCEL1 0x04 #define CMD_IOACCEL2 0x05 +#define IOACCEL2_TMF 0x06 #define DIRECT_LOOKUP_SHIFT 4 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) @@ -589,6 +590,7 @@ struct io_accel2_cmd { #define IOACCEL2_DIR_NO_DATA 0x00 #define IOACCEL2_DIR_DATA_IN 0x01 #define IOACCEL2_DIR_DATA_OUT 0x02 +#define IOACCEL2_TMF_ABORT 0x01 /* * SCSI Task Management Request format for Accelerator Mode 2 */ @@ -603,7 +605,7 @@ struct hpsa_tmf_struct { u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */ u64 error_ptr; /* Error Pointer */ u32 error_len; /* Error Length */ -}; +} __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT); /* Configuration Table Structure */ struct HostWrite { From 793c3405bc903eb096c6e164b0ac353ce386ea37 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:50 -0500 Subject: [PATCH 320/889] hpsa: make hpsa_send_reset_as_abort_ioaccel2() use the specified reply queue. We are sending a reset in order to get rid of a command we want to abort. If we make it return on the same reply queue as the command we want to abort, the completion of the aborted command will not race with the completion of the reset command. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ae9c231f41536e..d4ab93d1ffc8ea 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2685,7 +2685,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, } static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, - u8 reset_type) + u8 reset_type, int reply_queue) { int rc = IO_OK; struct CommandList *c; @@ -2697,7 +2697,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); goto out; @@ -5146,7 +5146,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) dev->expose_state); /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN); + rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, + DEFAULT_REPLY_QUEUE); if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) return SUCCESS; @@ -5286,8 +5287,7 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h, */ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, - unsigned char *scsi3addr, struct CommandList *abort, - __attribute__((unused)) int reply_queue) + unsigned char *scsi3addr, struct CommandList *abort, int reply_queue) { int rc = IO_OK; struct scsi_cmnd *scmd; /* scsi command within request being aborted */ @@ -5329,7 +5329,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, "Reset as abort: Resetting physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", psa[0], psa[1], psa[2], psa[3], psa[4], psa[5], psa[6], psa[7]); - rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET); + rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET, reply_queue); if (rc != 0) { dev_warn(&h->pdev->dev, "Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", From 8c8feef040b7564ebbb5d2db5331b86e9f9a2f19 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:50 -0500 Subject: [PATCH 321/889] hpsa: fix problem with abort support checking happening too early The code that checks whether aborts are supported is supposed to see if a logical drive is already known first, but this check happens too early before the necessary data is available. Check it later when the data is available. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d4ab93d1ffc8ea..851420434af66c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3217,8 +3217,6 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; - unsigned long flags; - int rc, entry; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) @@ -3275,30 +3273,36 @@ static int hpsa_update_device_info(struct ctlr_info *h, OBDR_SIG_LEN) == 0); } kfree(inq_buff); + return 0; + +bail_out: + kfree(inq_buff); + return 1; +} +static void hpsa_update_device_supports_aborts(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev, u8 *scsi3addr) +{ + unsigned long flags; + int rc, entry; /* * See if this device supports aborts. If we already know * the device, we already know if it supports aborts, otherwise * we have to find out if it supports aborts by trying one. */ spin_lock_irqsave(&h->devlock, flags); - rc = hpsa_scsi_find_entry(this_device, h->dev, h->ndevices, &entry); + rc = hpsa_scsi_find_entry(dev, h->dev, h->ndevices, &entry); if ((rc == DEVICE_SAME || rc == DEVICE_UPDATED) && entry >= 0 && entry < h->ndevices) { - this_device->supports_aborts = h->dev[entry]->supports_aborts; + dev->supports_aborts = h->dev[entry]->supports_aborts; spin_unlock_irqrestore(&h->devlock, flags); } else { spin_unlock_irqrestore(&h->devlock, flags); - this_device->supports_aborts = + dev->supports_aborts = hpsa_device_supports_aborts(h, scsi3addr); - if (this_device->supports_aborts < 0) - this_device->supports_aborts = 0; + if (dev->supports_aborts < 0) + dev->supports_aborts = 0; } - return 0; - -bail_out: - kfree(inq_buff); - return 1; } static unsigned char *ext_target_model[] = { @@ -3406,6 +3410,7 @@ static int add_ext_target_dev(struct ctlr_info *h, (*n_ext_target_devs)++; hpsa_set_bus_target_lun(this_device, tmpdevice->bus, tmpdevice->target, 0); + hpsa_update_device_supports_aborts(h, this_device, scsi3addr); set_bit(tmpdevice->target, lunzerobits); return 1; } @@ -3662,6 +3667,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) &is_OBDR)) continue; /* skip it if we can't talk to it. */ figure_bus_target_lun(h, lunaddrbytes, tmpdevice); + hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes); this_device = currentsd[ncurrent]; /* From 247f90d748f2bf9ae7ec287a455354d25290a02f Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:51 -0500 Subject: [PATCH 322/889] hpsa: use helper routines for finishing commands Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 58 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 851420434af66c..4824e4074a0ca4 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2129,6 +2129,21 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, return retry; /* retry on raid path? */ } +static void hpsa_cmd_free_and_done(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd) +{ + /* FIXME: should we clear c->scsi_cmd here? + * E.g., instead of doing it in complete_scsi_command() */ + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd->scsi_done(cmd); +} + +static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c) +{ + INIT_WORK(&c->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2139,11 +2154,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, /* check for good status */ if (likely(c2->error_data.serv_response == 0 && - c2->error_data.status == 0)) { - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - } + c2->error_data.status == 0)) + return hpsa_cmd_free_and_done(h, c, cmd); /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's @@ -2155,19 +2167,14 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (c2->error_data.status == IOACCEL2_STATUS_SR_IOACCEL_DISABLED) dev->offload_enabled = 0; - goto retry_cmd; + + return hpsa_retry_cmd(h, c); } if (handle_ioaccel_mode2_error(h, c, cmd, c2)) - goto retry_cmd; - - cmd_free(h, c); - cmd->scsi_done(cmd); - return; + return hpsa_retry_cmd(h, c); -retry_cmd: - INIT_WORK(&c->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); + return hpsa_cmd_free_and_done(h, c, cmd); } /* Returns 0 on success, < 0 otherwise. */ @@ -2235,9 +2242,7 @@ static void complete_scsi_command(struct CommandList *cp) if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) { /* DID_NO_CONNECT will prevent a retry */ cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, cp); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(h, cp, cmd); } if (cp->cmd_type == CMD_IOACCEL2) @@ -2247,9 +2252,7 @@ static void complete_scsi_command(struct CommandList *cp) if (ei->CommandStatus == 0) { if (cp->cmd_type == CMD_IOACCEL1) atomic_dec(&cp->phys_disk->ioaccel_cmds_out); - cmd_free(h, cp); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(h, cp, cmd); } /* For I/O accelerator commands, copy over some fields to the normal @@ -2271,10 +2274,7 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - INIT_WORK(&cp->work, hpsa_command_resubmit_worker); - queue_work_on(raw_smp_processor_id(), - h->resubmit_wq, &cp->work); - return; + return hpsa_retry_cmd(h, cp); } } @@ -2420,8 +2420,7 @@ static void complete_scsi_command(struct CommandList *cp) */ cp->scsi_cmd = NULL; - cmd_free(h, cp); - cmd->scsi_done(cmd); + return hpsa_cmd_free_and_done(h, cp, cmd); } static void hpsa_pci_unmap(struct pci_dev *pdev, @@ -4739,16 +4738,13 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) { struct scsi_cmnd *cmd; struct hpsa_scsi_dev_t *dev; - struct CommandList *c = - container_of(work, struct CommandList, work); + struct CommandList *c = container_of(work, struct CommandList, work); cmd = c->scsi_cmd; dev = cmd->device->hostdata; if (!dev) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(c->h, c); - cmd->scsi_done(cmd); - return; + return hpsa_cmd_free_and_done(c->h, c, cmd); } if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; From 17f10b1b2d92e80afb529a8f42711df74ea22fb5 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:52 -0500 Subject: [PATCH 323/889] hpsa: add pending abort flag to commands Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 40 ++++++++++++++++++++++++++++++++++++---- drivers/scsi/hpsa_cmd.h | 2 ++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4824e4074a0ca4..5ca7c3866e2eb3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1083,9 +1083,21 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, } } -static void enqueue_cmd_and_start_io(struct ctlr_info *h, - struct CommandList *c) +static void hpsa_mark_as_aborted(struct CommandList *c) +{ + struct ErrorInfo *ei = c->err_info; + + ei->CommandStatus = CMD_ABORTED; +} + +static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { + if (unlikely(c->abort_pending)) { + hpsa_mark_as_aborted(c); + finish_cmd(c); + return; + } + __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -2144,6 +2156,11 @@ static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c) queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } +static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd) +{ + cmd->result = DID_ABORT << 16; +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2157,6 +2174,12 @@ static void process_ioaccel2_completion(struct ctlr_info *h, c2->error_data.status == 0)) return hpsa_cmd_free_and_done(h, c, cmd); + /* don't requeue a command which is being aborted */ + if (unlikely(c->abort_pending)) { + hpsa_set_scsi_cmd_aborted(cmd); + return hpsa_cmd_free_and_done(h, c, cmd); + } + /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's * wrong. @@ -2274,10 +2297,14 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - return hpsa_retry_cmd(h, cp); + if (!cp->abort_pending) + return hpsa_retry_cmd(h, cp); } } + if (cp->abort_pending) + hpsa_mark_as_aborted(cp); + /* an error has occurred */ switch (ei->CommandStatus) { @@ -2365,7 +2392,7 @@ static void complete_scsi_command(struct CommandList *cp) cp->Request.CDB); break; case CMD_ABORTED: - cmd->result = DID_ABORT << 16; + hpsa_set_scsi_cmd_aborted(cmd); dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", cp->Request.CDB, ei->ScsiStatus); break; @@ -4746,6 +4773,10 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } + if (c->abort_pending) { + hpsa_set_scsi_cmd_aborted(cmd); + return hpsa_cmd_free_and_done(c->h, c, cmd); + } if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -5540,6 +5571,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } + abort->abort_pending = true; hpsa_get_tag(h, abort, &taglower, &tagupper); reply_queue = hpsa_extract_reply_queue(h, abort); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index cf3093dccd9f87..74f200e0256267 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -438,6 +438,8 @@ struct CommandList { * not used. */ struct hpsa_scsi_dev_t *phys_disk; + + int abort_pending; atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); From 2097a8bb74878209d79cf9a332fadc3535066705 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:52 -0500 Subject: [PATCH 324/889] hpsa: remove hpsa_mark_as_aborted() helper function Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5ca7c3866e2eb3..8be854639eca02 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1083,20 +1083,10 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, } } -static void hpsa_mark_as_aborted(struct CommandList *c) -{ - struct ErrorInfo *ei = c->err_info; - - ei->CommandStatus = CMD_ABORTED; -} - static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - if (unlikely(c->abort_pending)) { - hpsa_mark_as_aborted(c); - finish_cmd(c); - return; - } + if (unlikely(c->abort_pending)) + return finish_cmd(c); __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -2303,7 +2293,7 @@ static void complete_scsi_command(struct CommandList *cp) } if (cp->abort_pending) - hpsa_mark_as_aborted(cp); + ei->CommandStatus = CMD_ABORTED; /* an error has occurred */ switch (ei->CommandStatus) { From 0438824c92153628471a5474cd37275fd8a6ddf5 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:53 -0500 Subject: [PATCH 325/889] hpsa: move clearing of scsi_cmd to helper function Move the clearing of scsi_cmd from complete_scsi_command() to hpsa_cmd_free_and_done() to ensure that it is done in all cases. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8be854639eca02..33fef2a83a22a6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2134,8 +2134,21 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, static void hpsa_cmd_free_and_done(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd) { - /* FIXME: should we clear c->scsi_cmd here? - * E.g., instead of doing it in complete_scsi_command() */ + /* Prevent the following race in the abort handler: + * + * 1. LLD is requested to abort a SCSI command + * 2. The SCSI command completes + * 3. The struct CommandList associated with step 2 is made available + * 4. New I/O request to LLD to another LUN re-uses struct CommandList + * 5. Abort handler follows scsi_cmnd->host_scribble and + * finds struct CommandList and tries to aborts it + * Now we have aborted the wrong command. + * + * Clear c->scsi_cmd here so that if this command gets re-used, the + * abort handler will know it's a different scsi_cmnd. + */ + c->scsi_cmd = NULL; + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ cmd->scsi_done(cmd); } @@ -2423,20 +2436,6 @@ static void complete_scsi_command(struct CommandList *cp) cp, ei->CommandStatus); } - /* Prevent the following race in the abort handler: - * - * 1. LLD is requested to abort a scsi command - * 2. scsi command completes - * 3. The struct CommandList associated with 2 is made available. - * 4. new io request to LLD to another LUN re-uses struct CommandList - * 5. abort handler follows scsi_cmnd->host_scribble and - * finds struct CommandList and tries to aborts it. - * Now we have aborted the wrong command. - * Clear cp->scsi_cmd here so that if this get re-used, the abort - * handler will know it's a different scsi_cmnd. - */ - cp->scsi_cmd = NULL; - return hpsa_cmd_free_and_done(h, cp, cmd); } From bc2e92cf761f1f2611f8c337b8f18f481dd0561e Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:53 -0500 Subject: [PATCH 326/889] hpsa: if the current command has been aborted, do not call scsi_done() If the current command has been aborted, do not call the SCSI command completion routine from the I/O path: when the abort returns successfully, the SCSI mid-layer will handle the completion implicitly. Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 33fef2a83a22a6..3d420da71e0c1b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2164,6 +2164,16 @@ static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd) cmd->result = DID_ABORT << 16; } +static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, + struct scsi_cmnd *cmd) +{ + hpsa_set_scsi_cmd_aborted(cmd); + dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", + c->Request.CDB, c->err_info->ScsiStatus); + c->scsi_cmd = NULL; + cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ +} + static void process_ioaccel2_completion(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev) @@ -2178,10 +2188,8 @@ static void process_ioaccel2_completion(struct ctlr_info *h, return hpsa_cmd_free_and_done(h, c, cmd); /* don't requeue a command which is being aborted */ - if (unlikely(c->abort_pending)) { - hpsa_set_scsi_cmd_aborted(cmd); - return hpsa_cmd_free_and_done(h, c, cmd); - } + if (unlikely(c->abort_pending)) + return hpsa_cmd_abort_and_free(h, c, cmd); /* Any RAID offload error results in retry which will use * the normal I/O path so the controller can handle whatever's @@ -2395,10 +2403,8 @@ static void complete_scsi_command(struct CommandList *cp) cp->Request.CDB); break; case CMD_ABORTED: - hpsa_set_scsi_cmd_aborted(cmd); - dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", - cp->Request.CDB, ei->ScsiStatus); - break; + /* Return now to avoid calling scsi_done(). */ + return hpsa_cmd_abort_and_free(h, cp, cmd); case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n", @@ -4762,10 +4768,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } - if (c->abort_pending) { - hpsa_set_scsi_cmd_aborted(cmd); - return hpsa_cmd_free_and_done(c->h, c, cmd); - } + if (c->abort_pending) + return hpsa_cmd_abort_and_free(c->h, c, cmd); if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; From 91e185eb42cde9def4c7f62027096545d4056264 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:51:54 -0500 Subject: [PATCH 327/889] hpsa: don't return abort request until target is complete Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 3 +++ drivers/scsi/hpsa.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3d420da71e0c1b..d610735fc7316b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2172,6 +2172,7 @@ static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, c->Request.CDB, c->err_info->ScsiStatus); c->scsi_cmd = NULL; cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + wake_up_all(&h->abort_sync_wait_queue); } static void process_ioaccel2_completion(struct ctlr_info *h, @@ -5597,6 +5598,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); + wait_event(h->abort_sync_wait_queue, atomic_read(&abort->refcount) == 1); cmd_free(h, abort); return SUCCESS; } @@ -7924,6 +7926,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); + init_waitqueue_head(&h->abort_sync_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index d3a7b5299ec789..db450bd0964888 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -266,6 +266,7 @@ struct ctlr_info { struct workqueue_struct *resubmit_wq; atomic_t abort_cmds_available; wait_queue_head_t abort_cmd_wait_queue; + wait_queue_head_t abort_sync_wait_queue; }; struct offline_device_entry { From 10384b9400f1504755b0d0247f6dc1e8503370d3 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:54 -0500 Subject: [PATCH 328/889] hpsa: factor out hpsa_send_test_unit_ready function Factor out the code which sends the TEST_UNIT_READY from wait_for_device_to_become_ready() into its own function Move the code which waits for the TEST_UNIT_READY from wait_for_device_to_become_ready() into its own function Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 83 ++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d610735fc7316b..47533138824004 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5082,51 +5082,80 @@ static int hpsa_register_scsi(struct ctlr_info *h) return -ENOMEM; } -static int wait_for_device_to_become_ready(struct ctlr_info *h, - unsigned char lunaddr[]) +/* Send a TEST_UNIT_READY command to the specified LUN using the specified + * reply queue; returns zero if the unit is ready, and non-zero otherwise. */ +static int hpsa_send_test_unit_ready(struct ctlr_info *h, + struct CommandList *c, unsigned char lunaddr[], + int reply_queue) +{ + int rc; + + /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ + (void) fill_cmd(c, TEST_UNIT_READY, h, + NULL, 0, 0, lunaddr, TYPE_CMD); + rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + if (rc) + return rc; + /* no unmap needed here because no data xfer. */ + + /* Check if the unit is already ready. */ + if (c->err_info->CommandStatus == CMD_SUCCESS) + return 0; + + /* The first command sent after reset will receive "unit attention" to + * indicate that the LUN has been reset...this is actually what we're + * looking for (but, success is good too). */ + if (c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && + (c->err_info->SenseInfo[2] == NO_SENSE || + c->err_info->SenseInfo[2] == UNIT_ATTENTION)) + return 0; + + return 1; +} + +/* Wait for a TEST_UNIT_READY command to complete, retrying as necessary; + * returns zero when the unit is ready, and non-zero when giving up. */ +static int hpsa_wait_for_test_unit_ready(struct ctlr_info *h, struct CommandList *c, + unsigned char lunaddr[], int reply_queue) { int rc; int count = 0; int waittime = 1; /* seconds */ - struct CommandList *c; - - c = cmd_alloc(h); /* Send test unit ready until device ready, or give up. */ - while (count < HPSA_TUR_RETRY_LIMIT) { + for (count = 0; count < HPSA_TUR_RETRY_LIMIT; count++) { /* Wait for a bit. do this first, because if we send * the TUR right away, the reset will just abort it. */ msleep(1000 * waittime); - count++; - rc = 0; /* Device ready. */ + + rc = hpsa_send_test_unit_ready(h, c, lunaddr, reply_queue); + if (!rc) + break; /* Increase wait time with each try, up to a point. */ if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS) waittime = waittime * 2; - /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ - (void) fill_cmd(c, TEST_UNIT_READY, h, - NULL, 0, 0, lunaddr, TYPE_CMD); - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); - if (rc) - goto do_it_again; - /* no unmap needed here because no data xfer. */ + dev_warn(&h->pdev->dev, + "waiting %d secs for device to become ready.\n", + waittime); + } - if (c->err_info->CommandStatus == CMD_SUCCESS) - break; + return rc; +} - if (c->err_info->CommandStatus == CMD_TARGET_STATUS && - c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && - (c->err_info->SenseInfo[2] == NO_SENSE || - c->err_info->SenseInfo[2] == UNIT_ATTENTION)) - break; -do_it_again: - dev_warn(&h->pdev->dev, "waiting %d secs " - "for device to become ready.\n", waittime); - rc = 1; /* device not ready. */ - } +static int wait_for_device_to_become_ready(struct ctlr_info *h, + unsigned char lunaddr[]) +{ + int rc; + struct CommandList *c; + + c = cmd_alloc(h); + + rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, DEFAULT_REPLY_QUEUE); if (rc) dev_warn(&h->pdev->dev, "giving up on device.\n"); From 8bb3cadd68dd3819764bac459a627375a0398d45 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:55 -0500 Subject: [PATCH 329/889] hpsa: follow device resets with a TUR per reply queue to avoid races Since command completions may arrive on any reply queue, the completion of the reset doesn't mean that all affected commands' completions have been received and processed. This patch sends the test-unit-ready command multiple times specifying each reply queue; thus, when the last of the test unit ready completions is received, we can be sure that all affected commands have been completed. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 47533138824004..33a8270baebbe0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5148,14 +5148,34 @@ static int hpsa_wait_for_test_unit_ready(struct ctlr_info *h, struct CommandList } static int wait_for_device_to_become_ready(struct ctlr_info *h, - unsigned char lunaddr[]) + unsigned char lunaddr[], + int reply_queue) { - int rc; + int first_queue; + int last_queue; + int rq; + int rc = 0; struct CommandList *c; c = cmd_alloc(h); - rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, DEFAULT_REPLY_QUEUE); + /* If no specific reply queue was requested, then send the TUR + * repeatedly, requesting a reply on each reply queue; otherwise execute + * the loop exactly once using only the specified queue. */ + if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) { + first_queue = 0; + last_queue = h->nreply_queues - 1; + } else { + first_queue = reply_queue; + last_queue = reply_queue; + } + + for (rq = first_queue; rq <= last_queue; rq++) { + rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, + reply_queue == DEFAULT_REPLY_QUEUE ? rq : reply_queue); + if (rc) + break; + } if (rc) dev_warn(&h->pdev->dev, "giving up on device.\n"); @@ -5204,8 +5224,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, DEFAULT_REPLY_QUEUE); - if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) - return SUCCESS; + if (rc == 0) + if (!wait_for_device_to_become_ready(h, dev->scsi3addr, + DEFAULT_REPLY_QUEUE)) + return SUCCESS; dev_warn(&h->pdev->dev, "resetting scsi %d:%d:%d:%d failed\n", @@ -5395,7 +5417,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, } /* wait for device to recover */ - if (wait_for_device_to_become_ready(h, psa) != 0) { + if (wait_for_device_to_become_ready(h, psa, reply_queue) != 0) { dev_warn(&h->pdev->dev, "Reset as abort: Failed: Device never recovered from reset: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", psa[0], psa[1], psa[2], psa[3], From a33addf8f520a7a634813192f9dd679211eb05bf Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:56 -0500 Subject: [PATCH 330/889] hpsa: move SG descriptor set-up out of hpsa_scatter_gather() Move the code which sets up the SG descriptor out of hpsa_scatter_gather() and into a subroutine where it can be reused (in the next patch). The Ext field is now assigned unconditionally: this makes the refactor much simpler, but more importantly it removes a conditional operation from inside the loop. The case for which the conditional formerly tested is now executed (unconditionally) after the loop is exited. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 33a8270baebbe0..b54b75896e1a26 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3784,6 +3784,17 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) kfree(id_phys); } +static void hpsa_set_sg_descriptor(struct SGDescriptor *desc, + struct scatterlist *sg) +{ + u64 addr64 = (u64) sg_dma_address(sg); + unsigned int len = sg_dma_len(sg); + + desc->Addr = cpu_to_le64(addr64); + desc->Len = cpu_to_le32(len); + desc->Ext = 0; +} + /* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci * dma mapping and fills in the scatter gather entries of the * hpsa command, cp. @@ -3792,9 +3803,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct CommandList *cp, struct scsi_cmnd *cmd) { - unsigned int len; struct scatterlist *sg; - u64 addr64; int use_sg, i, sg_index, chained, last_sg; struct SGDescriptor *curr_sg; @@ -3818,14 +3827,13 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = h->cmd_sg_list[cp->cmdindex]; sg_index = 0; } - addr64 = (u64) sg_dma_address(sg); - len = sg_dma_len(sg); - curr_sg->Addr = cpu_to_le64(addr64); - curr_sg->Len = cpu_to_le32(len); - curr_sg->Ext = cpu_to_le32((i == last_sg) * HPSA_SG_LAST); + hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; } + /* Back the pointer up to the last entry and mark it as "last". */ + (curr_sg - 1)->Ext = cpu_to_le32(HPSA_SG_LAST); + if (use_sg + chained > h->maxSG) h->maxSG = use_sg + chained; From 11d708cb1865507e90924cbba3f155a24f23dfdb Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:56 -0500 Subject: [PATCH 331/889] hpsa: performance tweak for hpsa_scatter_gather() Divide the loop in hpsa_scatter_gather() into two, one for the initial SG list and a second one for the chained list, if any. This allows the conditional check which resets the indicies for the chained list to be performed outside the loop instead of being done on every iteration inside the loop. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b54b75896e1a26..0bffb073d2027e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3804,7 +3804,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct scsi_cmnd *cmd) { struct scatterlist *sg; - int use_sg, i, sg_index, chained, last_sg; + int use_sg, i, sg_limit, chained, last_sg; struct SGDescriptor *curr_sg; BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); @@ -3816,21 +3816,33 @@ static int hpsa_scatter_gather(struct ctlr_info *h, if (!use_sg) goto sglist_finished; + /* If the number of entries is greater than the max for a single list, + * then we have a chained list; we will set up all but one entry in the + * first list (the last entry is saved for link information); + * otherwise, we don't have a chained list and we'll set up at each of + * the entries in the one list. */ curr_sg = cp->SG; - chained = 0; - sg_index = 0; + chained = use_sg > h->max_cmd_sg_entries; + sg_limit = chained ? h->max_cmd_sg_entries - 1 : use_sg; last_sg = scsi_sg_count(cmd) - 1; - scsi_for_each_sg(cmd, sg, use_sg, i) { - if (i == h->max_cmd_sg_entries - 1 && - use_sg > h->max_cmd_sg_entries) { - chained = 1; - curr_sg = h->cmd_sg_list[cp->cmdindex]; - sg_index = 0; - } + scsi_for_each_sg(cmd, sg, sg_limit, i) { hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; } + if (chained) { + /* Continue with the chained list. Set curr_sg to the chained + * list. Modify the limit to the total count less the entries + * we've already set up. Resume the scan at the list entry + * where the previous loop left off. */ + curr_sg = h->cmd_sg_list[cp->cmdindex]; + sg_limit = use_sg - sg_limit; + for_each_sg(sg, sg, sg_limit, i) { + hpsa_set_sg_descriptor(curr_sg, sg); + curr_sg++; + } + } + /* Back the pointer up to the last entry and mark it as "last". */ (curr_sg - 1)->Ext = cpu_to_le32(HPSA_SG_LAST); From d8747aef5f53a6e7be2bc5586e10f4c56e5e8368 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:57 -0500 Subject: [PATCH 332/889] hpsa: restructure simple controller command interface/implementation, step 1. Rename hpsa_scsi_do_simple_cmd_core() to hpsa_scsi_do_simple_cmd(), since this function is the interface for issuing commands to the controller and not the "core" of that implementation. Add a parameter to it which allows the caller to specify the reply queue to be used. Modify existing callers to specify the default reply queue. Modify the existing callers of this routine (other than hpsa_scsi_do_simple_cmd()) to instead call hpsa_scsi_do_simple_cmd(), since it will now accept the reply_queue paramenter, and it provides a controller lock-up check. (Also, tweak two related message strings to make them distinct from each other.) Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0bffb073d2027e..ce148124759f75 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2488,7 +2488,7 @@ static int hpsa_map_one(struct pci_dev *pdev, #define NO_TIMEOUT ((unsigned long) -1) #define DEFAULT_TIMEOUT (30000) /* milliseconds */ -static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, +static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, struct CommandList *c, int reply_queue, unsigned long timeout_msecs) { DECLARE_COMPLETION_ONSTACK(wait); @@ -2508,15 +2508,14 @@ static int __hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, return 0; } -static int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c, unsigned long timeout_msecs) +static int hpsa_scsi_do_simple_cmd(struct ctlr_info *h, struct CommandList *c, + int reply_queue, unsigned long timeout_msecs) { if (unlikely(lockup_detected(h))) { c->err_info->CommandStatus = CMD_CTLR_LOCKUP; return 0; } - return __hpsa_scsi_do_simple_cmd_core(h, c, - DEFAULT_REPLY_QUEUE, timeout_msecs); + return hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, timeout_msecs); } static u32 lockup_detected(struct ctlr_info *h) @@ -2540,7 +2539,8 @@ static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, do { memset(c->err_info, 0, sizeof(*c->err_info)); - rc = hpsa_scsi_do_simple_cmd_core(h, c, timeout_msecs); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, + timeout_msecs); if (rc) break; retry_count++; @@ -2719,7 +2719,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ - rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); goto out; @@ -3132,7 +3132,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, c = cmd_alloc(h); (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD); - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (rc) { cmd_free(h, c); return 0; @@ -3205,7 +3205,7 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, c = cmd_alloc(h); (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG); - (void) __hpsa_scsi_do_simple_cmd_core(h, c, 0, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, 0, NO_TIMEOUT); /* no unmap needed here because no data xfer. */ ei = c->err_info; switch (ei->CommandStatus) { @@ -5113,7 +5113,7 @@ static int hpsa_send_test_unit_ready(struct ctlr_info *h, /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - rc = __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) return rc; /* no unmap needed here because no data xfer. */ @@ -5307,9 +5307,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 0, 0, scsi3addr, TYPE_MSG); if (h->needs_abort_tags_swizzled) swizzle_abort_tag(&c->Request.CDB[4]); - (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); - dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd(abort) completed.\n", __func__, tagupper, taglower); /* no unmap needed here because no data xfer. */ @@ -5470,10 +5470,10 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h, c = cmd_alloc(h); setup_ioaccel2_abort_cmd(c, h, abort, reply_queue); c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - (void) __hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, NO_TIMEOUT); + (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); hpsa_get_tag(h, abort, &taglower, &tagupper); dev_dbg(&h->pdev->dev, - "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + "%s: Tag:0x%08x:%08x: do_simple_cmd(ioaccel2 abort) completed.\n", __func__, tagupper, taglower); /* no unmap needed here because no data xfer. */ @@ -5943,7 +5943,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = cpu_to_le32(iocommand.buf_size); c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */ } - rc = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (rc) rc = -EIO; if (iocommand.buf_size > 0) @@ -6073,7 +6073,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) cpu_to_le32((i == sg_used) * HPSA_SG_LAST); } } - status = hpsa_scsi_do_simple_cmd_core(h, c, NO_TIMEOUT); + status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (status) { status = -EIO; goto cleanup0; From 7430a416415f179a25b2ca8db5abcdf168c97d8f Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:57 -0500 Subject: [PATCH 333/889] hpsa: refactor worker requeue code Refactor common code from hpsa_requeue_worker() and hpsa_rescan_ctlr_worker() which requeues the work item and place it in a separate routine, to encapsulate the conditional and make the code consistent (and remove a bug). Signed-off-by: Webb Scales --- drivers/scsi/hpsa.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ce148124759f75..d39b3ab9861cbe 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7779,9 +7779,18 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } -static void hpsa_rescan_ctlr_worker(struct work_struct *work) +static void hpsa_requeue_worker(struct ctlr_info *h, struct delayed_work *wi) { unsigned long flags; + + spin_lock_irqsave(&h->lock, flags); + if (!h->remove_in_progress) + schedule_delayed_work(wi, h->heartbeat_sample_interval); + spin_unlock_irqrestore(&h->lock, flags); +} + +static void hpsa_rescan_ctlr_worker(struct work_struct *work) +{ struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, rescan_ctlr_work); @@ -7791,32 +7800,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work) hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); } - spin_lock_irqsave(&h->lock, flags); - if (h->remove_in_progress) { - spin_unlock_irqrestore(&h->lock, flags); - return; - } - schedule_delayed_work(&h->rescan_ctlr_work, - h->heartbeat_sample_interval); - spin_unlock_irqrestore(&h->lock, flags); + + hpsa_requeue_worker(h, &h->rescan_ctlr_work); } static void hpsa_monitor_ctlr_worker(struct work_struct *work) { - unsigned long flags; struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, monitor_ctlr_work); detect_controller_lockup(h); if (lockup_detected(h)) return; - spin_lock_irqsave(&h->lock, flags); - if (h->remove_in_progress) - spin_unlock_irqrestore(&h->lock, flags); - else - schedule_delayed_work(&h->monitor_ctlr_work, - h->heartbeat_sample_interval); - spin_unlock_irqrestore(&h->lock, flags); + hpsa_requeue_worker(h, &h->monitor_ctlr_work); } static void check_board_id_tables(void) From 64e9d1a5be091ebb1a1c847d3ef525a34d1aba78 Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:51:58 -0500 Subject: [PATCH 334/889] hpsa: refactor hpsa_find_board_params() to encapsulate legacy test Encapsulate the conditional predicate which tests for legacy controllers in a separate function and rework the code comments. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d39b3ab9861cbe..09fb8ab53b7e09 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7139,6 +7139,15 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) } } +/* If the controller reports that the total max sg entries is greater than 512, + * then we know that chained SG blocks work. (Original smart arrays did not + * support chained SG blocks and would return zero for max sg entries.) + */ +static int hpsa_supports_chained_sg_blocks(struct ctlr_info *h) +{ + return h->maxsgentries > 512; +} + /* Interrogate the hardware for some limits: * max commands, max SG elements without chaining, and with chaining, * SG chain block size, etc. @@ -7149,18 +7158,20 @@ static void hpsa_find_board_params(struct ctlr_info *h) h->nr_cmds = h->max_commands; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); - /* - * Limit in-command s/g elements to 32 save dma'able memory. - * Howvever spec says if 0, use 31 - */ - h->max_cmd_sg_entries = 31; - if (h->maxsgentries > 512) { + if (hpsa_supports_chained_sg_blocks(h)) { + /* Limit in-command s/g elements to 32 save dma'able memory. */ h->max_cmd_sg_entries = 32; h->chainsize = h->maxsgentries - h->max_cmd_sg_entries; h->maxsgentries--; /* save one for chain pointer */ } else { - h->chainsize = 0; + /* Original smart arrays supported at most 31 scatter gather + * entries embedded inline in the command (trying to use more + * would lock up the controller, see + * https://lkml.org/lkml/2001/12/4/139 ). + */ + h->max_cmd_sg_entries = 31; h->maxsgentries = 31; /* default to traditional values */ + h->chainsize = 0; } /* Find out what task management functions are supported and cache */ From 6978ad977c55ffa3a1aea77c00fc51bea777b4a7 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Tue, 28 Oct 2014 11:51:58 -0500 Subject: [PATCH 335/889] hpsa: move test out of set_encrypt_ioaccel2 to avoid function call overhead Signed-off-by: Joe Handzik Signed-off-by: Stephen M. Cameron Reviewed-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 09fb8ab53b7e09..2efcb4e73193f3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4029,18 +4029,14 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, * Set encryption parameters for the ioaccel2 request */ static void set_encrypt_ioaccel2(struct ctlr_info *h, - struct CommandList *c, struct io_accel2_cmd *cp) + struct CommandList *c, struct io_accel2_cmd *cp, u16 dekindex) { struct scsi_cmnd *cmd = c->scsi_cmd; struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; struct raid_map_data *map = &dev->raid_map; u64 first_block; - /* Are we doing encryption on this device */ - if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON)) - return; - /* Set the data encryption key index. */ - cp->dekindex = map->dekindex; + cp->dekindex = dekindex; /* Set the encryption enable flag, encoded into direction field. */ cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK; @@ -4238,7 +4234,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } /* Set encryption parameters, if necessary */ - set_encrypt_ioaccel2(h, c, cp); + if (phys_disk->raid_map.flags & RAID_MAP_FLAG_ENCRYPT_ON) + set_encrypt_ioaccel2(h, c, cp, phys_disk->raid_map.dekindex); cp->scsi_nexus = ioaccel_handle; cp->Tag = c->cmdindex << DIRECT_LOOKUP_SHIFT; From 4ad39ef06448f07ea74191b1803afde398ee0e17 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:51:59 -0500 Subject: [PATCH 336/889] hpsa: use block layer tag for command allocation Modify cmd_tagged_allocation() to crash when it receives a bad tag from the block layer, instead of returning a NULL pointer and letting the next layer up fail: we should never get a bad tag, and if we do it means that the system is misconfigured (e.g., that the scsi-mq support is not enabled), and it would be best to die a clean, swift death before anyone gets hurt. Limit the search for free cmd blocks to only the reserved range, and remove the optimization which avoids starting the search at the beginning of the range. Remove the reserved_cmds commands field from the controller info structure and replace references to it with a #define'd symbol. Add a build-time assertion that the minimum number of available commands is greater than the number which are reserved by the driver to ensure that we can do at least some I/O. Replace the magic number used for the minimum number of commands with at #define'd symbol. reserve part of the tag space for the driver move tag selection to a helper function If the blk-mq support isn't available, set up the SCSI tagged command queuing (tcq) and use the SCSI midlayer tag. Signed-off-by: Webb Scales Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 177 ++++++++++++++++++++++++++++++++++++-------- drivers/scsi/hpsa.h | 1 - 2 files changed, 147 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2efcb4e73193f3..de3c4eb79c5a03 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -204,6 +204,9 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); static void cmd_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); +static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c); +static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, + struct scsi_cmnd *scmd); static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type); @@ -867,6 +870,9 @@ static struct device_attribute *hpsa_shost_attrs[] = { NULL, }; +#define HPSA_NRESERVED_CMDS (HPSA_CMDS_RESERVED_FOR_ABORTS + \ + HPSA_CMDS_RESERVED_FOR_DRIVER + HPSA_MAX_CONCURRENT_PASSTHRUS) + static struct scsi_host_template hpsa_driver_template = { .module = THIS_MODULE, .name = HPSA, @@ -1847,10 +1853,22 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); if (sd && (sd->expose_state & HPSA_SCSI_ADD)) { + int queue_depth = sd->queue_depth; + + if (queue_depth == 0) + queue_depth = sdev->host->can_queue; + sdev->hostdata = sd; - if (sd->queue_depth) + + if (shost_use_blk_mq(sdev->host)) { scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - sd->queue_depth); + queue_depth); + } else { + /* We depend on tags for cmd allocation. */ + BUG_ON(!sdev->tagged_supported); + scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); + scsi_activate_tcq(sdev, queue_depth); + } atomic_set(&sd->ioaccel_cmds_out, 0); } else { sdev->hostdata = NULL; @@ -2148,8 +2166,7 @@ static void hpsa_cmd_free_and_done(struct ctlr_info *h, * abort handler will know it's a different scsi_cmnd. */ c->scsi_cmd = NULL; - - cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd_tagged_free(h, c); cmd->scsi_done(cmd); } @@ -2171,7 +2188,7 @@ static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c, dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", c->Request.CDB, c->err_info->ScsiStatus); c->scsi_cmd = NULL; - cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */ + cmd_tagged_free(h, c); wake_up_all(&h->abort_sync_wait_queue); } @@ -4690,7 +4707,7 @@ static int hpsa_ciss_submit(struct ctlr_info *h, } if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } enqueue_cmd_and_start_io(h, c); @@ -4756,7 +4773,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (rc == 0) return 0; /* Sent on ioaccel path */ if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } } else if (dev->hba_ioaccel_enabled) { @@ -4767,7 +4784,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (rc == 0) return 0; /* Sent on direct map path */ if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); + cmd_tagged_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } } @@ -4853,11 +4870,11 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); return 0; } - c = cmd_alloc(h); + c = cmd_tagged_alloc(h, cmd); if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; - cmd_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ + cmd_tagged_free(h, c); /* FIXME may not be necessary, as lockup detector also frees everything */ cmd->scsi_done(cmd); return 0; } @@ -5037,13 +5054,25 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) { if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else + if (shost_use_blk_mq(sdev->host)) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else { + /* We require tags for our internal cmd allocation; if + * the caller wants to switch tag types, that's fine, + * but don't let them be disabled. */ + if (tag_type) + scsi_set_tag_type(sdev, tag_type); + else + tag_type = scsi_get_tag_type(sdev); + } + } else { + BUG_ON(!shost_use_blk_mq(sdev->host)); tag_type = 0; + } return tag_type; } @@ -5072,16 +5101,18 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds - - HPSA_CMDS_RESERVED_FOR_ABORTS - - HPSA_CMDS_RESERVED_FOR_DRIVER - - HPSA_MAX_CONCURRENT_PASSTHRUS; + sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; + if (!shost_use_blk_mq(sh)) { + error = scsi_init_shared_tag_map(sh, sh->can_queue); + if (error) + goto fail_host_put; + } error = scsi_add_host(sh, &h->pdev->dev); if (error) goto fail_host_put; @@ -5671,6 +5702,82 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return SUCCESS; } +/* + * One of the upper layers has already gone to the trouble of picking out a + * unique, small-integer tag for this request. If the blk-mq support is not + * available, we use the SCSI tag in the SCSI command; otherwise, we use the + * block layer tag in the embedded request structure. We use an offset from + * that value as an index to select our command block. (The offset allows us to + * reserve the low-numbered entries for our own uses.) + */ +static int hpsa_get_cmd_index(struct scsi_cmnd *scmd) +{ + struct scsi_device *dev = scmd->device; + int idx = shost_use_blk_mq(dev->host) ? scmd->request->tag : scmd->tag; + + if (idx < 0) { + dev_err(&dev->sdev_dev , "Invalid block tag: %d\n", idx); + /* This value comes from an upper layer...it's not our bug. */ + BUG_ON(idx < 0); + } + + /* Offset to leave space for internal cmds. */ + idx += HPSA_NRESERVED_CMDS; + + return idx; +} + +/* + * For operations with an associated SCSI command, a command block is allocated + * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the + * block request tag as an index into a table of entries. cmd_tagged_free() is + * the complement, although cmd_free() may be called instead. + */ +static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, + struct scsi_cmnd *scmd) +{ + int idx = hpsa_get_cmd_index(scmd); + struct CommandList *c = h->cmd_pool + idx; + int refcount = 0; + + if (idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds) { + dev_err(&h->pdev->dev, "Bad block tag: %d\n", idx); + /* The index value comes from the block layer, so if it's out of + * bounds, it's probably not our bug. + */ + BUG_ON(idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds); + } + + refcount = atomic_inc_return(&c->refcount); + if (unlikely(refcount > 1)) { + /* + * We expect that the SCSI layer will hand us a unique tag + * value. Thus, there should never be a collision here between + * two requests; however, it's possible that a lingering abort + * might have an outstanding reference when the next request + * comes in (the block layer tends to reuse the last-used tag + * first). Hopefully, that won't be a problem. + */ + dev_warn(&h->pdev->dev, + "tag collision (tag=%d) in cmd_tagged_alloc().\n", + idx); + } + + hpsa_cmd_partial_init(h, idx, c); + return c; +} + +static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c) +{ + /* + * Release our reference to the block. We don't need to do anything + * else to free it, because it is accessed by index. (There's no point + * in checking the result of the decrement, since we cannot guarantee + * that there isn't a concurrent abort which is also accessing it.) + */ + (void)atomic_dec_and_test(&c->refcount); +} + /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -5683,7 +5790,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) { struct CommandList *c; int refcount, i; - unsigned long offset; /* There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could @@ -5694,31 +5800,39 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * very unlucky thread might be starved anyway, never able to * beat the other threads. In reality, this happens so * infrequently as to be indistinguishable from never. + * + * Note that we start allocating commands before the SCSI host structure + * is initialized. Since the search starts at bit zero, this + * all works, since we have at least one command structure available; + * however, it means that the structures with the low indexes have to be + * reserved for driver-initiated requests, while requests from the block + * layer will use the higher indexes. */ - offset = h->last_allocation; /* benighly racy */ for (;;) { - i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); - if (unlikely(i == h->nr_cmds)) { - offset = 0; + i = find_first_zero_bit(h->cmd_pool_bits, HPSA_NRESERVED_CMDS); + if (unlikely(i >= HPSA_NRESERVED_CMDS)) continue; - } c = h->cmd_pool + i; refcount = atomic_inc_return(&c->refcount); if (unlikely(refcount > 1)) { cmd_free(h, c); /* already in use */ - offset = (i + 1) % h->nr_cmds; continue; } set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); break; /* it's ours now. */ } - h->last_allocation = i; /* benignly racy */ hpsa_cmd_partial_init(h, i, c); return c; } +/* + * This is the complementary operation to cmd_alloc(). Note, however, in some + * corner cases it may also be used to free blocks allocated by + * cmd_tagged_alloc() in which case the ref-count decrement does the trick and + * the clear-bit is harmless. + */ static void cmd_free(struct ctlr_info *h, struct CommandList *c) { if (atomic_dec_and_test(&c->refcount)) { @@ -7121,18 +7235,21 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) { +#define MIN_MAX_COMMANDS 16 + BUILD_BUG_ON(MIN_MAX_COMMANDS <= HPSA_NRESERVED_CMDS); + h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); /* Limit commands in memory limited kdump scenario. */ if (reset_devices && h->max_commands > 32) h->max_commands = 32; - if (h->max_commands < 16) { + if (h->max_commands < MIN_MAX_COMMANDS) { dev_warn(&h->pdev->dev, "Controller reports " "max supported commands of %d, an obvious lie. " "Using 16. Ensure that firmware is up to date.\n", h->max_commands); - h->max_commands = 16; + h->max_commands = MIN_MAX_COMMANDS; } } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index db450bd0964888..187bb0d47974bf 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -141,7 +141,6 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; - int last_allocation; atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 From 6c08fb9ed2bce0307c76a515376c6d0c9d6406fc Mon Sep 17 00:00:00 2001 From: Webb Scales Date: Tue, 28 Oct 2014 11:52:00 -0500 Subject: [PATCH 337/889] hpsa: remove unneeded lockup check Signed-off-by: Webb Scaled Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index de3c4eb79c5a03..e2c3c3f1727e14 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4943,6 +4943,8 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; } +======= +>>>>>>> patched /* Call alternate submit routine for I/O accelerated commands. * Retries always go down the normal I/O path. */ From 792172495c7e12931b2e4132613472270fbe3fa0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:52:00 -0500 Subject: [PATCH 338/889] hpsa: abort torture test code This is just debug/test code. Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 64 ++++++++++++++++++++++++++++++++++++++++- drivers/scsi/hpsa.h | 3 ++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e2c3c3f1727e14..199147115ee0ee 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -54,7 +54,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.8-0" +#define HPSA_DRIVER_VERSION "3.4.9-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -391,6 +391,39 @@ static ssize_t host_show_lockup_detector(struct device *dev, return snprintf(buf, 20, "%d\n", h->lockup_detector_enabled); } +static ssize_t host_store_abort_test(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost; + struct ctlr_info *h; + int len, value, timeout; + char tmpbuf[10]; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; + strncpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + if (sscanf(tmpbuf, "%d %d", &value, &timeout) != 2) + return -EINVAL; + shost = class_to_shost(dev); + h = shost_to_hba(shost); + h->abort_test = value; + h->abort_timeout = timeout; + return count; +} + +static ssize_t host_show_abort_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + + h = shost_to_hba(shost); + return snprintf(buf, 20, "%d %d\n", h->abort_test, h->abort_timeout); +} + static u32 lockup_detected(struct ctlr_info *h); static ssize_t host_show_lockup_detected(struct device *dev, struct device_attribute *attr, char *buf) @@ -846,6 +879,8 @@ static DEVICE_ATTR(lockup_detector, S_IWUSR|S_IRUGO, host_show_lockup_detector, host_store_lockup_detector); static DEVICE_ATTR(lockup_detected, S_IRUGO, host_show_lockup_detected, NULL); +static DEVICE_ATTR(abort_test, S_IWUSR|S_IRUGO, + host_show_abort_test, host_store_abort_test); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -867,6 +902,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_raid_offload_debug, &dev_attr_lockup_detector, &dev_attr_lockup_detected, + &dev_attr_abort_test, NULL, }; @@ -1065,11 +1101,36 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; } +static void __enqueue_cmd_and_start_io(struct ctlr_info *h, + struct CommandList *c, int reply_queue); + +static void hpsa_abort_torture_worker(struct work_struct *work) +{ + struct CommandList *c = container_of(to_delayed_work(work), + struct CommandList, abort_torture_work); + dev_warn(&c->h->pdev->dev, "Submitting delayed command\n"); + __enqueue_cmd_and_start_io(c->h, c, DEFAULT_REPLY_QUEUE); +} + static void __enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c, int reply_queue) { + if (h->abort_test > 0 && + (c->cmd_type == CMD_SCSI || + c->cmd_type == CMD_IOACCEL1|| + c->cmd_type == CMD_IOACCEL2)) { + h->abort_test = 0; + dev_warn(&h->pdev->dev, "delaying command for %d secs.\n", + h->abort_timeout); + INIT_DELAYED_WORK(&c->abort_torture_work, + hpsa_abort_torture_worker); + schedule_delayed_work(&c->abort_torture_work, h->abort_timeout * HZ); + atomic_inc(&h->cmds_sent); + return; + } dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); + atomic_inc(&h->cmds_sent); switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c, reply_queue); @@ -8065,6 +8126,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->scan_lock); atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); + atomic_set(&h->cmds_sent, 0); h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 187bb0d47974bf..f364bff8851977 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -266,6 +266,9 @@ struct ctlr_info { atomic_t abort_cmds_available; wait_queue_head_t abort_cmd_wait_queue; wait_queue_head_t abort_sync_wait_queue; + atomic_t cmds_sent; + int abort_test; + int abort_timeout; }; struct offline_device_entry { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 74f200e0256267..5ab1b13f996f83 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -428,6 +428,7 @@ struct CommandList { struct completion *waiting; struct scsi_cmnd *scsi_cmd; struct work_struct work; + struct delayed_work abort_torture_work; /* For commands using either of the two "ioaccel" paths to * bypass the RAID stack and go directly to the physical disk From 3d0b31e6c83f26f8a0ef7d6b678672bebaca4870 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:52:01 -0500 Subject: [PATCH 339/889] hpsa: fix bad lun and target update messages lun and target were being printed as -1 instead of the correct values Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 199147115ee0ee..3a776b54fbcb3b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1325,16 +1325,17 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, dev_info(&h->pdev->dev, "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", - hostno, new_entry->bus, new_entry->target, new_entry->lun, - scsi_device_type(new_entry->devtype), - new_entry->vendor, - new_entry->model, - new_entry->raid_level > RAID_UNKNOWN ? - "RAID-?" : raid_label[new_entry->raid_level], - new_entry->offload_config ? '+' : '-', - new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state, - new_entry->queue_depth); + hostno, h->dev[entry]->bus, + h->dev[entry]->target, h->dev[entry]->lun, + scsi_device_type(h->dev[entry]->devtype), + h->dev[entry]->vendor, + h->dev[entry]->model, + h->dev[entry]->raid_level > RAID_UNKNOWN ? + "RAID-?" : raid_label[h->dev[entry]->raid_level], + h->dev[entry]->offload_config ? '+' : '-', + h->dev[entry]->offload_enabled ? '+' : '-', + h->dev[entry]->expose_state, + h->dev[entry]->queue_depth); } /* Replace an entry from h->dev[] array. */ From f4b98d9dad78b12cd4923ccd35d41cfb67719923 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:52:01 -0500 Subject: [PATCH 340/889] hpsa: do not poll device with TUR after device reset If a logical drive has failed, resetting it will ensure outstanding commands are completed, but polling it with TURs after the reset will not work because the TURs will never report good status. So successful TUR should not be a condition of success for the device reset error handler. NOTE: THERE IS A PROBLEM WITH THIS PATCH. While it fixes the problem that a failed logical drive will never become ready, and so fixes the problem that the reset device error handler would get stuck for too long waiting for a failed logical drive to become ready, it defeats the purpose of that barrage of test unit readys, which was to avoid races of the completions of aborted commands with the device reset command completion in the completion queues. So, an alternative solution for those races is needed (webb is working on this). Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3a776b54fbcb3b..69bac60bc27936 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5337,9 +5337,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN, DEFAULT_REPLY_QUEUE); if (rc == 0) - if (!wait_for_device_to_become_ready(h, dev->scsi3addr, - DEFAULT_REPLY_QUEUE)) - return SUCCESS; + return SUCCESS; dev_warn(&h->pdev->dev, "resetting scsi %d:%d:%d:%d failed\n", From 46318d0fb859c3732d3b3a5d666e9cbe106a4e61 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:02 -0500 Subject: [PATCH 341/889] hpsa: fix queue_depth calculation for all RAID levels The logical drive queue_depth is ending up 1024 for RAID-5 made from 4 physical drives and other more complex RAID levels, which is too high. The calculation is being confused by parity rotation, ending up adding the depths supported by the drives for each different rotation combination (row_cnt). Stop counting after the true number of physical drives, which is: map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row) Signed-off-by: Robert Elliott --- drivers/scsi/hpsa.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 69bac60bc27936..22575ce636b3ee 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1636,6 +1636,8 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, int i, j; int nraid_map_entries = map->row_cnt * map->layout_map_count * (map->data_disks_per_row + map->metadata_disks_per_row); + int nphys_disk = map->layout_map_count * + (map->data_disks_per_row + map->metadata_disks_per_row); int qdepth; if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) @@ -1655,8 +1657,9 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, continue; logical_drive->phys_disk[i] = dev[j]; - qdepth = min(h->nr_cmds, qdepth + - logical_drive->phys_disk[i]->queue_depth); + if (i < nphys_disk) + qdepth = min(h->nr_cmds, qdepth + + logical_drive->phys_disk[i]->queue_depth); break; } From 0f5242005e16fcdb08f544663b551443db9ca77a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:02 -0500 Subject: [PATCH 342/889] hpsa: remove 0x from queue depth print which is in decimal The queue depth printed at startup is in decimal, so shouldn't have a 0x prefix. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 22575ce636b3ee..6d5026a6c94c07 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7063,7 +7063,7 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb) readl(&(tb->HostWrite.CoalIntDelay))); dev_info(dev, " Coalesce Interrupt Count = 0x%x\n", readl(&(tb->HostWrite.CoalIntCount))); - dev_info(dev, " Max outstanding commands = 0x%d\n", + dev_info(dev, " Max outstanding commands = %d\n", readl(&(tb->CmdsOutMax))); dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes))); for (i = 0; i < 16; i++) From fd5da3cb87ef6726f35f96c34b075cecc5a00681 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:03 -0500 Subject: [PATCH 343/889] hpsa: clean up register_scsi clean up new block layer tag error handling Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6d5026a6c94c07..ff047628a8b598 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5177,18 +5177,23 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->unique_id = sh->irq; if (!shost_use_blk_mq(sh)) { error = scsi_init_shared_tag_map(sh, sh->can_queue); - if (error) + if (error) { + dev_err(&h->pdev->dev, + "%s: scs_init_shared_tag_map failed for controller %d\n", + __func__, h->ctlr); goto fail_host_put; + } } error = scsi_add_host(sh, &h->pdev->dev); - if (error) + if (error) { + dev_err(&h->pdev->dev, "%s: scsi_add_host failed for controller %d\n", + __func__, h->ctlr); goto fail_host_put; + } scsi_scan_host(sh); return 0; fail_host_put: - dev_err(&h->pdev->dev, "%s: scsi_add_host" - " failed for controller %d\n", __func__, h->ctlr); scsi_host_put(sh); return error; fail: From 7cc3b97f2364d556e67da7a2056845c9e67397d4 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:04 -0500 Subject: [PATCH 344/889] hpsa: propagate errors in ioacccel2_sg_chain_blocks The error, if any, returned by hpsa_allocate_ioaccel2_sg_chain_blocks to hpsa_alloc_ioaccel2_cmd_and_bft should be returned upstream rather than assumed to be -ENOMEM. This differs slightly from hpsa_alloc_ioaccel1_cmd_and_bft, which does not call another hpsa_allocate function and only has -ENOMEM to return from some kmalloc calls. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ff047628a8b598..0e2801789a0ba8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8693,6 +8693,8 @@ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) /* Allocate ioaccel2 mode command blocks and block fetch table */ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) { + int rc; + /* Allocate ioaccel2 mode command blocks and block fetch table */ h->ioaccel_maxsg = @@ -8712,10 +8714,13 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) sizeof(u32)), GFP_KERNEL); if ((h->ioaccel2_cmd_pool == NULL) || - (h->ioaccel2_blockFetchTable == NULL)) + (h->ioaccel2_blockFetchTable == NULL)) { + rc = -ENOMEM; goto clean_up; + } - if (hpsa_allocate_ioaccel2_sg_chain_blocks(h)) + rc = hpsa_allocate_ioaccel2_sg_chain_blocks(h); + if (rc) goto clean_up; memset(h->ioaccel2_cmd_pool, 0, @@ -8724,7 +8729,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) clean_up: hpsa_free_ioaccel2_cmd_and_bft(h); - return -ENOMEM; + return rc; } /* Free items allocated by hpsa_put_ctlr_into_performant_mode */ From 329cb57701d6e628c39a206b623ab5de564d1bce Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:04 -0500 Subject: [PATCH 345/889] hpsa: free ioaccel2_sg_chain_blocks correctly hpsa_put_ctlr_into_performant_mode is the function that allocates ioaccel2_sg_chain_blocks (via hpsa_alloc_ioaccel2_cmd_and_bft), so hpsa_free_performant_mode should free it (via hpsa_free_ioaccel2_cmd_and_bft). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0e2801789a0ba8..edd947d8d68333 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7775,7 +7775,6 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_performant_mode(h); /* init_one 7 */ - hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ @@ -8379,7 +8378,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ hpsa_unregister_scsi(h); /* init_one "8" */ - hpsa_free_ioaccel2_sg_chain_blocks(h); kfree(h->hba_inquiry_data); /* init_one "8" */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ @@ -8683,6 +8681,8 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) /* Free ioaccel2 mode command blocks and block fetch table */ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) { + hpsa_free_ioaccel2_sg_chain_blocks(h); + if (h->ioaccel2_cmd_pool) pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), From 7ec6cb88dd468d297319a66ccb923b0962a537b6 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:05 -0500 Subject: [PATCH 346/889] hpsa: call pci_release_regions after pci_disable_device Despite the fact that PCI devices are enabled in this order: 1. pci_enable_device 2. pci_request_regions Documentation/PCI/pci.txt specifies that they be undone in this order 1. pci_disable_device 2. pci_release_regions Tested by injecting error in the call to pci_enable_device in hpsa_init_one -> hpsa_pci_init: [ 9.095001] hpsa 0000:04:00.0: failed to enable PCI device [ 9.095005] hpsa: probe of 0000:04:00.0 failed with error -22 (-22 is -EINVAL) and then in the call pci_request_regions: [ 9.178623] hpsa 0000:04:00.0: failed to obtain PCI resources [ 9.178671] hpsa: probe of 0000:04:00.0 failed with error -16 (-16 is -EBUSY) and then by adding reset_devices to the kernel command line and inject errors into the two calls to pci_enable_device and the call to pci_request_regions in hpsa_init_one -> hpsa_init_reset_devices. (inject on 6th call, 1st to hpsa2) [ 62.413750] hpsa 0000:04:00.0: Failed to enable PCI device (inject on 7th call, 2nd to hpsa2) [ 62.807571] hpsa 0000:04:00.0: failed to enable device. (inject on 8th call, 3rd to hpsa2) [ 62.697198] hpsa 0000:04:00.0: failed to obtain PCI resources [ 62.697234] hpsa: probe of 0000:04:00.0 failed with error -16 The reset_devices path calls return -ENODEV on failure rather than passing the result, which apparently doesn't cause the pci driver to print anything. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron Signed-off-by: Don Brace < don.brace@pmcs.com > --- drivers/scsi/hpsa.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index edd947d8d68333..b3dd2cd91692fb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7481,8 +7481,12 @@ static void hpsa_free_pci_init(struct ctlr_info *h) hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ - pci_release_regions(h->pdev); /* pci_init 2 */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); /* pci_init 1 */ + pci_release_regions(h->pdev); /* pci_init 2 */ } /* several items must be freed later */ @@ -7505,6 +7509,7 @@ static int hpsa_pci_init(struct ctlr_info *h) err = pci_enable_device(h->pdev); if (err) { dev_err(&h->pdev->dev, "failed to enable PCI device\n"); + pci_disable_device(h->pdev); return err; } @@ -7515,7 +7520,8 @@ static int hpsa_pci_init(struct ctlr_info *h) if (err) { dev_err(&h->pdev->dev, "failed to obtain PCI resources\n"); - goto clean1; /* pci */ + pci_disable_device(h->pdev); + return err; } hpsa_interrupt_mode(h); err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); @@ -7552,9 +7558,12 @@ static int hpsa_pci_init(struct ctlr_info *h) iounmap(h->vaddr); clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); - pci_release_regions(h->pdev); -clean1: /* pci */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); + pci_release_regions(h->pdev); return err; } @@ -7781,6 +7790,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ + /* + * call pci_disable_device before pci_release_regions per + * Documentation/PCI/pci.txt + */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); /* pci_init 2 */ kfree(h); /* init_one 1 */ From cc21b042c676d412af2069e2a22e4f4792899d4a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:05 -0500 Subject: [PATCH 347/889] hpsa: propagate hard_reset failures in reset_devices mode Return the real reason for kdump_hard_reset failure rather than change them all to -ENODEV. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b3dd2cd91692fb..59a50cb5a107e6 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7615,11 +7615,8 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) * "performant mode". Or, it might be 640x, which can't reset * due to concerns about shared bbwc between 6402/6404 pair. */ - if (rc) { - if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */ - rc = -ENODEV; + if (rc) goto out_disable; - } /* Now try to get the controller to respond to a no-op */ dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); From 86916c7e6d059b9270c90965d33397afbbdfffd3 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:06 -0500 Subject: [PATCH 348/889] hpsa: propagate return value from board ID lookup If the board ID lookup function fails, return the return code rather than return -ENODEV. The only board ID failure reason right now is -ENODEV, so this just provides more informative prints in kdump and adapts to future changes. Tested with error injection while booting with reset_devices on the kernel command line: [ 62.804324] injecting error in inj_hpsa_lookup_board_id: 1 11 [ 62.804423] hpsa 0000:04:00.0: Board ID not found (the pci probe layer does not print an additional message if -ENODEV is the reason) Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 59a50cb5a107e6..36ff757a2dcceb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6950,8 +6950,12 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) */ rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0 || !ctlr_is_resettable(board_id)) { - dev_warn(&pdev->dev, "Not resetting device.\n"); + if (rc < 0) { + dev_warn(&pdev->dev, "Board ID not found\n"); + return rc; + } + if (!ctlr_is_resettable(board_id)) { + dev_warn(&pdev->dev, "Controller not resettable\n"); return -ENODEV; } @@ -7496,7 +7500,7 @@ static int hpsa_pci_init(struct ctlr_info *h) prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); if (prod_index < 0) - return -ENODEV; + return prod_index; h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); From 846f56311bd809b4d22021e6518245964eaa5c5a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:06 -0500 Subject: [PATCH 349/889] hpsa: downgrade the Waiting for no-op print to dev_info There is nothing worrisome about the "Waiting for controller to respond to no-op" print, so use dev_info rather than dev_warn. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 36ff757a2dcceb..d1c70a18e46f22 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7623,7 +7623,7 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) goto out_disable; /* Now try to get the controller to respond to a no-op */ - dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); + dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n"); for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { if (hpsa_noop(pdev) == 0) break; From 0f9081c16eba8ff56510cf723fb41696d517692a Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:07 -0500 Subject: [PATCH 350/889] hpsa: set pointers to NULL after freeing After freeing dynamically allocated pointers, set the variable or structure containing the pointer to NULL so a stale address cannot inadvertently be used. Do this for every case except local stack variables at the end of a function Also zero out size variables that match the pointers Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 66 ++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d1c70a18e46f22..decd3424e04ecc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1881,6 +1881,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * since it didn't get added to scsi mid layer */ fixup_botched_add(h, added[i]); + added[i] = NULL; } free_and_out: @@ -7124,9 +7125,11 @@ static void hpsa_disable_interrupt_mode(struct ctlr_info *h) if (h->msix_vector) { if (h->pdev->msix_enabled) pci_disable_msix(h->pdev); + h->msix_vector = 0; } else if (h->msi_vector) { if (h->pdev->msi_enabled) pci_disable_msi(h->pdev); + h->msi_vector = 0; } #endif /* CONFIG_PCI_MSI */ } @@ -7266,8 +7269,14 @@ static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, static void hpsa_free_cfgtables(struct ctlr_info *h) { - iounmap(h->transtable); - iounmap(h->cfgtable); + if (h->transtable) { + iounmap(h->transtable); + h->transtable = NULL; + } + if (h->cfgtable) { + iounmap(h->cfgtable); + h->cfgtable = NULL; + } } /* Find and map CISS config table and transfer table @@ -7484,6 +7493,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h) { hpsa_free_cfgtables(h); /* pci_init 4 */ iounmap(h->vaddr); /* pci_init 3 */ + h->vaddr = NULL; hpsa_disable_interrupt_mode(h); /* pci_init 2 */ /* * call pci_disable_device before pci_release_regions per @@ -7560,6 +7570,7 @@ static int hpsa_pci_init(struct ctlr_info *h) hpsa_free_cfgtables(h); clean3: /* vaddr, intmode+region, pci */ iounmap(h->vaddr); + h->vaddr = NULL; clean2: /* intmode+region, pci */ hpsa_disable_interrupt_mode(h); /* @@ -7641,15 +7652,22 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) static void hpsa_free_cmd_pool(struct ctlr_info *h) { kfree(h->cmd_pool_bits); - if (h->cmd_pool) + h->cmd_pool_bits = NULL; + if (h->cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct CommandList), h->cmd_pool, h->cmd_pool_dhandle); - if (h->errinfo_pool) + h->cmd_pool = NULL; + h->cmd_pool_dhandle = 0; + } + if (h->errinfo_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct ErrorInfo), h->errinfo_pool, h->errinfo_pool_dhandle); + h->errinfo_pool = NULL; + h->errinfo_pool_dhandle = 0; + } } static int hpsa_alloc_cmd_pool(struct ctlr_info *h) @@ -7697,12 +7715,14 @@ static void hpsa_free_irqs(struct ctlr_info *h) i = h->intr_mode; irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); + h->q[i] = 0; return; } for (i = 0; i < h->msix_vector; i++) { irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); + h->q[i] = 0; } } @@ -7738,6 +7758,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, intxhandler, IRQF_SHARED, h->devname, &h->q[h->intr_mode]); } + irq_set_affinity_hint(h->intr[h->intr_mode], NULL); } if (rc) { dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", @@ -7779,6 +7800,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) h->reply_queue[i].head, h->reply_queue[i].busaddr); h->reply_queue[i].head = NULL; h->reply_queue[i].busaddr = 0; + h->reply_queue_size = 0; } } @@ -7788,15 +7810,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ - hpsa_free_cfgtables(h); /* pci_init 4 */ - iounmap(h->vaddr); /* pci_init 3 */ - hpsa_disable_interrupt_mode(h); /* pci_init 2 */ - /* - * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt - */ - pci_disable_device(h->pdev); - pci_release_regions(h->pdev); /* pci_init 2 */ + hpsa_free_pci_init(h); /* init_one 3 */ kfree(h); /* init_one 1 */ } @@ -8302,8 +8316,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clean3: /* pci, lockup, wq/aer/h */ hpsa_free_pci_init(h); clean2: /* lockup, wq/aer/h */ - if (h->lockup_detected) + if (h->lockup_detected) { free_percpu(h->lockup_detected); + h->lockup_detected = NULL; + } clean1: /* wq/aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); @@ -8363,8 +8379,10 @@ static void hpsa_free_device_info(struct ctlr_info *h) { int i; - for (i = 0; i < h->ndevices; i++) + for (i = 0; i < h->ndevices; i++) { kfree(h->dev[i]); + h->dev[i] = NULL; + } } static void hpsa_remove_one(struct pci_dev *pdev) @@ -8393,6 +8411,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_unregister_scsi(h); /* init_one "8" */ kfree(h->hba_inquiry_data); /* init_one "8" */ + h->hba_inquiry_data = NULL; /* init_one "8" */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ @@ -8403,6 +8422,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_pci_init(h); /* init_one 3 */ free_percpu(h->lockup_detected); /* init_one 2 */ + h->lockup_detected = NULL; /* init_one 2 */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); /* init_one 1 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ @@ -8610,7 +8630,7 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) cp->ReplyQueue = 0; cp->tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT); cp->host_addr = - cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + + cpu_to_le64((u64) (h->ioaccel_cmd_pool_dhandle + (i * sizeof(struct io_accel1_cmd)))); } } else if (trans_support & CFGTBL_Trans_io_accel2) { @@ -8649,11 +8669,15 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) /* Free ioaccel1 mode command blocks and block fetch table */ static void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h) { - if (h->ioaccel_cmd_pool) + if (h->ioaccel_cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); + h->ioaccel_cmd_pool = NULL; + h->ioaccel_cmd_pool_dhandle = 0; + } kfree(h->ioaccel1_blockFetchTable); + h->ioaccel1_blockFetchTable = NULL; } /* Allocate ioaccel1 mode command blocks and block fetch table */ @@ -8697,11 +8721,15 @@ static void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h) { hpsa_free_ioaccel2_sg_chain_blocks(h); - if (h->ioaccel2_cmd_pool) + if (h->ioaccel2_cmd_pool) { pci_free_consistent(h->pdev, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle); + h->ioaccel2_cmd_pool = NULL; + h->ioaccel2_cmd_pool_dhandle = 0; + } kfree(h->ioaccel2_blockFetchTable); + h->ioaccel2_blockFetchTable = NULL; } /* Allocate ioaccel2 mode command blocks and block fetch table */ @@ -8750,6 +8778,7 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) static void hpsa_free_performant_mode(struct ctlr_info *h) { kfree(h->blockFetchTable); + h->blockFetchTable = NULL; hpsa_free_reply_queues(h); hpsa_free_ioaccel1_cmd_and_bft(h); hpsa_free_ioaccel2_cmd_and_bft(h); @@ -8820,6 +8849,7 @@ static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) clean2: /* bft, rq, ioaccel */ kfree(h->blockFetchTable); + h->blockFetchTable = NULL; clean1: /* rq, ioaccel */ hpsa_free_reply_queues(h); hpsa_free_ioaccel1_cmd_and_bft(h); From 95bd9b16e222060895601115fd94c540f60147ab Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:08 -0500 Subject: [PATCH 351/889] hpsa: notice all request_irq errors In MSI and MSI-X mode, where hpsa asks for more than one interrupt, hpsa_request_irqs forgets if the first request_irq calls failed if later ones succeed. It needs exit the loop on any failure rather than continue, freeing all irqs that were requested until that point. Also, it needs to clear out the q numbers up to MAX_REPLY_QUEUES. The same is true for the general hpsa_free_irqs function. Tested with error injection of -ENOSYS on the 4th call: [ 9.277691] injecting error in inj_request_irq: 1 4 [ 9.277780] hpsa 0000:02:00.0: failed to get irq 35 for hpsa1 [ 10.711623] scsi host1: Error handler scsi_eh_1 exiting [ 10.739170] hpsa: probe of 0000:02:00.0 failed with error -38 Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index decd3424e04ecc..e7b8a61d1b70ef 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7724,6 +7724,8 @@ static void hpsa_free_irqs(struct ctlr_info *h) free_irq(h->intr[i], &h->q[i]); h->q[i] = 0; } + for (; i < MAX_REPLY_QUEUES; i++) + h->q[i] = 0; } /* returns 0 on success; cleans up and returns -Enn on error */ @@ -7742,10 +7744,25 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) { /* If performant mode and MSI-X, use multiple reply queues */ - for (i = 0; i < h->msix_vector; i++) + for (i = 0; i < h->msix_vector; i++) { rc = request_irq(h->intr[i], msixhandler, 0, h->devname, &h->q[i]); + if (rc) { + int j; + + dev_err(&h->pdev->dev, + "failed to get irq %d for %s\n", + h->intr[i], h->devname); + for (j = 0; j < i; j++) { + free_irq(h->intr[j], &h->q[j]); + h->q[j] = 0; + } + for (; j < MAX_REPLY_QUEUES; j++) + h->q[j] = 0; + return rc; + } + } hpsa_irq_affinity_hints(h); } else { /* Use single reply pool */ From c6db7a0dccc0f8e071c286d903573986cb87851d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:08 -0500 Subject: [PATCH 352/889] hpsa: skip free_irq calls if irqs are not allocated If try_soft_reset fails to re-allocate irqs, the error exit starts with free_irq calls, which generate kernel WARN messages since they were already freed a few lines earlier. Jump to the next exit label to skip the free_irq calls. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e7b8a61d1b70ef..1b0a84517818e3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8267,7 +8267,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - goto clean4; + /* clean4 starts with free_irqs, but that was just + * done. Then, request_irqs_failed, so there is + * nothing to free. So, goto the next label. */ + goto clean3; } rc = hpsa_kdump_soft_reset(h); From e67a6d527e861371cd9995626e2d43cf419643ad Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:09 -0500 Subject: [PATCH 353/889] hpsa: cleanup for init_one step 2 in kdump In hpsa_undo_allocations_after_kdump_soft_reset, the things allocated in hpsa_init_one step 2 - h->resubmit_wq and h->lockup_detected need to be freed, in the right order. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1b0a84517818e3..548ffaad8cceee 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7828,6 +7828,10 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ hpsa_free_pci_init(h); /* init_one 3 */ + free_percpu(h->lockup_detected); /* init_one 2 */ + h->lockup_detected = NULL; /* init_one 2 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 1 */ kfree(h); /* init_one 1 */ } From 99a997b2441d90af1707cb8bdbb942a4daf27c28 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:09 -0500 Subject: [PATCH 354/889] hpsa: fix try_soft_reset error handling If registering the special interrupt handlers in hpsa_init_one before a soft reset fails, the error exit needs to deallocate everything that was allocated before. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 548ffaad8cceee..b532313875091c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8271,16 +8271,20 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* clean4 starts with free_irqs, but that was just - * done. Then, request_irqs_failed, so there is - * nothing to free. So, goto the next label. */ + /* cannot goto clean7 or free_irqs will be called + * again. Instead, do its work */ + hpsa_free_performant_mode(h); /* clean7 */ + hpsa_free_sg_chain_blocks(h); /* clean6 */ + hpsa_free_cmd_pool(h); /* clean5 */ + /* skip hpsa_free_irqs(h) clean4 since that + * was just called before request_irqs failed */ goto clean3; } rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean4; + goto clean7; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8301,7 +8305,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpsa_undo_allocations_after_kdump_soft_reset(h); try_soft_reset = 0; if (rc) - /* don't go to clean4, we already unallocated */ + /* don't goto clean, we already unallocated */ return -ENODEV; goto reinit_after_soft_reset; From 4917a3b394206341587b0398d148f71cedee038d Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:10 -0500 Subject: [PATCH 355/889] hpsa: create workqueue after the driver is ready for use Don't create the resubmit workqueue in hpsa_init_one until everything else is ready to use, so everything can be freed in reverse order of when they were allocated without risking freeing things while workqueue items are still active. Destroy the workqueue in the right order in hpsa_undo_allocations_after_kdump_soft_reset too. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 65 ++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b532313875091c..7bc5faa17fbd15 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8183,24 +8183,18 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS); atomic_set(&h->cmds_sent, 0); - h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); - if (!h->resubmit_wq) { - dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); - rc = -ENOMEM; - goto clean1; /* aer/h */ - } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); if (!h->lockup_detected) { dev_err(&h->pdev->dev, "Failed to allocate lockup detector\n"); rc = -ENOMEM; - goto clean1; /* wq/aer/h */ + goto clean1; /* aer/h */ } set_lockup_detected_for_all_cpus(h, 0); rc = hpsa_pci_init(h); if (rc) - goto clean2; /* lockup, wq/aer/h */ + goto clean2; /* lockup, aer/h */ sprintf(h->devname, HPSA "%d", number_of_controllers); h->ctlr = number_of_controllers; @@ -8216,7 +8210,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean3; /* pci, lockup, wq/aer/h */ + goto clean3; /* pci, lockup, aer/h */ } } @@ -8225,16 +8219,16 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) - goto clean3; /* pci, lockup, wq/aer/h */ + goto clean3; /* pci, lockup, aer/h */ dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean4; /* irq, pci, lockup, wq/aer/h */ + goto clean4; /* irq, pci, lockup, aer/h */ rc = hpsa_alloc_sg_chain_blocks(h); if (rc) - goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */ + goto clean5; /* cmd, irq, pci, lockup, aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); init_waitqueue_head(&h->abort_sync_wait_queue); @@ -8247,7 +8241,15 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&h->devlock); rc = hpsa_put_ctlr_into_performant_mode(h); if (rc) - goto clean6; /* sg, cmd, irq, pci, lockup, wq/aer/h */ + goto clean6; /* sg, cmd, irq, pci, lockup, aer/h */ + + /* create the resubmit workqueue */ + h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); + if (!h->resubmit_wq) { + dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); + rc = -ENOMEM; + goto clean7; /* perf, sg, cmd, irq, pci, lockup, aer/h */ + } /* At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -8271,8 +8273,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* cannot goto clean7 or free_irqs will be called + /* cannot goto clean8 or free_irqs will be called * again. Instead, do its work */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* clean8 */ hpsa_free_performant_mode(h); /* clean7 */ hpsa_free_sg_chain_blocks(h); /* clean6 */ hpsa_free_cmd_pool(h); /* clean5 */ @@ -8284,7 +8288,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean7; + goto clean8; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8322,7 +8326,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpsa_hba_inquiry(h); rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ if (rc) - goto clean7; + goto clean8; /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -8334,23 +8338,24 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean7: /* perf, sg, cmd, irq, pci, lockup, wq/aer/h */ +clean8: /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); +clean7: /* perf, sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_performant_mode(h); -clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); -clean5: /* cmd, irq, pci, lockup, wq/aer/h */ +clean6: /* sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, pci, lockup, aer/h */ hpsa_free_cmd_pool(h); -clean4: /* irq, pci, lockup, wq/aer/h */ +clean4: /* irq, pci, lockup, aer/h */ hpsa_free_irqs(h); -clean3: /* pci, lockup, wq/aer/h */ +clean3: /* pci, lockup, aer/h */ hpsa_free_pci_init(h); -clean2: /* lockup, wq/aer/h */ +clean2: /* lockup, aer/h */ if (h->lockup_detected) { free_percpu(h->lockup_detected); h->lockup_detected = NULL; } -clean1: /* wq/aer/h */ - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); +clean1: /* aer/h */ /* (void) pci_disable_pcie_error_reporting(pdev); */ kfree(h); return rc; @@ -8437,9 +8442,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ - hpsa_unregister_scsi(h); /* init_one "8" */ - kfree(h->hba_inquiry_data); /* init_one "8" */ - h->hba_inquiry_data = NULL; /* init_one "8" */ + hpsa_unregister_scsi(h); /* init_one 9 */ + kfree(h->hba_inquiry_data); /* init_one 9 */ + h->hba_inquiry_data = NULL; /* init_one 9 */ + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); /* init_one 8 */ hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ @@ -8451,8 +8458,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ - if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* init_one 1 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ kfree(h); /* init_one 1 */ } From 801b0cd4b10c7c92aee1efa99489c3ffa1cba935 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:11 -0500 Subject: [PATCH 356/889] hpsa: add interrupt number to /proc/interrupts interrupt name Add the interrupt number to the interrupt names that appear in /proc/interrupts, so they are unique Also, delete the IRQ and DAC prints. Other parts of the kernel already print the IRQ assignments, and dual-address-cycle support has not been interesting since the parallel PCI bus went from 32 to 64 bits wide. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 20 ++++++++++++++------ drivers/scsi/hpsa.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7bc5faa17fbd15..492ad68aa5cc7d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7745,8 +7745,9 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) { /* If performant mode and MSI-X, use multiple reply queues */ for (i = 0; i < h->msix_vector; i++) { + sprintf(h->intrname[i], "%s-msix%d", h->devname, i); rc = request_irq(h->intr[i], msixhandler, - 0, h->devname, + 0, h->intrname[i], &h->q[i]); if (rc) { int j; @@ -7767,12 +7768,22 @@ static int hpsa_request_irqs(struct ctlr_info *h, } else { /* Use single reply pool */ if (h->msix_vector > 0 || h->msi_vector) { + if (h->msix_vector) + sprintf(h->intrname[h->intr_mode], + "%s-msix", h->devname); + else + sprintf(h->intrname[h->intr_mode], + "%s-msi", h->devname); rc = request_irq(h->intr[h->intr_mode], - msixhandler, 0, h->devname, + msixhandler, 0, + h->intrname[h->intr_mode], &h->q[h->intr_mode]); } else { + sprintf(h->intrname[h->intr_mode], + "%s-intx", h->devname); rc = request_irq(h->intr[h->intr_mode], - intxhandler, IRQF_SHARED, h->devname, + intxhandler, IRQF_SHARED, + h->intrname[h->intr_mode], &h->q[h->intr_mode]); } irq_set_affinity_hint(h->intr[h->intr_mode], NULL); @@ -8220,9 +8231,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) goto clean3; /* pci, lockup, aer/h */ - dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", - h->devname, pdev->device, - h->intr[h->intr_mode], dac ? "" : " not"); rc = hpsa_alloc_cmd_pool(h); if (rc) goto clean4; /* irq, pci, lockup, aer/h */ diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index f364bff8851977..5643d55ac5a805 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -219,6 +219,7 @@ struct ctlr_info { int remove_in_progress; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; + char intrname[MAX_REPLY_QUEUES][16]; /* "hpsa0-msix00" names */ u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ #define HPSATMF_BITS_SUPPORTED (1 << 0) #define HPSATMF_PHYS_LUN_RESET (1 << 1) From aa08bd237b7f6f3c5e21ea103f295d7dea3e61ca Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:11 -0500 Subject: [PATCH 357/889] hpsa: use scsi host_no as hpsa controller number Rather than numbering the hpsa controllers with an incrementing 0..n value (e.g., that shows up in /proc/interrupts), use the scsi midlayer host_no (e.g. matching /sys/class/scsi_host/hostNN). Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 153 ++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 68 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 492ad68aa5cc7d..ef1fca519d00d8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -318,32 +318,36 @@ static int check_for_unit_attention(struct ctlr_info *h, switch (asc) { case STATE_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: a state change " - "detected, command retried\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: a state change detected, command retried\n", + h->devname); break; case LUN_FAILED: dev_warn(&h->pdev->dev, - HPSA "%d: LUN failure detected\n", h->ctlr); + "%s: LUN failure detected\n", h->devname); break; case REPORT_LUNS_CHANGED: dev_warn(&h->pdev->dev, - HPSA "%d: report LUN data changed\n", h->ctlr); + "%s: report LUN data changed\n", h->devname); /* * Note: this REPORT_LUNS_CHANGED condition only occurs on the external * target (array) devices. */ break; case POWER_OR_RESET: - dev_warn(&h->pdev->dev, HPSA "%d: a power on " - "or device reset detected\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: a power on or device reset detected\n", + h->devname); break; case UNIT_ATTENTION_CLEARED: - dev_warn(&h->pdev->dev, HPSA "%d: unit attention " - "cleared by another initiator\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: unit attention cleared by another initiator\n", + h->devname); break; default: - dev_warn(&h->pdev->dev, HPSA "%d: unknown " - "unit attention detected\n", h->ctlr); + dev_warn(&h->pdev->dev, + "%s: unknown unit attention detected\n", + h->devname); break; } return 1; @@ -5145,22 +5149,15 @@ static int hpsa_change_queue_type(struct scsi_device *sdev, int tag_type) return tag_type; } -static void hpsa_unregister_scsi(struct ctlr_info *h) -{ - /* we are being forcibly unloaded, and may not refuse. */ - scsi_remove_host(h->scsi_host); - scsi_host_put(h->scsi_host); - h->scsi_host = NULL; -} - -static int hpsa_register_scsi(struct ctlr_info *h) +static int hpsa_scsi_host_alloc(struct ctlr_info *h) { struct Scsi_Host *sh; - int error; sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); - if (sh == NULL) - goto fail; + if (sh == NULL) { + dev_err(&h->pdev->dev, "scsi_host_alloc failed\n"); + return -ENOMEM; + } sh->io_port = 0; sh->n_io_port = 0; @@ -5172,35 +5169,35 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; - h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; if (!shost_use_blk_mq(sh)) { - error = scsi_init_shared_tag_map(sh, sh->can_queue); + int error = scsi_init_shared_tag_map(sh, sh->can_queue); + if (error) { dev_err(&h->pdev->dev, "%s: scs_init_shared_tag_map failed for controller %d\n", __func__, h->ctlr); - goto fail_host_put; + scsi_host_put(sh); + return error; } } - error = scsi_add_host(sh, &h->pdev->dev); - if (error) { - dev_err(&h->pdev->dev, "%s: scsi_add_host failed for controller %d\n", - __func__, h->ctlr); - goto fail_host_put; - } - scsi_scan_host(sh); + h->scsi_host = sh; return 0; +} - fail_host_put: - scsi_host_put(sh); - return error; - fail: - dev_err(&h->pdev->dev, "%s: scsi_host_alloc" - " failed for controller %d\n", __func__, h->ctlr); - return -ENOMEM; +static int hpsa_scsi_add_host(struct ctlr_info *h) +{ + int rv; + + rv = scsi_add_host(h->scsi_host, &h->pdev->dev); + if (rv) { + dev_err(&h->pdev->dev, "scsi_add_host failed\n"); + return rv; + } + scsi_scan_host(h->scsi_host); + return 0; } /* Send a TEST_UNIT_READY command to the specified LUN using the specified @@ -7838,7 +7835,9 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ hpsa_free_irqs(h); /* init_one 4 */ - hpsa_free_pci_init(h); /* init_one 3 */ + scsi_host_put(h->scsi_host); /* init_one 3 */ + h->scsi_host = NULL; /* init_one 3 */ + hpsa_free_pci_init(h); /* init_one 2_5 */ free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ if (h->resubmit_wq) @@ -8205,10 +8204,15 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_pci_init(h); if (rc) - goto clean2; /* lockup, aer/h */ + goto clean2; /* lu, aer/h */ - sprintf(h->devname, HPSA "%d", number_of_controllers); - h->ctlr = number_of_controllers; + /* relies on h-> settings made by hpsa_pci_init, including + * interrupt_mode h->intr */ + rc = hpsa_scsi_host_alloc(h); + if (rc) + goto clean2_5; /* pci, lu, aer/h */ + + sprintf(h->devname, HPSA "%d", h->scsi_host->host_no); number_of_controllers++; /* configure PCI DMA stuff */ @@ -8221,7 +8225,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dac = 0; } else { dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean3; /* pci, lockup, aer/h */ + goto clean3; /* shost, pci, lu, aer/h */ } } @@ -8230,13 +8234,13 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) - goto clean3; /* pci, lockup, aer/h */ + goto clean3; /* shost, pci, lu, aer/h */ rc = hpsa_alloc_cmd_pool(h); if (rc) - goto clean4; /* irq, pci, lockup, aer/h */ + goto clean4; /* irq, shost, pci, lu, aer/h */ rc = hpsa_alloc_sg_chain_blocks(h); if (rc) - goto clean5; /* cmd, irq, pci, lockup, aer/h */ + goto clean5; /* cmd, irq, shost, pci, lu, aer/h */ init_waitqueue_head(&h->scan_wait_queue); init_waitqueue_head(&h->abort_cmd_wait_queue); init_waitqueue_head(&h->abort_sync_wait_queue); @@ -8245,18 +8249,23 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, h); h->ndevices = 0; h->hba_mode_enabled = 0; - h->scsi_host = NULL; + spin_lock_init(&h->devlock); rc = hpsa_put_ctlr_into_performant_mode(h); if (rc) - goto clean6; /* sg, cmd, irq, pci, lockup, aer/h */ + goto clean6; /* sg, cmd, irq, shost, pci, lu, aer/h */ + + /* hook into SCSI subsystem */ + rc = hpsa_scsi_add_host(h); + if (rc) + goto clean7; /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ /* create the resubmit workqueue */ h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0); if (!h->resubmit_wq) { dev_err(&h->pdev->dev, "Failed to allocate work queue\n"); rc = -ENOMEM; - goto clean7; /* perf, sg, cmd, irq, pci, lockup, aer/h */ + goto clean8; /* sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ } /* At this point, the controller is ready to take commands. @@ -8281,10 +8290,10 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); - /* cannot goto clean8 or free_irqs will be called + /* cannot goto clean9 or free_irqs will be called * again. Instead, do its work */ if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* clean8 */ + destroy_workqueue(h->resubmit_wq); /* clean9 */ hpsa_free_performant_mode(h); /* clean7 */ hpsa_free_sg_chain_blocks(h); /* clean6 */ hpsa_free_cmd_pool(h); /* clean5 */ @@ -8296,7 +8305,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean8; + goto clean9; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8332,9 +8341,6 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->access.set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); - rc = hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ - if (rc) - goto clean8; /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; @@ -8346,19 +8352,26 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) h->heartbeat_sample_interval); return 0; -clean8: /* wq, perf, sg, cmd, irq, pci, lockup, aer/h */ +clean9: /* wq, sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ if (h->resubmit_wq) destroy_workqueue(h->resubmit_wq); -clean7: /* perf, sg, cmd, irq, pci, lockup, aer/h */ +clean8: /* sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ + /* nothing to clean from scsi_add_host... + * scsi_host_put will do so below */ +clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ hpsa_free_performant_mode(h); -clean6: /* sg, cmd, irq, pci, lockup, aer/h */ hpsa_free_sg_chain_blocks(h); -clean5: /* cmd, irq, pci, lockup, aer/h */ +clean6: /* sg, cmd, irq, shost, pci, lu, aer/h */ + hpsa_free_sg_chain_blocks(h); +clean5: /* cmd, irq, shost, pci, lu, aer/h */ hpsa_free_cmd_pool(h); -clean4: /* irq, pci, lockup, aer/h */ +clean4: /* irq, shost, pci, lu, aer/h */ hpsa_free_irqs(h); -clean3: /* pci, lockup, aer/h */ +clean3: /* shost, pci, lu, aer/h */ + scsi_host_put(h->scsi_host); + h->scsi_host = NULL; +clean2_5: /* pci, lu, aer/h */ hpsa_free_pci_init(h); -clean2: /* lockup, aer/h */ +clean2: /* lu, aer/h */ if (h->lockup_detected) { free_percpu(h->lockup_detected); h->lockup_detected = NULL; @@ -8450,19 +8463,23 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_device_info(h); /* scan */ - hpsa_unregister_scsi(h); /* init_one 9 */ - kfree(h->hba_inquiry_data); /* init_one 9 */ - h->hba_inquiry_data = NULL; /* init_one 9 */ + kfree(h->hba_inquiry_data); /* init_one 10 */ + h->hba_inquiry_data = NULL; /* init_one 10 */ if (h->resubmit_wq) - destroy_workqueue(h->resubmit_wq); /* init_one 8 */ + destroy_workqueue(h->resubmit_wq); /* init_one 9 */ + scsi_remove_host(h->scsi_host); /* init_one 8 */ + hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ + scsi_host_put(h->scsi_host); /* init_one 3 */ + h->scsi_host = NULL; /* init_one 3 */ + /* includes hpsa_disable_interrupt_mode - pci_init 2 */ - hpsa_free_pci_init(h); /* init_one 3 */ + hpsa_free_pci_init(h); /* init_one 2.5 */ free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ From d7e8d5d646375c2e30f4403becabb665a5103954 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:12 -0500 Subject: [PATCH 358/889] hpsa: propagate the error code in hpsa_kdump_soft_reset If hpsa_wait_for_board_state fails, hpsa_kdump_soft_reset should propagate its return value (e.g., -ENODEV) rather than just returning -1. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ef1fca519d00d8..69b89768b7766e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7796,19 +7796,22 @@ static int hpsa_request_irqs(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { + int rc; hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { + rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY); + if (rc) { dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); - return -1; + return rc; } dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) { + rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); + if (rc) { dev_warn(&h->pdev->dev, "Board failed to become ready " "after soft reset.\n"); - return -1; + return rc; } return 0; From f7fe41ad32025e21dfd7c7564edbc29f71e8e8fa Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 28 Oct 2014 11:52:12 -0500 Subject: [PATCH 359/889] hpsa: adjust RAID-1, RAID-1ADM, and RAID-6 names HP now uses RAID-6 rather than RAID-ADG (Advanced Data Guarding) as the marketing name for our implementation of RAID-6. The driver considers RAID-1 and RAID-1+0 to be the same level, and considers RAID-1ADM and RAID-1+0ADM to be the same level. Parenthesis can be used to reflect the optional +0 portion of both those RAID levels. Rename: RAID-ADG to RAID-6 RAID-1(1+0) to RAID-1(+0) RAID-1(ADM) to RAID-1(+0)ADM Also, add another const after the pointer type as suggested by checkpatch.pl so the array is: static const char * const raid_label[] Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 69b89768b7766e..f98c824a17597d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -738,8 +738,8 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) return (scsi3addr[3] & 0xC0) == 0x40; } -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "1(ADM)", "UNKNOWN" +static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", + "1(+0)ADM", "UNKNOWN" }; #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 From c7ddb31de63afe28a7f93810d07cbe9abdebe549 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Oct 2014 11:52:13 -0500 Subject: [PATCH 360/889] hpsa: remove queue depth from add/remove prints The queue depth is not finalized when device add/update prints are done, so is inaccurate. It is correct in device removal prints, when it doesn't matter any more. Since the final queue depth is available in /sys/block/sdNN/device/queue_depth just drop printing them. Signed-off-by: Robert Elliott Signed-off-by: Stephen M. Cameron --- drivers/scsi/hpsa.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f98c824a17597d..a412a9c5908c73 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1273,7 +1273,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, (*nadded)++; dev_info(&h->pdev->dev, - "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "%6s scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", device->expose_state & HPSA_SCSI_ADD ? "added" : "masked", hostno, device->bus, device->target, device->lun, scsi_device_type(device->devtype), @@ -1282,9 +1282,8 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, device->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[device->raid_level], device->offload_config ? '+' : '-', - device->offload_enabled ? '+' : '-', - device->expose_state, - device->queue_depth); + device->offload_to_be_enabled ? '+' : '-', + device->expose_state); return 0; } @@ -1328,7 +1327,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->queue_depth = new_entry->queue_depth; dev_info(&h->pdev->dev, - "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "updated scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, h->dev[entry]->bus, h->dev[entry]->target, h->dev[entry]->lun, scsi_device_type(h->dev[entry]->devtype), @@ -1337,9 +1336,8 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, h->dev[entry]->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[h->dev[entry]->raid_level], h->dev[entry]->offload_config ? '+' : '-', - h->dev[entry]->offload_enabled ? '+' : '-', - h->dev[entry]->expose_state, - h->dev[entry]->queue_depth); + h->dev[entry]->offload_to_be_enabled ? '+' : '-', + h->dev[entry]->expose_state); } /* Replace an entry from h->dev[] array. */ @@ -1368,7 +1366,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, added[*nadded] = new_entry; (*nadded)++; dev_info(&h->pdev->dev, - "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "replaced scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, new_entry->bus, new_entry->target, new_entry->lun, scsi_device_type(new_entry->devtype), new_entry->vendor, @@ -1376,9 +1374,8 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, new_entry->raid_level > RAID_UNKNOWN ? "RAID-?" : raid_label[new_entry->raid_level], new_entry->offload_config ? '+' : '-', - new_entry->offload_enabled ? '+' : '-', - new_entry->expose_state, - new_entry->queue_depth); + new_entry->offload_to_be_enabled ? '+' : '-', + new_entry->expose_state); } /* Remove an entry from h->dev[] array. */ @@ -1399,7 +1396,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, h->dev[i] = h->dev[i+1]; h->ndevices--; dev_info(&h->pdev->dev, - "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "removed scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, sd->bus, sd->target, sd->lun, scsi_device_type(sd->devtype), sd->vendor, @@ -1408,8 +1405,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, "RAID-?" : raid_label[sd->raid_level], sd->offload_config ? '+' : '-', sd->offload_enabled ? '+' : '-', - sd->expose_state, - sd->queue_depth); + sd->expose_state); } #define SCSI3ADDR_EQ(a, b) ( \ @@ -1786,7 +1782,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, if (sd[i]->volume_offline) { hpsa_show_volume_status(h, sd[i]); dev_info(&h->pdev->dev, - "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d qd=%d\n", + "offline scsi %d:%d:%d:%d: %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", hostno, sd[i]->bus, sd[i]->target, sd[i]->lun, scsi_device_type(sd[i]->devtype), sd[i]->vendor, @@ -1796,8 +1792,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, raid_label[sd[i]->raid_level], sd[i]->offload_config ? '+' : '-', sd[i]->offload_enabled ? '+' : '-', - sd[i]->expose_state, - sd[i]->queue_depth); + sd[i]->expose_state); continue; } From 3c12e51cc8c4b51d844dccccaf09f6944172fbc1 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:52:14 -0500 Subject: [PATCH 361/889] debug tag collisions --- drivers/scsi/hpsa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a412a9c5908c73..873146de937e87 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5790,6 +5790,14 @@ static int hpsa_get_cmd_index(struct scsi_cmnd *scmd) return idx; } +static void print_scsi_cmd(struct ctlr_info *h, struct scsi_cmnd *scmd, int idx) +{ + char format[50]; + + sprintf(format, "Tag %d: CDB: %dph\n", idx, scmd->cmd_len); + dev_warn(&h->pdev->dev, format, scmd->cmnd); +} + /* * For operations with an associated SCSI command, a command block is allocated * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the @@ -5824,6 +5832,7 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, dev_warn(&h->pdev->dev, "tag collision (tag=%d) in cmd_tagged_alloc().\n", idx); + print_scsi_cmd(h, scmd, idx); } hpsa_cmd_partial_init(h, idx, c); From f229925b42b63e9494db57994fa135331a13b1c2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 28 Oct 2014 11:52:14 -0500 Subject: [PATCH 362/889] debug aborts --- drivers/scsi/hpsa.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 873146de937e87..abf5e1ef89e99a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5651,6 +5651,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) u32 tagupper, taglower; int refcount, reply_queue; + /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); if (WARN(h == NULL, @@ -5658,8 +5659,10 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) sc)) return FAILED; + dev_warn(&h->pdev->dev, "abort 0\n"); /* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, "abort 0.1\n"); dev_warn(&h->pdev->dev, "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, @@ -5670,10 +5673,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* FIXME eh_timeout_handler would be even better. * for testing, abort is just being used for timeouts, * so is equivalent */ + dev_warn(&h->pdev->dev, "abort 0.2\n"); detect_controller_lockup(h); + dev_warn(&h->pdev->dev, "abort 0.3\n"); /* check again in case one just occurred */ if (lockup_detected(h)) { + dev_warn(&h->pdev->dev, "abort 0.4\n"); dev_warn(&h->pdev->dev, "scsi %d:%d:%d:%llu scmd %p ABORT FAILED, lockup detected\n", h->scsi_host->host_no, sc->device->channel, @@ -5682,11 +5688,13 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) } } + dev_warn(&h->pdev->dev, "abort 1\n"); /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) return FAILED; + dev_warn(&h->pdev->dev, "abort 2\n"); memset(msg, 0, sizeof(msg)); ml += sprintf(msg+ml, "scsi %d:%d:%d:%llu scmd %p ABORT ", h->scsi_host->host_no, sc->device->channel, @@ -5700,18 +5708,21 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } + dev_warn(&h->pdev->dev, "abort 3\n"); /* Get SCSI command to be aborted */ abort = (struct CommandList *) sc->host_scribble; if (abort == NULL) { /* This can happen if the command already completed. */ return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 4\n"); refcount = atomic_inc_return(&abort->refcount); if (refcount == 1) { /* Command is done already. */ cmd_free(h, abort); return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 5\n"); /* Don't bother trying the abort if we know it won't work. */ if (abort->cmd_type != CMD_IOACCEL2 && abort->cmd_type != CMD_IOACCEL1 && !dev->supports_aborts) { @@ -5719,6 +5730,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) return FAILED; } + dev_warn(&h->pdev->dev, "abort 6\n"); /* Check that we're aborting the right command. * It's possible the CommandList already completed and got re-used. */ @@ -5726,6 +5738,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return SUCCESS; } + dev_warn(&h->pdev->dev, "abort 7\n"); abort->abort_pending = true; hpsa_get_tag(h, abort, &taglower, &tagupper); @@ -5738,6 +5751,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) as->cmd_len, as->cmnd[0], as->cmnd[1], as->serial_number); dev_warn(&h->pdev->dev, "%s BEING SENT\n", msg); + dev_warn(&h->pdev->dev, "abort 8 (waiting for abort command to be free)\n"); /* * Command is in flight, or possibly already completed @@ -5751,6 +5765,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return FAILED; } + dev_warn(&h->pdev->dev, "abort 9 (got abort command)\n"); rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue); atomic_inc(&h->abort_cmds_available); wake_up_all(&h->abort_cmd_wait_queue); @@ -5759,9 +5774,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) cmd_free(h, abort); return FAILED; } + dev_warn(&h->pdev->dev, "abort 10\n"); dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg); wait_event(h->abort_sync_wait_queue, atomic_read(&abort->refcount) == 1); cmd_free(h, abort); + dev_warn(&h->pdev->dev, "abort 11\n"); return SUCCESS; } From 42f183b08ef699ea8175300f79faa558f2d2737f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 25 Sep 2014 15:27:00 +0100 Subject: [PATCH 363/889] staging:iio:ad5933: Fix NULL pointer deref when enabling buffer In older versions of the IIO framework it was possible to pass a completely different set of channels to iio_buffer_register() as the one that is assigned to the IIO device. Commit 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") introduced a restriction that requires that the set of channels that is passed to iio_buffer_register() is a subset of the channels assigned to the IIO device as the IIO core will use the list of channels that is assigned to the device to lookup a channel by scan index in iio_compute_scan_bytes(). If it can not find the channel the function will crash. This patch fixes the issue by making sure that the same set of channels is assigned to the IIO device and passed to iio_buffer_register(). Fixes the follow NULL pointer derefernce kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 00000016 pgd = d53d0000 [00000016] *pgd=1534e831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1626 Comm: bash Not tainted 3.15.0-19969-g2a180eb-dirty #9545 task: d6c124c0 ti: d539a000 task.ti: d539a000 PC is at iio_compute_scan_bytes+0x34/0xa8 LR is at iio_compute_scan_bytes+0x34/0xa8 pc : [] lr : [] psr: 60070013 sp : d539beb8 ip : 00000001 fp : 00000000 r10: 00000002 r9 : 00000000 r8 : 00000001 r7 : 00000000 r6 : d6dc8800 r5 : d7571000 r4 : 00000002 r3 : d7571000 r2 : 00000044 r1 : 00000001 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c5387d Table: 153d004a DAC: 00000015 Process bash (pid: 1626, stack limit = 0xd539a240) Stack: (0xd539beb8 to 0xd539c000) bea0: c02fc0e4 d7571000 bec0: d76c1640 d6dc8800 d757117c 00000000 d757112c c0305b04 d76c1690 d76c1640 bee0: d7571188 00000002 00000000 d7571000 d539a000 00000000 000dd1c8 c0305d54 bf00: d7571010 0160b868 00000002 c69d3900 d7573278 d7573308 c69d3900 c01ece90 bf20: 00000002 c0103fac c0103f6c d539bf88 00000002 c69d3b00 c69d3b0c c0103468 bf40: 00000000 00000000 d7694a00 00000002 000af408 d539bf88 c000dd84 c00b2f94 bf60: d7694a00 000af408 00000002 d7694a00 d7694a00 00000002 000af408 c000dd84 bf80: 00000000 c00b32d0 00000000 00000000 00000002 b6f1aa78 00000002 000af408 bfa0: 00000004 c000dc00 b6f1aa78 00000002 00000001 000af408 00000002 00000000 bfc0: b6f1aa78 00000002 000af408 00000004 be806a4c 000a6094 00000000 000dd1c8 bfe0: 00000000 be8069cc b6e8ab77 b6ec125c 40070010 00000001 22940489 154a5007 [] (iio_compute_scan_bytes) from [] (__iio_update_buffers+0x248/0x438) [] (__iio_update_buffers) from [] (iio_buffer_store_enable+0x60/0x7c) [] (iio_buffer_store_enable) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store) from [] (sysfs_kf_write+0x40/0x4c) [] (sysfs_kf_write) from [] (kernfs_fop_write+0x110/0x154) [] (kernfs_fop_write) from [] (vfs_write+0xd0/0x160) [] (vfs_write) from [] (SyS_write+0x40/0x78) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) Code: ea00000e e1a01008 e1a00005 ebfff6fc (e5d0a016) Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars-Peter Clausen Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index d0c89d0457de08..9a6665dcf72b23 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -115,6 +115,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), .address = AD5933_REG_TEMP_DATA, + .scan_index = -1, .scan_type = { .sign = 's', .realbits = 14, @@ -125,8 +126,6 @@ static const struct iio_chan_spec ad5933_channels[] = { .indexed = 1, .channel = 0, .extend_name = "real_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), .address = AD5933_REG_REAL_DATA, .scan_index = 0, .scan_type = { @@ -139,8 +138,6 @@ static const struct iio_chan_spec ad5933_channels[] = { .indexed = 1, .channel = 0, .extend_name = "imag_raw", - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), .address = AD5933_REG_IMAG_DATA, .scan_index = 1, .scan_type = { @@ -749,14 +746,14 @@ static int ad5933_probe(struct i2c_client *client, indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad5933_channels; - indio_dev->num_channels = 1; /* only register temp0_input */ + indio_dev->num_channels = ARRAY_SIZE(ad5933_channels); ret = ad5933_register_ring_funcs_and_init(indio_dev); if (ret) goto error_disable_reg; - /* skip temp0_input, register in0_(real|imag)_raw */ - ret = iio_buffer_register(indio_dev, &ad5933_channels[1], 2); + ret = iio_buffer_register(indio_dev, ad5933_channels, + ARRAY_SIZE(ad5933_channels)); if (ret) goto error_unreg_ring; From a17a85df741511bc867c77c22c46d8a5d160d9f0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 25 Sep 2014 15:27:00 +0100 Subject: [PATCH 364/889] staging:iio:ad5933: Drop "raw" from channel names "raw" is the name of a channel property, but should not be part of the channel name itself. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 9a6665dcf72b23..b6bd609c3655f9 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -125,7 +125,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .extend_name = "real_raw", + .extend_name = "real", .address = AD5933_REG_REAL_DATA, .scan_index = 0, .scan_type = { @@ -137,7 +137,7 @@ static const struct iio_chan_spec ad5933_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .extend_name = "imag_raw", + .extend_name = "imag", .address = AD5933_REG_IMAG_DATA, .scan_index = 1, .scan_type = { From 06f2afbc3d8e893135531776f8d73285856de3ea Mon Sep 17 00:00:00 2001 From: Robin van der Gracht Date: Mon, 29 Sep 2014 15:00:07 +0200 Subject: [PATCH 365/889] iio: st_sensors: Fix buffer copy Use byte_for_channel as iterator to properly initialize the buffer. Signed-off-by: Robin van der Gracht Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron Cc: --- drivers/iio/common/st_sensors/st_sensors_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 1665c8e4b62b24..e18bc67822563e 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -71,7 +71,7 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) goto st_sensors_free_memory; } - for (i = 0; i < n * num_data_channels; i++) { + for (i = 0; i < n * byte_for_channel; i++) { if (i < n) buf[i] = rx_array[i]; else From 1ebd38b7c57e34fae1e458cd33ce090fffdc3238 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 14 Sep 2014 21:48:28 +0300 Subject: [PATCH 366/889] mac80211: fix warning on htmldocs for last_tdls_pkt_time Forgot to add an entry to the struct description of sta_info. Signed-off-by: Liad Kaufman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/sta_info.h | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 42f68cb8957e5a..bcda2ac7d84402 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -336,6 +336,7 @@ struct ieee80211_tx_latency_stat { * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * AP only. * @cipher_scheme: optional cipher scheme for this station + * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed */ struct sta_info { /* General information, mostly static */ From 31d5ed1b72cd04a2bf518aa7b7eef22ac3581185 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 30 Sep 2014 07:08:02 +0300 Subject: [PATCH 367/889] mac80211: return the vif's chandef in ieee80211_cfg_get_channel() The chandef of the channel context a vif is using may be different than the chandef of the vif itself. For instance, the bandwidth used by the vif may be narrower than the one configured in the channel context. To avoid confusion, return the vif's chandef in ieee80211_cfg_get_channel() instead of the chandef of the channel context. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb6a1502b6dfa6..343da1e3502519 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3458,7 +3458,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (chanctx_conf) { - *chandef = chanctx_conf->def; + *chandef = sdata->vif.bss_conf.chandef; ret = 0; } else if (local->open_count > 0 && local->open_count == local->monitors && From b6917c79c1a74e0a40716289b5037882353f03f2 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 8 Oct 2014 09:48:34 +0300 Subject: [PATCH 368/889] nl80211: sanity check the channel switch counter value The nl80211 channel switch count attribute (NL80211_ATTR_CH_SWITCH_COUNT) is specified as u32, but the specification uses u8 for the counter. To make sure strange things don't happen without informing the user, sanity check the value and return -EINVAL if it doesn't fit in u8. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cb9f5a44ffadf7..5839c85075f154 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5927,6 +5927,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) int err; bool need_new_beacon = false; int len, i; + u32 cs_count; if (!rdev->ops->channel_switch || !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) @@ -5963,7 +5964,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES]) return -EINVAL; - params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); + /* Even though the attribute is u32, the specification says + * u8, so let's make sure we don't overflow. + */ + cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); + if (cs_count > 255) + return -EINVAL; + + params.count = cs_count; if (!need_new_beacon) goto skip_beacons; From a5619e1650e0a2db184f9416cfac715cf43b8f59 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 4 Oct 2014 08:50:21 -0300 Subject: [PATCH 369/889] iio: adc: mxs-lradc: Disable the clock on probe failure We should disable lradc->clk in the case of errors in the probe function. Signed-off-by: Fabio Estevam Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron Cc: --- drivers/staging/iio/adc/mxs-lradc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 32a19264a170ce..2a29b9baec0de5 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1559,14 +1559,16 @@ static int mxs_lradc_probe(struct platform_device *pdev) /* Grab all IRQ sources */ for (i = 0; i < of_cfg->irq_count; i++) { lradc->irq[i] = platform_get_irq(pdev, i); - if (lradc->irq[i] < 0) - return lradc->irq[i]; + if (lradc->irq[i] < 0) { + ret = lradc->irq[i]; + goto err_clk; + } ret = devm_request_irq(dev, lradc->irq[i], mxs_lradc_handle_irq, 0, of_cfg->irq_name[i], iio); if (ret) - return ret; + goto err_clk; } lradc->vref_mv = of_cfg->vref_mv; @@ -1588,7 +1590,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) &mxs_lradc_trigger_handler, &mxs_lradc_buffer_ops); if (ret) - return ret; + goto err_clk; ret = mxs_lradc_trigger_init(iio); if (ret) @@ -1643,6 +1645,8 @@ static int mxs_lradc_probe(struct platform_device *pdev) mxs_lradc_trigger_remove(iio); err_trig: iio_triggered_buffer_cleanup(iio); +err_clk: + clk_disable_unprepare(lradc->clk); return ret; } From bf6ccb02e9a0bf721a09f32b7d873382202fcb2a Mon Sep 17 00:00:00 2001 From: Adel Gadllah Date: Thu, 9 Oct 2014 08:05:52 +0200 Subject: [PATCH 370/889] HID: usbhid: enable always-poll quirk for Elan Touchscreen 009b This device needs the quirk as well. Signed-off-by: Adel Gadllah Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index cd9c9e96cf0ef8..27fbd138c5091d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -298,6 +298,7 @@ #define USB_VENDOR_ID_ELAN 0x04f3 #define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089 +#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B 0x009b #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index f3cb5b0a43454e..40aac21581565b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -71,6 +71,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, From 10bf35f280e6b0193d6209f206338320852c6083 Mon Sep 17 00:00:00 2001 From: Adel Gadllah Date: Thu, 9 Oct 2014 08:05:53 +0200 Subject: [PATCH 371/889] HID: usbhid: enable always-poll quirk for Elan Touchscreen 016f This device needs the quirk as well. Tested-by: Kevin Fenzi Signed-off-by: Adel Gadllah Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 27fbd138c5091d..e23ab8b30626da 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -299,6 +299,7 @@ #define USB_VENDOR_ID_ELAN 0x04f3 #define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089 #define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B 0x009b +#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F 0x016f #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 40aac21581565b..5014bb567b29cd 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -72,6 +72,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, From 9b4c4afdec0d22231aee3cf3b56c48a7a8e6af2f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 10 Oct 2014 11:25:20 +0200 Subject: [PATCH 372/889] netfilter: missing module license in the nf_reject_ipvX modules [ 23.545204] nf_reject_ipv4: module license 'unspecified' taints kernel. Fixes: c8d7b98 ("netfilter: move nf_send_resetX() code to nf_reject_ipvX modules") Reported-by: Dave Young Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_reject_ipv4.c | 3 +++ net/ipv6/netfilter/nf_reject_ipv6.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index b023b4eb1a9664..92b303dbd5fcdd 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -125,3 +126,5 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) kfree_skb(nskb); } EXPORT_SYMBOL_GPL(nf_send_reset); + +MODULE_LICENSE("GPL"); diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 5f5f0438d74d9b..20d9defc6c59c2 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -5,6 +5,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#include #include #include #include @@ -161,3 +163,5 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) ip6_local_out(nskb); } EXPORT_SYMBOL_GPL(nf_send_reset6); + +MODULE_LICENSE("GPL"); From 42ecaa6653c41e4ac560ae0ff0b20b6458b56422 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 13 Oct 2014 19:50:22 +0200 Subject: [PATCH 373/889] netfilter: nf_tables: restrict nat/masq expressions to nat chain type This adds the missing validation code to avoid the use of nat/masq from non-nat chains. The validation assumes two possible configuration scenarios: 1) Use of nat from base chain that is not of nat type. Reject this configuration from the nft_*_init() path of the expression. 2) Use of nat from non-base chain. In this case, we have to wait until the non-base chain is referenced by at least one base chain via jump/goto. This is resolved from the nft_*_validate() path which is called from nf_tables_check_loops(). The user gets an -EOPNOTSUPP in both cases. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 3 +++ include/net/netfilter/nft_masq.h | 3 +++ net/ipv4/netfilter/nft_masq_ipv4.c | 1 + net/ipv6/netfilter/nft_masq_ipv6.c | 1 + net/netfilter/nf_tables_api.c | 14 ++++++++++++++ net/netfilter/nft_masq.c | 12 ++++++++++++ net/netfilter/nft_nat.c | 12 ++++++++++++ 7 files changed, 46 insertions(+) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 3d7292392fac91..845c596bf594c5 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -530,6 +530,9 @@ enum nft_chain_type { NFT_CHAIN_T_MAX }; +int nft_chain_validate_dependency(const struct nft_chain *chain, + enum nft_chain_type type); + struct nft_stats { u64 bytes; u64 pkts; diff --git a/include/net/netfilter/nft_masq.h b/include/net/netfilter/nft_masq.h index c72729f954f41e..e2a518b60e1903 100644 --- a/include/net/netfilter/nft_masq.h +++ b/include/net/netfilter/nft_masq.h @@ -13,4 +13,7 @@ int nft_masq_init(const struct nft_ctx *ctx, int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); +int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + const struct nft_data **data); + #endif /* _NFT_MASQ_H_ */ diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c index 1c636d6b5b5007..c1023c4459201a 100644 --- a/net/ipv4/netfilter/nft_masq_ipv4.c +++ b/net/ipv4/netfilter/nft_masq_ipv4.c @@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = { .eval = nft_masq_ipv4_eval, .init = nft_masq_init, .dump = nft_masq_dump, + .validate = nft_masq_validate, }; static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c index 556262f407616e..8a7ac685076d91 100644 --- a/net/ipv6/netfilter/nft_masq_ipv6.c +++ b/net/ipv6/netfilter/nft_masq_ipv6.c @@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = { .eval = nft_masq_ipv6_eval, .init = nft_masq_init, .dump = nft_masq_dump, + .validate = nft_masq_validate, }; static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 556a0dfa4abc07..65eb2a1160d544 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3744,6 +3744,20 @@ static const struct nfnetlink_subsystem nf_tables_subsys = { .abort = nf_tables_abort, }; +int nft_chain_validate_dependency(const struct nft_chain *chain, + enum nft_chain_type type) +{ + const struct nft_base_chain *basechain; + + if (chain->flags & NFT_BASE_CHAIN) { + basechain = nft_base_chain(chain); + if (basechain->type->type != type) + return -EOPNOTSUPP; + } + return 0; +} +EXPORT_SYMBOL_GPL(nft_chain_validate_dependency); + /* * Loop detection - walk through the ruleset beginning at the destination chain * of a new jump until either the source chain is reached (loop) or all diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c index 6637bab0056705..d1ffd5eb3a9b5b 100644 --- a/net/netfilter/nft_masq.c +++ b/net/netfilter/nft_masq.c @@ -26,6 +26,11 @@ int nft_masq_init(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { struct nft_masq *priv = nft_expr_priv(expr); + int err; + + err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); + if (err < 0) + return err; if (tb[NFTA_MASQ_FLAGS] == NULL) return 0; @@ -55,5 +60,12 @@ int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr) } EXPORT_SYMBOL_GPL(nft_masq_dump); +int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + const struct nft_data **data) +{ + return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); +} +EXPORT_SYMBOL_GPL(nft_masq_validate); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arturo Borrero Gonzalez "); diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 799550b476fbde..0f0af6e86fb8a5 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -95,6 +95,10 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, u32 family; int err; + err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); + if (err < 0) + return err; + if (tb[NFTA_NAT_TYPE] == NULL) return -EINVAL; @@ -205,6 +209,13 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) return -1; } +static int nft_nat_validate(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nft_data **data) +{ + return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); +} + static struct nft_expr_type nft_nat_type; static const struct nft_expr_ops nft_nat_ops = { .type = &nft_nat_type, @@ -212,6 +223,7 @@ static const struct nft_expr_ops nft_nat_ops = { .eval = nft_nat_eval, .init = nft_nat_init, .dump = nft_nat_dump, + .validate = nft_nat_validate, }; static struct nft_expr_type nft_nat_type __read_mostly = { From 764995524fdff560da6c3d4aa4b15cae3355d414 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 13 Oct 2014 14:34:41 +0200 Subject: [PATCH 374/889] mac80211: fix typo in starting baserate for rts_cts_rate_idx It affects non-(V)HT rates and can lead to selecting an rts_cts rate that is not a basic rate or way superior to the reference rate (ATM rates[0] used for the 1st attempt of the protected frame data). E.g, assuming drivers register growing (bitrate) sorted tables of ieee80211_rate-s, having : - rates[0].idx == d'2 and basic_rates == b'10100 will select rts_cts idx b'10011 & ~d'(BIT(2)-1), i.e. 1, likewise - rates[0].idx == d'2 and basic_rates == b'10001 will select rts_cts idx b'10000 The first is not a basic rate and the second is > rates[0]. Also, wrt severity of the addressed misbehavior, ATM we only have one rts_cts_rate_idx rather than one per rate table entry, so this idx might still point to bitrates > rates[1..MAX_RATES]. Fixes: 5253ffb8c9e1 ("mac80211: always pick a basic rate to tx RTS/CTS for pre-HT rates") Cc: stable@vger.kernel.org Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- net/mac80211/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 8fdadfd94ba857..6081329784dd44 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -448,7 +448,7 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif, */ if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) { u32 basic_rates = vif->bss_conf.basic_rates; - s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0; + s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0; rate = &sband->bitrates[rates[0].idx]; From 69619dab744b5a10d6f64ac633910ae468885cac Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 14 Oct 2014 12:43:50 +0200 Subject: [PATCH 375/889] netfilter: nft_compat: fix hook validation for non-base chains Set hook_mask to zero for non-base chains, otherwise people may hit bogus errors from the xt_check_target() and xt_check_match() when validating the uninitialized hook_mask. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_compat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 7e2683c8a44a9d..44ae273b43917c 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -95,6 +95,8 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, const struct nf_hook_ops *ops = &basechain->ops[0]; par->hook_mask = 1 << ops->hooknum; + } else { + par->hook_mask = 0; } par->family = ctx->afi->family; } @@ -293,6 +295,8 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, const struct nf_hook_ops *ops = &basechain->ops[0]; par->hook_mask = 1 << ops->hooknum; + } else { + par->hook_mask = 0; } par->family = ctx->afi->family; } From 923a5942c0a5902900a1001b97a8664d128d21b0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 14 Oct 2014 11:11:02 -0300 Subject: [PATCH 376/889] ASoC: sgtl500: Document the required supplies sgtl5000 has two required supplies: VDDA and VDDIO and one optional supply: VDDD, so document this properly. Not passing VDDA and VDDIO prevents the driver to probe successfully. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/sgtl5000.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 955df60a118c54..d556dcb8816bd9 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -7,10 +7,20 @@ Required properties: - clocks : the clock provider of SYS_MCLK +- VDDA-supply : the regulator provider of VDDA + +- VDDIO-supply: the regulator provider of VDDIO + +Optional properties: + +- VDDD-supply : the regulator provider of VDDD + Example: codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; clocks = <&clks 150>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; }; From ef38ae007f8021d6134a7a9205d856804f8b13db Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 16 Oct 2014 15:29:14 +0100 Subject: [PATCH 377/889] ASoC: Intel: HSW/BDW only support S16 and S24 formats. Fix driver with correct formats. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/intel/sst-haswell-pcm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 33fc5c3abf558e..4df867cbb92a19 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -691,9 +691,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) } #define HSW_FORMATS \ - (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S8) + (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) static struct snd_soc_dai_driver hsw_dais[] = { { From 079fe8b53ecf0570d5a2600de4cd3e15d02d2bb5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 27 Aug 2014 16:53:31 +0100 Subject: [PATCH 378/889] drm/armada: add IRQ support back Add IRQ support back so that vblank ioctls work again. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index f672e6ad8afae0..908e5316eac425 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -190,6 +190,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_comp; + dev->irq_enabled = true; dev->vblank_disable_allowed = 1; ret = armada_fbdev_init(dev); @@ -331,7 +332,7 @@ static struct drm_driver armada_drm_driver = { .desc = "Armada SoC DRM", .date = "20120730", .driver_features = DRIVER_GEM | DRIVER_MODESET | - DRIVER_PRIME, + DRIVER_HAVE_IRQ | DRIVER_PRIME, .ioctls = armada_ioctls, .fops = &armada_drm_fops, }; From a0c87d28e32e797294425a82d85f9098be698e78 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 11 Oct 2014 23:53:35 +0100 Subject: [PATCH 379/889] drm/armada: fix page_flip refcounting leak A refcounting leak was found of the original frame buffer attached to the CRTC when using the page_flip ioctl, resulting in the frame buffer never being freed. This was not obvious initially, as if the page flip subsequently re-attaches the original frame buffer, the refcounts will be balanced. However, if the original frame buffer is freed, then it will be leaked. Fix this by ensuring that we take a reference on the incoming fb, but rely on the queued work to drop that ref count. Reviewed-by: Daniel Vetter Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9a0cc09e665308..ef6be294c07da4 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -945,18 +945,15 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, armada_reg_queue_end(work->regs, i); /* - * Hold the old framebuffer for the work - DRM appears to drop our - * reference to the old framebuffer in drm_mode_page_flip_ioctl(). + * Ensure that we hold a reference on the new framebuffer. + * This has to match the behaviour in mode_set. */ - drm_framebuffer_reference(work->old_fb); + drm_framebuffer_reference(fb); ret = armada_drm_crtc_queue_frame_work(dcrtc, work); if (ret) { - /* - * Undo our reference above; DRM does not drop the reference - * to this object on error, so that's okay. - */ - drm_framebuffer_unreference(work->old_fb); + /* Undo our reference above */ + drm_framebuffer_unreference(fb); kfree(work); return ret; } From f227cc3f80a6d5af19ea56078de427833416db1c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 11 Oct 2014 23:57:04 +0100 Subject: [PATCH 380/889] drm/armada: convert to use vblank_on/off calls A future commit changes the way various vblank calls behave, which causes drivers to break. Converting to use the drm_crtc_vblank_on/off calls avoids this breakage. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index ef6be294c07da4..e4a1490b42c280 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -260,7 +260,7 @@ static void armada_drm_vblank_off(struct armada_crtc *dcrtc) * Tell the DRM core that vblank IRQs aren't going to happen for * a while. This cleans up any pending vblank events for us. */ - drm_vblank_off(dev, dcrtc->num); + drm_crtc_vblank_off(&dcrtc->crtc); /* Handle any pending flip event. */ spin_lock_irq(&dev->event_lock); @@ -289,6 +289,8 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) armada_drm_crtc_update(dcrtc); if (dpms_blanked(dpms)) armada_drm_vblank_off(dcrtc); + else + drm_crtc_vblank_on(&dcrtc->crtc); } } @@ -526,7 +528,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, /* Wait for pending flips to complete */ wait_event(dcrtc->frame_wait, !dcrtc->frame_work); - drm_vblank_pre_modeset(crtc->dev, dcrtc->num); + drm_crtc_vblank_off(crtc); crtc->mode = *adj; @@ -617,7 +619,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_drm_crtc_update(dcrtc); - drm_vblank_post_modeset(crtc->dev, dcrtc->num); + drm_crtc_vblank_on(crtc); armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); return 0; From ac01fed690645b89d3e43472d665bdd0e11c176c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 29 Sep 2014 11:47:53 +0200 Subject: [PATCH 381/889] mtd: m25p80: get rid of spi_get_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies the way we use spi_nor framework and will allow us to drop spi_nor_match_id. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dcda6287228d0b..822209d1068930 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -197,6 +197,7 @@ static int m25p_probe(struct spi_device *spi) struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; + char *flash_name = NULL; int ret; data = dev_get_platdata(&spi->dev); @@ -236,12 +237,11 @@ static int m25p_probe(struct spi_device *spi) * If that's the case, respect "type" and ignore a "name". */ if (data && data->type) - id = spi_nor_match_id(data->type); - - /* If we didn't get name from platform, simply use "modalias". */ - if (!id) - id = spi_get_device_id(spi); + flash_name = data->type; + else + flash_name = spi->modalias; + id = spi_nor_match_id(flash_name); ret = spi_nor_scan(nor, id, mode); if (ret) return ret; From d357d3b674cd83fd83c01296f231a344bd811c5b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 29 Sep 2014 11:47:54 +0200 Subject: [PATCH 382/889] mtd: spi-nor: make spi_nor_scan() take a chip type name, not spi_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drivers currently call spi_nor_match_id() and then spi_nor_scan(). This adds a dependency on struct spi_device_id which we want to avoid. Make spi_nor_scan() do it for them. Signed-off-by: Ben Hutchings Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 4 +--- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +------ drivers/mtd/spi-nor/spi-nor.c | 13 +++++++++---- include/linux/mtd/spi-nor.h | 20 +++----------------- 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 822209d1068930..bd5e4c6edfd4bf 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -193,7 +193,6 @@ static int m25p_probe(struct spi_device *spi) { struct mtd_part_parser_data ppdata; struct flash_platform_data *data; - const struct spi_device_id *id = NULL; struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; @@ -241,8 +240,7 @@ static int m25p_probe(struct spi_device *spi) else flash_name = spi->modalias; - id = spi_nor_match_id(flash_name); - ret = spi_nor_scan(nor, id, mode); + ret = spi_nor_scan(nor, flash_name, mode); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 8d659a2888d5f0..d5269a26c83938 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -881,7 +881,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { - const struct spi_device_id *id; char modalias[40]; /* skip the holes */ @@ -909,10 +908,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) goto map_failed; - id = spi_nor_match_id(modalias); - if (!id) - goto map_failed; - ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) @@ -921,7 +916,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); - ret = spi_nor_scan(nor, id, SPI_NOR_QUAD); + ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) goto map_failed; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index ae16aa2f688526..5c8e39977bc5b2 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,6 +28,8 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) +static const struct spi_device_id *spi_nor_match_id(const char *name); + /* * Read the status register, returning its value in the location * Return the status register value. @@ -911,9 +913,9 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode) +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { + const struct spi_device_id *id = NULL; struct flash_info *info; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; @@ -925,6 +927,10 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (ret) return ret; + id = spi_nor_match_id(name); + if (!id) + return -ENOENT; + info = (void *)id->driver_data; if (info->jedec_id) { @@ -1113,7 +1119,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(char *name) +static const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; @@ -1124,7 +1130,6 @@ const struct spi_device_id *spi_nor_match_id(char *name) } return NULL; } -EXPORT_SYMBOL_GPL(spi_nor_match_id); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f32ba88f..a5a7a086748d0c 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -187,32 +187,18 @@ struct spi_nor { /** * spi_nor_scan() - scan the SPI NOR * @nor: the spi_nor structure - * @id: the spi_device_id provided by the driver + * @name: the chip type name * @mode: the read mode supported by the driver * * The drivers can use this fuction to scan the SPI NOR. * In the scanning, it will try to get all the necessary information to * fill the mtd_info{} and the spi_nor{}. * - * The board may assigns a spi_device_id with @id which be used to compared with - * the spi_device_id detected by the scanning. + * The chip type name can be provided through the @name parameter. * * Return: 0 for success, others for failure. */ -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode); +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); extern const struct spi_device_id spi_nor_ids[]; -/** - * spi_nor_match_id() - find the spi_device_id by the name - * @name: the name of the spi_device_id - * - * The drivers use this function to find the spi_device_id - * specified by the @name. - * - * Return: returns the right spi_device_id pointer on success, - * and returns NULL on failure. - */ -const struct spi_device_id *spi_nor_match_id(char *name); - #endif From 599c6e3d07288293cf7d6ee94dd83b0f791083b7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 14 Oct 2014 10:13:48 +0200 Subject: [PATCH 383/889] netfilter: nft_compat: validate chain type in match/target We have to validate the real chain type to ensure that matches/targets are not used out from their scope (eg. MASQUERADE in nat chain type). The existing validation relies on the table name, but this is not sufficient since userspace can fool us by using the appropriate table name with a different chain type. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_compat.c | 75 +++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 44ae273b43917c..0480f57a4eb6c6 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -19,9 +19,52 @@ #include #include #include -#include /* for set_fs */ #include +static const struct { + const char *name; + u8 type; +} table_to_chaintype[] = { + { "filter", NFT_CHAIN_T_DEFAULT }, + { "raw", NFT_CHAIN_T_DEFAULT }, + { "security", NFT_CHAIN_T_DEFAULT }, + { "mangle", NFT_CHAIN_T_ROUTE }, + { "nat", NFT_CHAIN_T_NAT }, + { }, +}; + +static int nft_compat_table_to_chaintype(const char *table) +{ + int i; + + for (i = 0; table_to_chaintype[i].name != NULL; i++) { + if (strcmp(table_to_chaintype[i].name, table) == 0) + return table_to_chaintype[i].type; + } + + return -1; +} + +static int nft_compat_chain_validate_dependency(const char *tablename, + const struct nft_chain *chain) +{ + enum nft_chain_type type; + const struct nft_base_chain *basechain; + + if (!tablename || !(chain->flags & NFT_BASE_CHAIN)) + return 0; + + type = nft_compat_table_to_chaintype(tablename); + if (type < 0) + return -EINVAL; + + basechain = nft_base_chain(chain); + if (basechain->type->type != type) + return -EINVAL; + + return 0; +} + union nft_entry { struct ipt_entry e4; struct ip6t_entry e6; @@ -153,6 +196,10 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, union nft_entry e = {}; int ret; + ret = nft_compat_chain_validate_dependency(target->table, ctx->chain); + if (ret < 0) + goto err; + target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); if (ctx->nla[NFTA_RULE_COMPAT]) { @@ -218,6 +265,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, { struct xt_target *target = expr->ops->data; unsigned int hook_mask = 0; + int ret; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = @@ -225,11 +273,13 @@ static int nft_target_validate(const struct nft_ctx *ctx, const struct nf_hook_ops *ops = &basechain->ops[0]; hook_mask = 1 << ops->hooknum; - if (hook_mask & target->hooks) - return 0; + if (!(hook_mask & target->hooks)) + return -EINVAL; - /* This target is being called from an invalid chain */ - return -EINVAL; + ret = nft_compat_chain_validate_dependency(target->table, + ctx->chain); + if (ret < 0) + return ret; } return 0; } @@ -324,6 +374,10 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, union nft_entry e = {}; int ret; + ret = nft_compat_chain_validate_dependency(match->name, ctx->chain); + if (ret < 0) + goto err; + match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); if (ctx->nla[NFTA_RULE_COMPAT]) { @@ -383,6 +437,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, { struct xt_match *match = expr->ops->data; unsigned int hook_mask = 0; + int ret; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = @@ -390,11 +445,13 @@ static int nft_match_validate(const struct nft_ctx *ctx, const struct nf_hook_ops *ops = &basechain->ops[0]; hook_mask = 1 << ops->hooknum; - if (hook_mask & match->hooks) - return 0; + if (!(hook_mask & match->hooks)) + return -EINVAL; - /* This match is being called from an invalid chain */ - return -EINVAL; + ret = nft_compat_chain_validate_dependency(match->name, + ctx->chain); + if (ret < 0) + return ret; } return 0; } From 2e90b4991fe71579ce5250ca22d6c6c79f32c9c0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 16 Oct 2014 00:16:57 +0200 Subject: [PATCH 384/889] netfilter: nft_nat: insufficient attribute validation We have to validate that we at least get an NFTA_NAT_REG_ADDR_MIN or NFTA_NFT_REG_PROTO_MIN attribute. Reject the configuration if none of them are present. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_nat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 0f0af6e86fb8a5..5078f1f1c569df 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -99,7 +99,9 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, if (err < 0) return err; - if (tb[NFTA_NAT_TYPE] == NULL) + if (tb[NFTA_NAT_TYPE] == NULL || + (tb[NFTA_NAT_REG_ADDR_MIN] == NULL && + tb[NFTA_NAT_REG_PROTO_MIN] == NULL)) return -EINVAL; switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) { From 3be229893209886a434ff223817b6fb9f0d62bee Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 16 Oct 2014 00:19:35 +0200 Subject: [PATCH 385/889] netfilter: nft_nat: NFTA_NAT_REG_ADDR_MAX depends on NFTA_NAT_REG_ADDR_MIN Interpret NFTA_NAT_REG_ADDR_MAX if NFTA_NAT_REG_ADDR_MIN is present, otherwise, skip it. Same thing with NFTA_NAT_REG_PROTO_MAX. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_nat.c | 50 +++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 5078f1f1c569df..a95e0c1addd32a 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -126,38 +126,44 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, priv->family = family; if (tb[NFTA_NAT_REG_ADDR_MIN]) { - priv->sreg_addr_min = ntohl(nla_get_be32( - tb[NFTA_NAT_REG_ADDR_MIN])); + priv->sreg_addr_min = + ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN])); + err = nft_validate_input_register(priv->sreg_addr_min); if (err < 0) return err; - } - if (tb[NFTA_NAT_REG_ADDR_MAX]) { - priv->sreg_addr_max = ntohl(nla_get_be32( - tb[NFTA_NAT_REG_ADDR_MAX])); - err = nft_validate_input_register(priv->sreg_addr_max); - if (err < 0) - return err; - } else - priv->sreg_addr_max = priv->sreg_addr_min; + if (tb[NFTA_NAT_REG_ADDR_MAX]) { + priv->sreg_addr_max = + ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX])); + + err = nft_validate_input_register(priv->sreg_addr_max); + if (err < 0) + return err; + } else { + priv->sreg_addr_max = priv->sreg_addr_min; + } + } if (tb[NFTA_NAT_REG_PROTO_MIN]) { - priv->sreg_proto_min = ntohl(nla_get_be32( - tb[NFTA_NAT_REG_PROTO_MIN])); + priv->sreg_proto_min = + ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN])); + err = nft_validate_input_register(priv->sreg_proto_min); if (err < 0) return err; - } - if (tb[NFTA_NAT_REG_PROTO_MAX]) { - priv->sreg_proto_max = ntohl(nla_get_be32( - tb[NFTA_NAT_REG_PROTO_MAX])); - err = nft_validate_input_register(priv->sreg_proto_max); - if (err < 0) - return err; - } else - priv->sreg_proto_max = priv->sreg_proto_min; + if (tb[NFTA_NAT_REG_PROTO_MAX]) { + priv->sreg_proto_max = + ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX])); + + err = nft_validate_input_register(priv->sreg_proto_max); + if (err < 0) + return err; + } else { + priv->sreg_proto_max = priv->sreg_proto_min; + } + } if (tb[NFTA_NAT_FLAGS]) { priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); From b5255ce0a3f55b26a1a80b1990827c3bd9535e82 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 16 Oct 2014 00:24:14 +0200 Subject: [PATCH 386/889] netfilter: nft_nat: dump attributes if they are set Dump NFTA_NAT_REG_ADDR_MIN if this is non-zero. Same thing with NFTA_NAT_REG_PROTO_MIN. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_nat.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index a95e0c1addd32a..afe2b0b45ec41f 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -191,17 +191,19 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family))) goto nla_put_failure; - if (nla_put_be32(skb, - NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min))) - goto nla_put_failure; - if (nla_put_be32(skb, - NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max))) - goto nla_put_failure; + + if (priv->sreg_addr_min) { + if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN, + htonl(priv->sreg_addr_min)) || + nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX, + htonl(priv->sreg_addr_max))) + goto nla_put_failure; + } + if (priv->sreg_proto_min) { if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN, - htonl(priv->sreg_proto_min))) - goto nla_put_failure; - if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, + htonl(priv->sreg_proto_min)) || + nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max))) goto nla_put_failure; } From eae5c802758489c32f2f085269f2f3510b312bc0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 15 Oct 2014 22:37:13 +0100 Subject: [PATCH 387/889] ARM: Blacklist GCC 4.8.0 to GCC 4.8.2 - PR58854 These stock GCC versions miscompile the kernel by incorrectly optimising the function epilogue code - by first increasing the stack pointer, and then loading entries from below the stack. This means that an opportune interrupt or exception will corrupt the current function's saved state, which may result in the parent function seeing different register values. As this bug has been known to result in corrupted filesystems, and these buggy compiler versions seem to be frequently used, we have little option but to blacklist these compiler versions. Distributions may have fixed PR58854, but as their compilers are totally indistinguishable from the buggy versions, it is unfortunate that this also results in those also being blacklisted. Given the filesystem corruption potential of the original, this is the lesser evil. People who want to build with their fixed compiler versions will need to adjust the kernel source. (Distros need to think about the implications of fixing such a compiler bug, and consider how to ensure that their fixed compiler versions can be detected if they wish to avoid this.) Signed-off-by: Russell King --- arch/arm/kernel/asm-offsets.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 713e807621d2cf..2d2d6087b9b105 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -10,6 +10,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include @@ -39,10 +40,19 @@ * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c * (http://gcc.gnu.org/PR8896) and incorrect structure * initialisation in fs/jffs2/erase.c + * GCC 4.8.0-4.8.2: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58854 + * miscompiles find_get_entry(), and can result in EXT3 and EXT4 + * filesystem corruption (possibly other FS too). */ +#ifdef __GNUC__ #if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) #error Your compiler is too buggy; it is known to miscompile kernels. -#error Known good compilers: 3.3 +#error Known good compilers: 3.3, 4.x +#endif +#if GCC_VERSION >= 40800 && GCC_VERSION < 40803 +#error Your compiler is too buggy; it is known to miscompile kernels +#error and result in filesystem corruption and oopses. +#endif #endif int main(void) From 6f6441b755e5727fbba562b0a39510648c97f34d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 19 Oct 2014 11:41:52 +0200 Subject: [PATCH 388/889] x86/smpboot: Move data structure to its primary usage scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the code more readable by moving variable and usage closer to each other, which also avoids this build warning in the !CONFIG_HOTPLUG_CPU case: arch/x86/kernel/smpboot.c:105:42: warning: ‘die_complete’ defined but not used [-Wunused-variable] Cc: Prarit Bhargava Cc: Lan Tianyu Cc: Borislav Petkov Cc: Peter Zijlstra Cc: srostedt@redhat.com Cc: toshi.kani@hp.com Cc: imammedo@redhat.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1409039025-32310-1-git-send-email-tianyu.lan@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/smpboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2d5200e56357d4..4d2128ac70bdab 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -102,8 +102,6 @@ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map); DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info); EXPORT_PER_CPU_SYMBOL(cpu_info); -static DEFINE_PER_CPU(struct completion, die_complete); - atomic_t init_deasserted; /* @@ -1318,6 +1316,8 @@ void cpu_disable_common(void) fixup_irqs(); } +static DEFINE_PER_CPU(struct completion, die_complete); + int native_cpu_disable(void) { int ret; From c601b2c0081800aa6c8f85412c70b8ccc0bb2d6e Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Oct 2014 16:09:14 +0100 Subject: [PATCH 389/889] staging: comedi: (regression) channel list must be set for COMEDI_CMD ioctl `do_cmd_ioctl()`, the handler for the `COMEDI_CMD` ioctl can incorrectly call the Comedi subdevice's `do_cmd()` handler with a NULL channel list pointer. This is a regression as the `do_cmd()` handler has never been expected to deal with that, leading to a kernel OOPS when it tries to dereference it. A NULL channel list pointer is allowed for the `COMEDI_CMDTEST` ioctl, handled by `do_cmdtest_ioctl()` and the subdevice's `do_cmdtest()` handler, but not for the `COMEDI_CMD` ioctl and its handlers. Both `do_cmd_ioctl()` and `do_cmdtest_ioctl()` call `__comedi_get_user_chanlist()` to copy the channel list from user memory into dynamically allocated kernel memory and check it for consistency. That function currently returns 0 if the `user_chanlist` parameter (pointing to the channel list in user memory) is NULL. That's fine for `do_cmdtest_ioctl()`, but `do_cmd_ioctl()` incorrectly assumes the kernel copy of the channel list has been set-up correctly. Fix it by not allowing the `user_chanlist` parameter to be NULL in `__comedi_get_user_chanlist()`, and only calling it from `do_cmdtest_ioctl()` if the parameter is non-NULL. Thanks to Bernd Porr for reporting the bug via an initial patch sent privately. Fixes: c6cd0eefb27b ("staging: comedi: comedi_fops: introduce __comedi_get_user_chanlist()") Reported-by: Bernd Porr Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Cc: Bernd Porr Cc: # 3.15.y 3.16.y 3.17.y Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 495969f46e7665..a9b7fe52d380a5 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1462,10 +1462,6 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev, unsigned int *chanlist; int ret; - /* user_chanlist could be NULL for do_cmdtest ioctls */ - if (!user_chanlist) - return 0; - chanlist = memdup_user(user_chanlist, cmd->chanlist_len * sizeof(unsigned int)); if (IS_ERR(chanlist)) @@ -1609,10 +1605,13 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, s = &dev->subdevices[cmd.subdev]; - /* load channel/gain list */ - ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd); - if (ret) - return ret; + /* user_chanlist can be NULL for COMEDI_CMDTEST ioctl */ + if (user_chanlist) { + /* load channel/gain list */ + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd); + if (ret) + return ret; + } ret = s->do_cmdtest(dev, s, &cmd); From 22de64677288a3cb9f88fb37fe9b41a04626e564 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 2 Oct 2014 22:41:18 +0800 Subject: [PATCH 390/889] drivers/staging/comedi/Kconfig: Let COMEDI_II_PCI20KC depend on HAS_IOMEM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit COMEDI_II_PCI20KC needs HAS_IOMEM, so depend on it. The related error ( with allmodconfig under um): CC [M] drivers/staging/comedi/drivers/ii_pci20kc.o drivers/staging/comedi/drivers/ii_pci20kc.c: In function ‘ii20k_attach’: drivers/staging/comedi/drivers/ii_pci20kc.c:442:2: error: implicit declaration of function ‘ioremap’ [-Werror=implicit-function-declaration] dev->mmio = ioremap(membase, II20K_SIZE); ^ drivers/staging/comedi/drivers/ii_pci20kc.c:442:12: warning: assignment makes pointer from integer without a cast [enabled by default] dev->mmio = ioremap(membase, II20K_SIZE); ^ drivers/staging/comedi/drivers/ii_pci20kc.c: In function ‘ii20k_detach’: drivers/staging/comedi/drivers/ii_pci20kc.c:512:3: error: implicit declaration of function ‘iounmap’ [-Werror=implicit-function-declaration] iounmap(dev->mmio); ^ Signed-off-by: Chen Gang Reviewed-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index a8bc2b567789c8..b709736c683375 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -426,6 +426,7 @@ config COMEDI_AIO_IIRO_16 config COMEDI_II_PCI20KC tristate "Intelligent Instruments PCI-20001C carrier support" + depends on HAS_IOMEM ---help--- Enable support for Intelligent Instruments PCI-20001C carrier PCI-20001, PCI-20006 and PCI-20341 From fa2dcf7af6d6a0bc2c85f21aad942cecbd5bffd4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Fri, 10 Oct 2014 21:41:24 +0200 Subject: [PATCH 391/889] staging: rtl8723au: Fix alignment of mac_addr for ether_addr_copy() usage Make sure struct eeprom_priv->mac_addr is 2 byte aligned to work with ether_addr_copy() Reported-by: Dan Carpenter Signed-off-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/include/rtw_eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723au/include/rtw_eeprom.h b/drivers/staging/rtl8723au/include/rtw_eeprom.h index e5121a2a64b459..a86f36e49dd1bb 100644 --- a/drivers/staging/rtl8723au/include/rtw_eeprom.h +++ b/drivers/staging/rtl8723au/include/rtw_eeprom.h @@ -107,12 +107,12 @@ enum rt_customer_id }; struct eeprom_priv { + u8 mac_addr[6]; /* PermanentAddress */ u8 bautoload_fail_flag; u8 bloadfile_fail_flag; u8 bloadmac_fail_flag; /* u8 bempty; */ /* u8 sys_config; */ - u8 mac_addr[6]; /* PermanentAddress */ /* u8 config0; */ u16 channel_plan; /* u8 country_string[3]; */ From 01bdd5e49a4ccb799d63d381c94fd1a6edd3ae1b Mon Sep 17 00:00:00 2001 From: Ian Morgan Date: Sun, 19 Oct 2014 08:05:13 -0400 Subject: [PATCH 392/889] ax88179_178a: fix bonding failure The following patch fixes a bug which causes the ax88179_178a driver to be incapable of being added to a bond. When I brought up the issue with the bonding maintainers, they indicated that the real problem was with the NIC driver which must return zero for success (of setting the MAC address). I see that several other NIC drivers follow that pattern by either simply always returing zero, or by passing through a negative (error) result while rewriting any positive return code to zero. With that same philisophy applied to the ax88179_178a driver, it allows it to work correctly with the bonding driver. I believe this is suitable for queuing in -stable, as it's a small, simple, and obvious fix that corrects a defect with no other known workaround. This patch is against vanilla 3.17(.0). Signed-off-by: Ian Morgan drivers/net/usb/ax88179_178a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) Signed-off-by: David S. Miller --- drivers/net/usb/ax88179_178a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index be4275721039ad..e6338c16081a5d 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -937,6 +937,7 @@ static int ax88179_set_mac_addr(struct net_device *net, void *p) { struct usbnet *dev = netdev_priv(net); struct sockaddr *addr = p; + int ret; if (netif_running(net)) return -EBUSY; @@ -946,8 +947,12 @@ static int ax88179_set_mac_addr(struct net_device *net, void *p) memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); /* Set the MAC address */ - return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, + ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, net->dev_addr); + if (ret < 0) + return ret; + + return 0; } static const struct net_device_ops ax88179_netdev_ops = { From 35ca70f6144f07107a63b9d1a21c454c8ef9dff9 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 26 Sep 2014 16:14:51 +0200 Subject: [PATCH 393/889] pinctrl: baytrail: Clear DIRECT_IRQ bit Direct irq en bit should be cleared for pads using io mode. If not, the io based irq will never be detected. However, this bit can sometimes be misconfigured (BIOS issue). Force clearing of this bit in io mode and trigger a WARN. Signed-off-by: Loic Poulain Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-baytrail.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index e12e5b07f6d751..b83ec87c71fe91 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -227,10 +227,14 @@ static int byt_irq_type(struct irq_data *d, unsigned type) spin_lock_irqsave(&vg->lock, flags); value = readl(reg); + WARN(value & BYT_DIRECT_IRQ_EN, + "Bad pad config for io mode, force direct_irq_en bit clearing"); + /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits * are used to indicate high and low level triggering */ - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG | + BYT_TRIG_LVL); switch (type) { case IRQ_TYPE_LEVEL_HIGH: From fa2458752582acbb63f225f25fdd7a005c78a3e2 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Thu, 16 Oct 2014 19:06:59 -0700 Subject: [PATCH 394/889] pinctrl: use linux-gpio mailing list The GPIO concepts are close enough to pin control that we may use the same mailing list to discuss them. Signed-off-by: Linus Walleij --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index dab92a78d1d5e5..eb9affb9745880 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7175,6 +7175,7 @@ F: drivers/crypto/picoxcell* PIN CONTROL SUBSYSTEM M: Linus Walleij +L: linux-gpio@vger.kernel.org S: Maintained F: drivers/pinctrl/ F: include/linux/pinctrl/ From d607a69c78d19d29408a83b6de60c374c36f2305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Sun, 19 Oct 2014 00:50:50 +0200 Subject: [PATCH 395/889] ASoC: s6000: remove driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The s6000 Xtensa support is removed from the kernel. There are no other chips known to use this I2S controller. Signed-off-by: Daniel Glöckner Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 - sound/soc/Makefile | 1 - sound/soc/s6000/Kconfig | 26 -- sound/soc/s6000/Makefile | 11 - sound/soc/s6000/s6000-i2s.c | 617 ---------------------------------- sound/soc/s6000/s6000-i2s.h | 23 -- sound/soc/s6000/s6000-pcm.c | 521 ---------------------------- sound/soc/s6000/s6000-pcm.h | 33 -- sound/soc/s6000/s6105-ipcam.c | 221 ------------ 9 files changed, 1454 deletions(-) delete mode 100644 sound/soc/s6000/Kconfig delete mode 100644 sound/soc/s6000/Makefile delete mode 100644 sound/soc/s6000/s6000-i2s.c delete mode 100644 sound/soc/s6000/s6000-i2s.h delete mode 100644 sound/soc/s6000/s6000-pcm.c delete mode 100644 sound/soc/s6000/s6000-pcm.h delete mode 100644 sound/soc/s6000/s6105-ipcam.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 0e9623368ab0ad..7d5d6444a83737 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -49,7 +49,6 @@ source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" -source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 534714a1ca449d..d88edfced8c498 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ -obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig deleted file mode 100644 index f244a2566f202b..00000000000000 --- a/sound/soc/s6000/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config SND_S6000_SOC - tristate "SoC Audio for the Stretch s6000 family" - depends on XTENSA_VARIANT_S6000 || COMPILE_TEST - depends on HAS_IOMEM - select SND_S6000_SOC_PCM if XTENSA_VARIANT_S6000 - help - Say Y or M if you want to add support for codecs attached to - s6000 family chips. You will also need to select the platform - to support below. - -config SND_S6000_SOC_PCM - tristate - -config SND_S6000_SOC_I2S - tristate - -config SND_S6000_SOC_S6IPCAM - bool "SoC Audio support for Stretch 6105 IP Camera" - depends on SND_S6000_SOC=y - depends on I2C=y - depends on XTENSA_PLATFORM_S6105 || COMPILE_TEST - select SND_S6000_SOC_I2S - select SND_SOC_TLV320AIC3X - help - Say Y if you want to add support for SoC audio on the - Stretch s6105 IP Camera Reference Design. diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile deleted file mode 100644 index 0f0ae2a012aa7d..00000000000000 --- a/sound/soc/s6000/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# s6000 Platform Support -snd-soc-s6000-objs := s6000-pcm.o -snd-soc-s6000-i2s-objs := s6000-i2s.o - -obj-$(CONFIG_SND_S6000_SOC_PCM) += snd-soc-s6000.o -obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o - -# s6105 Machine Support -snd-soc-s6ipcam-objs := s6105-ipcam.o - -obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c deleted file mode 100644 index 1c8d01166e5bfd..00000000000000 --- a/sound/soc/s6000/s6000-i2s.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * ALSA SoC I2S Audio Layer for the Stretch S6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "s6000-i2s.h" -#include "s6000-pcm.h" - -struct s6000_i2s_dev { - dma_addr_t sifbase; - u8 __iomem *scbbase; - unsigned int wide; - unsigned int channel_in; - unsigned int channel_out; - unsigned int lines_in; - unsigned int lines_out; - struct s6000_pcm_dma_params dma_params; -}; - -#define S6_I2S_INTERRUPT_STATUS 0x00 -#define S6_I2S_INT_OVERRUN 1 -#define S6_I2S_INT_UNDERRUN 2 -#define S6_I2S_INT_ALIGNMENT 4 -#define S6_I2S_INTERRUPT_ENABLE 0x04 -#define S6_I2S_INTERRUPT_RAW 0x08 -#define S6_I2S_INTERRUPT_CLEAR 0x0C -#define S6_I2S_INTERRUPT_SET 0x10 -#define S6_I2S_MODE 0x20 -#define S6_I2S_DUAL 0 -#define S6_I2S_WIDE 1 -#define S6_I2S_TX_DEFAULT 0x24 -#define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c)) -#define S6_I2S_IN 0 -#define S6_I2S_OUT 1 -#define S6_I2S_UNUSED 2 -#define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c)) -#define S6_I2S_DIV_MASK 0x001fff -#define S6_I2S_16BIT 0x000000 -#define S6_I2S_20BIT 0x002000 -#define S6_I2S_24BIT 0x004000 -#define S6_I2S_32BIT 0x006000 -#define S6_I2S_BITS_MASK 0x006000 -#define S6_I2S_MEM_16BIT 0x000000 -#define S6_I2S_MEM_32BIT 0x008000 -#define S6_I2S_MEM_MASK 0x008000 -#define S6_I2S_CHANNELS_SHIFT 16 -#define S6_I2S_CHANNELS_MASK 0x030000 -#define S6_I2S_SCK_IN 0x000000 -#define S6_I2S_SCK_OUT 0x040000 -#define S6_I2S_SCK_DIR 0x040000 -#define S6_I2S_WS_IN 0x000000 -#define S6_I2S_WS_OUT 0x080000 -#define S6_I2S_WS_DIR 0x080000 -#define S6_I2S_LEFT_FIRST 0x000000 -#define S6_I2S_RIGHT_FIRST 0x100000 -#define S6_I2S_FIRST 0x100000 -#define S6_I2S_CUR_SCK 0x200000 -#define S6_I2S_CUR_WS 0x400000 -#define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c)) -#define S6_I2S_DISABLE_IF 0x02 -#define S6_I2S_ENABLE_IF 0x03 -#define S6_I2S_IS_BUSY 0x04 -#define S6_I2S_DMA_ACTIVE 0x08 -#define S6_I2S_IS_ENABLED 0x10 - -#define S6_I2S_NUM_LINES 4 - -#define S6_I2S_SIF_PORT0 0x0000000 -#define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */ - -static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val) -{ - writel(val, dev->scbbase + reg); -} - -static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg) -{ - return readl(dev->scbbase + reg); -} - -static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg, - u32 mask, u32 val) -{ - val ^= s6_i2s_read_reg(dev, reg) & ~mask; - s6_i2s_write_reg(dev, reg, val); -} - -static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel) -{ - int i, j, cur, prev; - - /* - * Wait for WCLK to toggle 5 times before enabling the channel - * s6000 Family Datasheet 3.6.4: - * "At least two cycles of WS must occur between commands - * to disable or enable the interface" - */ - j = 0; - prev = ~S6_I2S_CUR_WS; - for (i = 1000000; --i && j < 6; ) { - cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel)) - & S6_I2S_CUR_WS; - if (prev != cur) { - prev = cur; - j++; - } - } - if (j < 6) - printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n"); - - s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF); -} - -static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel) -{ - s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF); -} - -static void s6000_i2s_start(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - int channel; - - channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - dev->channel_out : dev->channel_in; - - s6000_i2s_start_channel(dev, channel); -} - -static void s6000_i2s_stop(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - int channel; - - channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - dev->channel_out : dev->channel_in; - - s6000_i2s_stop_channel(dev, channel); -} - -static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - int after) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after) - s6000_i2s_start(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!after) - s6000_i2s_stop(substream); - } - return 0; -} - -static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev) -{ - unsigned int pending; - pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW); - pending &= S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN; - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending); - - return pending; -} - -static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai) -{ - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - unsigned int errors; - unsigned int ret; - - errors = s6000_i2s_int_sources(dev); - if (likely(!errors)) - return 0; - - ret = 0; - if (errors & S6_I2S_INT_ALIGNMENT) - printk(KERN_ERR "s6000-i2s: WCLK misaligned\n"); - if (errors & S6_I2S_INT_UNDERRUN) - ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK; - if (errors & S6_I2S_INT_OVERRUN) - ret |= 1 << SNDRV_PCM_STREAM_CAPTURE; - return ret; -} - -static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev) -{ - int channel; - int n = 50; - for (channel = 0; channel < 2; channel++) { - while (--n >= 0) { - int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel)); - if ((v & S6_I2S_IS_ENABLED) - || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY))) - break; - udelay(20); - } - } - if (n < 0) - printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces"); -} - -static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - u32 w; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - w = S6_I2S_SCK_IN | S6_I2S_WS_IN; - break; - case SND_SOC_DAIFMT_CBS_CFM: - w = S6_I2S_SCK_OUT | S6_I2S_WS_IN; - break; - case SND_SOC_DAIFMT_CBM_CFS: - w = S6_I2S_SCK_IN | S6_I2S_WS_OUT; - break; - case SND_SOC_DAIFMT_CBS_CFS: - w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - w |= S6_I2S_LEFT_FIRST; - break; - case SND_SOC_DAIFMT_NB_IF: - w |= S6_I2S_RIGHT_FIRST; - break; - default: - return -EINVAL; - } - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0), - S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1), - S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); - - return 0; -} - -static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) -{ - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2) - return -EINVAL; - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id), - S6_I2S_DIV_MASK, div / 2 - 1); - return 0; -} - -static int s6000_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - int interf; - u32 w = 0; - - if (dev->wide) - interf = 0; - else { - w |= (((params_channels(params) - 2) / 2) - << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK; - interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ? dev->channel_out : dev->channel_in; - } - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT; - break; - case SNDRV_PCM_FORMAT_S32_LE: - w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT; - break; - default: - printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n", - params_format(params)); - return -EINVAL; - } - - if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf)) - & S6_I2S_IS_ENABLED) { - printk(KERN_ERR "s6000-i2s: interface already enabled\n"); - return -EBUSY; - } - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf), - S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK, - w); - - return 0; -} - -static int s6000_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - struct s6000_snd_platform_data *pdata = dai->dev->platform_data; - - if (!pdata) - return -EINVAL; - - dai->capture_dma_data = &dev->dma_params; - dai->playback_dma_data = &dev->dma_params; - - dev->wide = pdata->wide; - dev->channel_in = pdata->channel_in; - dev->channel_out = pdata->channel_out; - dev->lines_in = pdata->lines_in; - dev->lines_out = pdata->lines_out; - - s6_i2s_write_reg(dev, S6_I2S_MODE, - dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL); - - if (dev->wide) { - int i; - - if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES) - return -EINVAL; - - dev->channel_in = 0; - dev->channel_out = 1; - dai->driver->capture.channels_min = 2 * dev->lines_in; - dai->driver->capture.channels_max = dai->driver->capture.channels_min; - dai->driver->playback.channels_min = 2 * dev->lines_out; - dai->driver->playback.channels_max = dai->driver->playback.channels_min; - - for (i = 0; i < dev->lines_out; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT); - - for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), - S6_I2S_UNUSED); - - for (; i < S6_I2S_NUM_LINES; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN); - } else { - unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED}; - - if (dev->lines_in > 1 || dev->lines_out > 1) - return -EINVAL; - - dai->driver->capture.channels_min = 2 * dev->lines_in; - dai->driver->capture.channels_max = 8 * dev->lines_in; - dai->driver->playback.channels_min = 2 * dev->lines_out; - dai->driver->playback.channels_max = 8 * dev->lines_out; - - if (dev->lines_in) - cfg[dev->channel_in] = S6_I2S_IN; - if (dev->lines_out) - cfg[dev->channel_out] = S6_I2S_OUT; - - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]); - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]); - } - - if (dev->lines_out) { - if (dev->lines_in) { - if (!dev->dma_params.dma_out) - return -ENODEV; - } else { - dev->dma_params.dma_out = dev->dma_params.dma_in; - dev->dma_params.dma_in = 0; - } - } - dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ? - S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); - dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ? - S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); - dev->dma_params.same_rate = pdata->same_rate | pdata->wide; - return 0; -} - -#define S6000_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS -#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static const struct snd_soc_dai_ops s6000_i2s_dai_ops = { - .set_fmt = s6000_i2s_set_dai_fmt, - .set_clkdiv = s6000_i2s_set_clkdiv, - .hw_params = s6000_i2s_hw_params, -}; - -static struct snd_soc_dai_driver s6000_i2s_dai = { - .probe = s6000_i2s_dai_probe, - .playback = { - .channels_min = 2, - .channels_max = 8, - .formats = S6000_I2S_FORMATS, - .rates = S6000_I2S_RATES, - .rate_min = 0, - .rate_max = 1562500, - }, - .capture = { - .channels_min = 2, - .channels_max = 8, - .formats = S6000_I2S_FORMATS, - .rates = S6000_I2S_RATES, - .rate_min = 0, - .rate_max = 1562500, - }, - .ops = &s6000_i2s_dai_ops, -}; - -static const struct snd_soc_component_driver s6000_i2s_component = { - .name = "s6000-i2s", -}; - -static int s6000_i2s_probe(struct platform_device *pdev) -{ - struct s6000_i2s_dev *dev; - struct resource *scbmem, *sifmem, *region, *dma1, *dma2; - u8 __iomem *mmio; - int ret; - - scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!scbmem) { - dev_err(&pdev->dev, "no mem resource?\n"); - ret = -ENODEV; - goto err_release_none; - } - - region = request_mem_region(scbmem->start, resource_size(scbmem), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S SCB region already claimed\n"); - ret = -EBUSY; - goto err_release_none; - } - - mmio = ioremap(scbmem->start, resource_size(scbmem)); - if (!mmio) { - dev_err(&pdev->dev, "can't ioremap SCB region\n"); - ret = -ENOMEM; - goto err_release_scb; - } - - sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!sifmem) { - dev_err(&pdev->dev, "no second mem resource?\n"); - ret = -ENODEV; - goto err_release_map; - } - - region = request_mem_region(sifmem->start, resource_size(sifmem), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S SIF region already claimed\n"); - ret = -EBUSY; - goto err_release_map; - } - - dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dma1) { - dev_err(&pdev->dev, "no dma resource?\n"); - ret = -ENODEV; - goto err_release_sif; - } - - region = request_mem_region(dma1->start, resource_size(dma1), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S DMA region already claimed\n"); - ret = -EBUSY; - goto err_release_sif; - } - - dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (dma2) { - region = request_mem_region(dma2->start, resource_size(dma2), - pdev->name); - if (!region) { - dev_err(&pdev->dev, - "I2S DMA region already claimed\n"); - ret = -EBUSY; - goto err_release_dma1; - } - } - - dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL); - if (!dev) { - ret = -ENOMEM; - goto err_release_dma2; - } - dev_set_drvdata(&pdev->dev, dev); - - dev->sifbase = sifmem->start; - dev->scbbase = mmio; - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, - S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN); - - s6000_i2s_stop_channel(dev, 0); - s6000_i2s_stop_channel(dev, 1); - s6000_i2s_wait_disabled(dev); - - dev->dma_params.check_xrun = s6000_i2s_check_xrun; - dev->dma_params.trigger = s6000_i2s_trigger; - dev->dma_params.dma_in = dma1->start; - dev->dma_params.dma_out = dma2 ? dma2->start : 0; - dev->dma_params.irq = platform_get_irq(pdev, 0); - if (dev->dma_params.irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - ret = -ENODEV; - goto err_release_dev; - } - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, - S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN); - - ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component, - &s6000_i2s_dai, 1); - if (ret) - goto err_release_dev; - - return 0; - -err_release_dev: - kfree(dev); -err_release_dma2: - if (dma2) - release_mem_region(dma2->start, resource_size(dma2)); -err_release_dma1: - release_mem_region(dma1->start, resource_size(dma1)); -err_release_sif: - release_mem_region(sifmem->start, resource_size(sifmem)); -err_release_map: - iounmap(mmio); -err_release_scb: - release_mem_region(scbmem->start, resource_size(scbmem)); -err_release_none: - return ret; -} - -static int s6000_i2s_remove(struct platform_device *pdev) -{ - struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - struct resource *region; - void __iomem *mmio = dev->scbbase; - - snd_soc_unregister_component(&pdev->dev); - - s6000_i2s_stop_channel(dev, 0); - s6000_i2s_stop_channel(dev, 1); - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); - kfree(dev); - - region = platform_get_resource(pdev, IORESOURCE_DMA, 0); - release_mem_region(region->start, resource_size(region)); - - region = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (region) - release_mem_region(region->start, resource_size(region)); - - region = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(region->start, resource_size(region)); - - iounmap(mmio); - region = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_mem_region(region->start, resource_size(region)); - - return 0; -} - -static struct platform_driver s6000_i2s_driver = { - .probe = s6000_i2s_probe, - .remove = s6000_i2s_remove, - .driver = { - .name = "s6000-i2s", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(s6000_i2s_driver); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h deleted file mode 100644 index 86aa1921c89e3b..00000000000000 --- a/sound/soc/s6000/s6000-i2s.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ALSA SoC I2S Audio Layer for the Stretch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _S6000_I2S_H -#define _S6000_I2S_H - -struct s6000_snd_platform_data { - int lines_in; - int lines_out; - int channel_in; - int channel_out; - int wide; - int same_rate; -}; -#endif diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c deleted file mode 100644 index fb8461e1b1f666..00000000000000 --- a/sound/soc/s6000/s6000-pcm.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * ALSA PCM interface for the Stetch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "s6000-pcm.h" - -#define S6_PCM_PREALLOCATE_SIZE (96 * 1024) -#define S6_PCM_PREALLOCATE_MAX (2048 * 1024) - -static struct snd_pcm_hardware s6000_pcm_hardware = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX), - .buffer_bytes_max = 0x7ffffff0, - .period_bytes_min = 16, - .period_bytes_max = 0xfffff0, - .periods_min = 2, - .periods_max = 1024, /* no limit */ - .fifo_size = 0, -}; - -struct s6000_runtime_data { - spinlock_t lock; - int period; /* current DMA period */ -}; - -static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - int channel; - unsigned int period_size; - unsigned int dma_offset; - dma_addr_t dma_pos; - dma_addr_t src, dst; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - period_size = snd_pcm_lib_period_bytes(substream); - dma_offset = prtd->period * period_size; - dma_pos = runtime->dma_addr + dma_offset; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - src = dma_pos; - dst = par->sif_out; - channel = par->dma_out; - } else { - src = par->sif_in; - dst = dma_pos; - channel = par->dma_in; - } - - if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel))) - return; - - if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) { - printk(KERN_ERR "s6000-pcm: fifo full\n"); - return; - } - - if (WARN_ON(period_size & 15)) - return; - s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel), - src, dst, period_size); - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static irqreturn_t s6000_pcm_irq(int irq, void *data) -{ - struct snd_pcm *pcm = data; - struct snd_soc_pcm_runtime *runtime = pcm->private_data; - struct s6000_runtime_data *prtd; - unsigned int has_xrun; - int i, ret = IRQ_NONE; - - for (i = 0; i < 2; ++i) { - struct snd_pcm_substream *substream = pcm->streams[i].substream; - struct s6000_pcm_dma_params *params = - snd_soc_dai_get_dma_data(runtime->cpu_dai, substream); - u32 channel; - unsigned int pending; - - if (substream == SNDRV_PCM_STREAM_PLAYBACK) - channel = params->dma_out; - else - channel = params->dma_in; - - has_xrun = params->check_xrun(runtime->cpu_dai); - - if (!channel) - continue; - - if (unlikely(has_xrun & (1 << i)) && - substream->runtime && - snd_pcm_running(substream)) { - dev_dbg(pcm->dev, "xrun\n"); - snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(substream); - ret = IRQ_HANDLED; - } - - pending = s6dmac_int_sources(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel)); - - if (pending & 1) { - ret = IRQ_HANDLED; - if (likely(substream->runtime && - snd_pcm_running(substream))) { - snd_pcm_period_elapsed(substream); - dev_dbg(pcm->dev, "period elapsed %x %x\n", - s6dmac_cur_src(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel)), - s6dmac_cur_dst(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel))); - prtd = substream->runtime->private_data; - spin_lock(&prtd->lock); - s6000_pcm_enqueue_dma(substream); - spin_unlock(&prtd->lock); - } - } - - if (unlikely(pending & ~7)) { - if (pending & (1 << 3)) - printk(KERN_WARNING - "s6000-pcm: DMA %x Underflow\n", - channel); - if (pending & (1 << 4)) - printk(KERN_WARNING - "s6000-pcm: DMA %x Overflow\n", - channel); - if (pending & 0x1e0) - printk(KERN_WARNING - "s6000-pcm: DMA %x Master Error " - "(mask %x)\n", - channel, pending >> 5); - - } - } - - return ret; -} - -static int s6000_pcm_start(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - unsigned long flags; - int srcinc; - u32 dma; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - spin_lock_irqsave(&prtd->lock, flags); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - srcinc = 1; - dma = par->dma_out; - } else { - srcinc = 0; - dma = par->dma_in; - } - s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma), - 1 /* priority 1 (0 is max) */, - 0 /* peripheral requests w/o xfer length mode */, - srcinc /* source address increment */, - srcinc^1 /* destination address increment */, - 0 /* chunksize 0 (skip impossible on this dma) */, - 0 /* source skip after chunk (impossible) */, - 0 /* destination skip after chunk (impossible) */, - 4 /* 16 byte burst size */, - -1 /* don't conserve bandwidth */, - 0 /* low watermark irq descriptor threshold */, - 0 /* disable hardware timestamps */, - 1 /* enable channel */); - - s6000_pcm_enqueue_dma(substream); - s6000_pcm_enqueue_dma(substream); - - spin_unlock_irqrestore(&prtd->lock, flags); - - return 0; -} - -static int s6000_pcm_stop(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - unsigned long flags; - u32 channel; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - channel = par->dma_out; - else - channel = par->dma_in; - - s6dmac_set_terminal_count(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel), 0); - - spin_lock_irqsave(&prtd->lock, flags); - - s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel)); - - spin_unlock_irqrestore(&prtd->lock, flags); - - return 0; -} - -static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - int ret; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - ret = par->trigger(substream, cmd, 0); - if (ret < 0) - return ret; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = s6000_pcm_start(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = s6000_pcm_stop(substream); - break; - default: - ret = -EINVAL; - } - if (ret < 0) - return ret; - - return par->trigger(substream, cmd, 1); -} - -static int s6000_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; - - return 0; -} - -static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - unsigned long flags; - unsigned int offset; - dma_addr_t count; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - spin_lock_irqsave(&prtd->lock, flags); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out), - DMA_INDEX_CHNL(par->dma_out)); - else - count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in), - DMA_INDEX_CHNL(par->dma_in)); - - count -= runtime->dma_addr; - - spin_unlock_irqrestore(&prtd->lock, flags); - - offset = bytes_to_frames(runtime, count); - if (unlikely(offset >= runtime->buffer_size)) - offset = 0; - - return offset; -} - -static int s6000_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd; - int ret; - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware); - - ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); - if (ret < 0) - return ret; - ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); - if (ret < 0) - return ret; - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - - if (par->same_rate) { - int rate; - spin_lock(&par->lock); /* needed? */ - rate = par->rate; - spin_unlock(&par->lock); - if (rate != -1) { - ret = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_RATE, - rate, rate); - if (ret < 0) - return ret; - } - } - - prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - - runtime->private_data = prtd; - - return 0; -} - -static int s6000_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - - kfree(prtd); - - return 0; -} - -static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par; - int ret; - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n"); - return ret; - } - - par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - if (par->same_rate) { - spin_lock(&par->lock); - if (par->rate == -1 || - !(par->in_use & ~(1 << substream->stream))) { - par->rate = params_rate(hw_params); - par->in_use |= 1 << substream->stream; - } else if (params_rate(hw_params) != par->rate) { - snd_pcm_lib_free_pages(substream); - par->in_use &= ~(1 << substream->stream); - ret = -EBUSY; - } - spin_unlock(&par->lock); - } - return ret; -} - -static int s6000_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = - snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); - - spin_lock(&par->lock); - par->in_use &= ~(1 << substream->stream); - if (!par->in_use) - par->rate = -1; - spin_unlock(&par->lock); - - return snd_pcm_lib_free_pages(substream); -} - -static struct snd_pcm_ops s6000_pcm_ops = { - .open = s6000_pcm_open, - .close = s6000_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = s6000_pcm_hw_params, - .hw_free = s6000_pcm_hw_free, - .trigger = s6000_pcm_trigger, - .prepare = s6000_pcm_prepare, - .pointer = s6000_pcm_pointer, -}; - -static void s6000_pcm_free(struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *runtime = pcm->private_data; - struct s6000_pcm_dma_params *params = - snd_soc_dai_get_dma_data(runtime->cpu_dai, - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); - - free_irq(params->irq, pcm); - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime) -{ - struct snd_card *card = runtime->card->snd_card; - struct snd_pcm *pcm = runtime->pcm; - struct s6000_pcm_dma_params *params; - int res; - - params = snd_soc_dai_get_dma_data(runtime->cpu_dai, - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); - - res = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); - if (res) - return res; - - if (params->dma_in) { - s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in), - DMA_INDEX_CHNL(params->dma_in)); - s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in), - DMA_INDEX_CHNL(params->dma_in)); - } - - if (params->dma_out) { - s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out), - DMA_INDEX_CHNL(params->dma_out)); - s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out), - DMA_INDEX_CHNL(params->dma_out)); - } - - res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED, - "s6000-audio", pcm); - if (res) { - printk(KERN_ERR "s6000-pcm couldn't get IRQ\n"); - return res; - } - - res = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - card->dev, - S6_PCM_PREALLOCATE_SIZE, - S6_PCM_PREALLOCATE_MAX); - if (res) - printk(KERN_WARNING "s6000-pcm: preallocation failed\n"); - - spin_lock_init(¶ms->lock); - params->in_use = 0; - params->rate = -1; - return 0; -} - -static struct snd_soc_platform_driver s6000_soc_platform = { - .ops = &s6000_pcm_ops, - .pcm_new = s6000_pcm_new, - .pcm_free = s6000_pcm_free, -}; - -static int s6000_soc_platform_probe(struct platform_device *pdev) -{ - return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform); -} - -static int s6000_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static struct platform_driver s6000_pcm_driver = { - .driver = { - .name = "s6000-pcm-audio", - .owner = THIS_MODULE, - }, - - .probe = s6000_soc_platform_probe, - .remove = s6000_soc_platform_remove, -}; - -module_platform_driver(s6000_pcm_driver); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h deleted file mode 100644 index 09d9b883e58b08..00000000000000 --- a/sound/soc/s6000/s6000-pcm.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * ALSA PCM interface for the Stretch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _S6000_PCM_H -#define _S6000_PCM_H - -struct snd_soc_dai; -struct snd_pcm_substream; - -struct s6000_pcm_dma_params { - unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai); - int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after); - dma_addr_t sif_in; - dma_addr_t sif_out; - u32 dma_in; - u32 dma_out; - int irq; - int same_rate; - - spinlock_t lock; - int in_use; - int rate; -}; - -#endif diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c deleted file mode 100644 index 3510c01f8a6a6c..00000000000000 --- a/sound/soc/s6000/s6105-ipcam.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * ASoC driver for Stretch s6105 IP camera platform - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "s6000-pcm.h" -#include "s6000-i2s.h" - -#define S6105_CAM_CODEC_CLOCK 12288000 - -static int s6105_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_NB_NF); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK, - SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops s6105_ops = { - .hw_params = s6105_hw_params, -}; - -/* s6105 machine dapm widgets */ -static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { - SND_SOC_DAPM_LINE("Audio Out Differential", NULL), - SND_SOC_DAPM_LINE("Audio Out Stereo", NULL), - SND_SOC_DAPM_LINE("Audio In", NULL), -}; - -/* s6105 machine audio_mapnections to the codec pins */ -static const struct snd_soc_dapm_route audio_map[] = { - /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */ - {"Audio Out Differential", NULL, "HPLOUT"}, - {"Audio Out Differential", NULL, "HPLCOM"}, - {"Audio Out Stereo", NULL, "HPLOUT"}, - {"Audio Out Stereo", NULL, "HPROUT"}, - - /* Audio In connected to LINE1L, LINE1R */ - {"LINE1L", NULL, "Audio In"}, - {"LINE1R", NULL, "Audio In"}, -}; - -static int output_type_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item) { - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT"); - } else { - strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM"); - } - return 0; -} - -static int output_type_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = kcontrol->private_value; - return 0; -} - -static int output_type_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = kcontrol->private_data; - struct snd_soc_dapm_context *dapm = &card->dapm; - unsigned int val = (ucontrol->value.enumerated.item[0] != 0); - char *differential = "Audio Out Differential"; - char *stereo = "Audio Out Stereo"; - - if (kcontrol->private_value == val) - return 0; - kcontrol->private_value = val; - snd_soc_dapm_disable_pin(dapm, val ? differential : stereo); - snd_soc_dapm_sync(dapm); - snd_soc_dapm_enable_pin(dapm, val ? stereo : differential); - snd_soc_dapm_sync(dapm); - - return 1; -} - -static const struct snd_kcontrol_new audio_out_mux = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Output Mux", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = output_type_info, - .get = output_type_get, - .put = output_type_put, - .private_value = 1 /* default to stereo */ -}; - -/* Logic for a aic3x as connected on the s6105 ip camera ref design */ -static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - - /* must correspond to audio_out_mux.private_value initializer */ - snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential"); - - snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card)); - - return 0; -} - -/* s6105 digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link s6105_dai = { - .name = "TLV320AIC31", - .stream_name = "AIC31", - .cpu_dai_name = "s6000-i2s", - .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "s6000-pcm-audio", - .codec_name = "tlv320aic3x-codec.0-001a", - .init = s6105_aic3x_init, - .ops = &s6105_ops, -}; - -/* s6105 audio machine driver */ -static struct snd_soc_card snd_soc_card_s6105 = { - .name = "Stretch IP Camera", - .owner = THIS_MODULE, - .dai_link = &s6105_dai, - .num_links = 1, - - .dapm_widgets = aic3x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .fully_routed = true, -}; - -static struct s6000_snd_platform_data s6105_snd_data __initdata = { - .wide = 0, - .channel_in = 0, - .channel_out = 1, - .lines_in = 1, - .lines_out = 1, - .same_rate = 1, -}; - -static struct platform_device *s6105_snd_device; - -/* temporary i2c device creation until this can be moved into the machine - * support file. -*/ -static struct i2c_board_info i2c_device[] = { - { I2C_BOARD_INFO("tlv320aic33", 0x18), } -}; - -static int __init s6105_init(void) -{ - int ret; - - i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device)); - - s6105_snd_device = platform_device_alloc("soc-audio", -1); - if (!s6105_snd_device) - return -ENOMEM; - - platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105); - platform_device_add_data(s6105_snd_device, &s6105_snd_data, - sizeof(s6105_snd_data)); - - ret = platform_device_add(s6105_snd_device); - if (ret) - platform_device_put(s6105_snd_device); - - return ret; -} - -static void __exit s6105_exit(void) -{ - platform_device_unregister(s6105_snd_device); -} - -module_init(s6105_init); -module_exit(s6105_exit); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver"); -MODULE_LICENSE("GPL"); From 98fb8fd2522b637f8aaf1719f2dfd308f7191450 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 20 Oct 2014 10:54:36 +0200 Subject: [PATCH 396/889] mac80211: minstrels: fix buffer overflow in HT debugfs rc_stats ATM an HT rc_stats line is 106 chars. Times 8(MCS_GROUP_RATES)*3(SS)*2(GI)*2(BW) + CCK(4), i.e. x100, this is well above the current 8192 - sizeof(*ms) currently allocated. Fix this by squeezing the output as follows (not that we're short on memory but this also improves readability and range, the new format adds one more digit to *ok/*cum and ok/cum): - Before (HT) (106 ch): type rate throughput ewma prob this prob retry this succ/attempt success attempts CCK/LP 5.5M 0.0 0.0 0.0 0 0( 0) 0 0 HT20/LGI ABCDP MCS0 0.0 0.0 0.0 1 0( 0) 0 0 - After (75 ch): type rate tpt eprob *prob ret *ok(*cum) ok( cum) CCK/LP 5.5M 0.0 0.0 0.0 0 0( 0) 0( 0) HT20/LGI ABCDP MCS0 0.0 0.0 0.0 1 0( 0) 0( 0) - Align non-HT format Before (non-HT) (83 ch): rate throughput ewma prob this prob this succ/attempt success attempts ABCDP 6 0.0 0.0 0.0 0( 0) 0 0 54 0.0 0.0 0.0 0( 0) 0 0 - After (61 ch): rate tpt eprob *prob *ok(*cum) ok( cum) ABCDP 1 0.0 0.0 0.0 0( 0) 0( 0) 54 0.0 0.0 0.0 0( 0) 0( 0) *This also adds dynamic checks for overflow, lowers the size of the non-HT request (allowing > 30 entries) and replaces the buddy-rounded allocations (s/sizeof(*ms) + 8192/8192). Signed-off-by: Karl Beldan Acked-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_debugfs.c | 12 +++++++----- net/mac80211/rc80211_minstrel_ht_debugfs.c | 13 ++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index edde723f9f009e..2acab1bcaa4b37 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -62,14 +62,14 @@ minstrel_stats_open(struct inode *inode, struct file *file) unsigned int i, tp, prob, eprob; char *p; - ms = kmalloc(sizeof(*ms) + 4096, GFP_KERNEL); + ms = kmalloc(2048, GFP_KERNEL); if (!ms) return -ENOMEM; file->private_data = ms; p = ms->buf; - p += sprintf(p, "rate throughput ewma prob this prob " - "this succ/attempt success attempts\n"); + p += sprintf(p, "rate tpt eprob *prob" + " *ok(*cum) ok( cum)\n"); for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate_stats *mrs = &mi->r[i].stats; @@ -86,8 +86,8 @@ minstrel_stats_open(struct inode *inode, struct file *file) prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); eprob = MINSTREL_TRUNC(mrs->probability * 1000); - p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " - " %3u(%3u) %8llu %8llu\n", + p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u" + " %4u(%4u) %9llu(%9llu)\n", tp / 10, tp % 10, eprob / 10, eprob % 10, prob / 10, prob % 10, @@ -102,6 +102,8 @@ minstrel_stats_open(struct inode *inode, struct file *file) mi->sample_packets); ms->len = p - ms->buf; + WARN_ON(ms->len + sizeof(*ms) > 2048); + return 0; } diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index a72ad46f2a04b6..d537bec9375463 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -63,8 +63,8 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) prob = MINSTREL_TRUNC(mr->cur_prob * 1000); eprob = MINSTREL_TRUNC(mr->probability * 1000); - p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " - "%3u %3u(%3u) %8llu %8llu\n", + p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u " + "%3u %4u(%4u) %9llu(%9llu)\n", tp / 10, tp % 10, eprob / 10, eprob % 10, prob / 10, prob % 10, @@ -96,14 +96,15 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) return ret; } - ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL); + ms = kmalloc(8192, GFP_KERNEL); if (!ms) return -ENOMEM; file->private_data = ms; p = ms->buf; - p += sprintf(p, "type rate throughput ewma prob " - "this prob retry this succ/attempt success attempts\n"); + p += sprintf(p, "type rate tpt eprob *prob " + "ret *ok(*cum) ok( cum)\n"); + p = minstrel_ht_stats_dump(mi, max_mcs, p); for (i = 0; i < max_mcs; i++) @@ -118,6 +119,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); ms->len = p - ms->buf; + WARN_ON(ms->len + sizeof(*ms) > 8192); + return nonseekable_open(inode, file); } From 62d3644784ac66ad54fa0e88f828c9619f91f3b6 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 20 Oct 2014 22:45:27 +0800 Subject: [PATCH 397/889] x86: ACPI: Do not translate GSI number if IOAPIC is disabled When IOAPIC is disabled, acpi_gsi_to_irq() should return gsi directly instead of calling mp_map_gsi_to_irq() to translate gsi to IRQ by IOAPIC. It fixes https://bugzilla.kernel.org/show_bug.cgi?id=84381. This regression was introduced with commit 6b9fb7082409 "x86, ACPI, irq: Consolidate algorithm of mapping (ioapic, pin) to IRQ number" Reported-and-Tested-by: Thomas Richter Signed-off-by: Jiang Liu Cc: Tony Luck Cc: Thomas Richter Cc: rui.zhang@intel.com Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: # 3.17 Link: http://lkml.kernel.org/r/1413816327-12850-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index b436fc735aa455..d5c887216fb303 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -604,14 +604,18 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) { - int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); + int irq; - if (irq >= 0) { + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { + *irqp = gsi; + } else { + irq = mp_map_gsi_to_irq(gsi, + IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); + if (irq < 0) + return -1; *irqp = irq; - return 0; } - - return -1; + return 0; } EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); From 7d3d4cdfd96db924c10e891b81327c708c58b9f2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 20 Oct 2014 13:49:16 +0200 Subject: [PATCH 398/889] net: gso: use feature flag argument in all protocol gso handlers skb_gso_segment() has a 'features' argument representing offload features available to the output path. A few handlers, e.g. GRE, instead re-fetch the features of skb->dev and use those instead of the provided ones when handing encapsulation/tunnels. Depending on dev->hw_enc_features of the output device skb_gso_segment() can then return NULL even when the caller has disabled all GSO feature bits, as segmentation of inner header thinks device will take care of segmentation. This e.g. affects the tbf scheduler, which will silently drop GRE-encap GSO skbs that did not fit the remaining token quota as the segmentation does not work when device supports corresponding hw offload capabilities. Cc: Pravin B Shelar Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- net/ipv4/gre_offload.c | 2 +- net/ipv4/udp_offload.c | 2 +- net/ipv6/ip6_offload.c | 2 +- net/mpls/mpls_gso.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 92db7a69f2b9d1..8b7fe5b0390685 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1246,7 +1246,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, encap = SKB_GSO_CB(skb)->encap_level > 0; if (encap) - features = skb->dev->hw_enc_features & netif_skb_features(skb); + features &= skb->dev->hw_enc_features; SKB_GSO_CB(skb)->encap_level += ihl; skb_reset_transport_header(skb); diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index ccda09628de7e7..f6e345c0bc2394 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -68,7 +68,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, skb->mac_len = skb_inner_network_offset(skb); /* segment inner packet. */ - enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); + enc_features = skb->dev->hw_enc_features & features; segs = skb_mac_gso_segment(skb, enc_features); if (IS_ERR_OR_NULL(segs)) { skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len); diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 507310ef4b5681..6480cea7aa53a6 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -58,7 +58,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, skb->encap_hdr_csum = 1; /* segment inner packet. */ - enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); + enc_features = skb->dev->hw_enc_features & features; segs = gso_inner_segment(skb, enc_features); if (IS_ERR_OR_NULL(segs)) { skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 91014d32488ded..a071563a7e6e9c 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -90,7 +90,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, encap = SKB_GSO_CB(skb)->encap_level > 0; if (encap) - features = skb->dev->hw_enc_features & netif_skb_features(skb); + features &= skb->dev->hw_enc_features; SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h); ipv6h = ipv6_hdr(skb); diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index e28ed2ef5b0650..f0f5309a2d7262 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c @@ -48,7 +48,7 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, __skb_push(skb, skb->mac_len); /* Segment inner packet. */ - mpls_features = skb->dev->mpls_features & netif_skb_features(skb); + mpls_features = skb->dev->mpls_features & features; segs = skb_mac_gso_segment(skb, mpls_features); From 3b62499b76f6bcbef0dadf3040f02d9c1487301c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 20 Oct 2014 13:49:17 +0200 Subject: [PATCH 399/889] net: make skb_gso_segment error handling more robust skb_gso_segment has three possible return values: 1. a pointer to the first segmented skb 2. an errno value (IS_ERR()) 3. NULL. This can happen when GSO is used for header verification. However, several callers currently test IS_ERR instead of IS_ERR_OR_NULL and would oops when NULL is returned. Note that these call sites should never actually see such a NULL return value; all callers mask out the GSO bits in the feature argument. However, there have been issues with some protocol handlers erronously not respecting the specified feature mask in some cases. It is preferable to get 'have to turn off hw offloading, else slow' reports rather than 'kernel crashes'. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 2 +- net/netfilter/nfnetlink_queue_core.c | 2 +- net/openvswitch/datapath.c | 2 ++ net/xfrm/xfrm_output.c | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 88e5ef2c7f511f..bc6471d4abcdaa 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -231,7 +231,7 @@ static int ip_finish_output_gso(struct sk_buff *skb) */ features = netif_skb_features(skb); segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); - if (IS_ERR(segs)) { + if (IS_ERR_OR_NULL(segs)) { kfree_skb(skb); return -ENOMEM; } diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index a82077d9f59b2f..7c60ccd61a3e16 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -665,7 +665,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) * returned by nf_queue. For instance, callers rely on -ECANCELED to * mean 'ignore this hook'. */ - if (IS_ERR(segs)) + if (IS_ERR_OR_NULL(segs)) goto out_err; queued = 0; err = 0; diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 2e31d9e7f4dc4c..e6d7255183eba3 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -324,6 +324,8 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, segs = __skb_gso_segment(skb, NETIF_F_SG, false); if (IS_ERR(segs)) return PTR_ERR(segs); + if (segs == NULL) + return -EINVAL; /* Queue all of the segments. */ skb = segs; diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 499d6c18a8ce43..7c532856b39829 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -157,6 +157,8 @@ static int xfrm_output_gso(struct sk_buff *skb) kfree_skb(skb); if (IS_ERR(segs)) return PTR_ERR(segs); + if (segs == NULL) + return -EINVAL; do { struct sk_buff *nskb = segs->next; From 32fc3e6f02604e0c5f85ac71c73950ff9df91c11 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 20 Oct 2014 13:49:18 +0200 Subject: [PATCH 400/889] net: core: handle encapsulation offloads when computing segment lengths if ->encapsulation is set we have to use inner_tcp_hdrlen and add the size of the inner network headers too. This is 'mostly harmless'; tbf might send skb that is slightly over quota or drop skb even if it would have fit. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/core/skbuff.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 61059a05ec95f1..c16615bfb61edd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4070,15 +4070,22 @@ EXPORT_SYMBOL_GPL(skb_scrub_packet); unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) { const struct skb_shared_info *shinfo = skb_shinfo(skb); + unsigned int thlen = 0; - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) - return tcp_hdrlen(skb) + shinfo->gso_size; + if (skb->encapsulation) { + thlen = skb_inner_transport_header(skb) - + skb_transport_header(skb); + if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) + thlen += inner_tcp_hdrlen(skb); + } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { + thlen = tcp_hdrlen(skb); + } /* UFO sets gso_size to the size of the fragmentation * payload, i.e. the size of the L4 (UDP) header is already * accounted for. */ - return shinfo->gso_size; + return thlen + shinfo->gso_size; } EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); From 510fd591e46dd4d7d16e90a8228d7b6fdb236c27 Mon Sep 17 00:00:00 2001 From: Olivier Gay Date: Sat, 18 Oct 2014 01:53:39 +0200 Subject: [PATCH 401/889] HID: add keyboard input assist hid usages Add keyboard input assist controls usages from approved hid usage table request HUTTR42: http://www.usb.org/developers/hidpage/HUTRR42c.pdf Signed-off-by: Olivier Gay Acked-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 6 ++++++ drivers/hid/hid-input.c | 7 +++++++ include/uapi/linux/input.h | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 84c3cb15ccdd45..8bf61d295ffd7e 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -946,6 +946,12 @@ static const char *keys[KEY_MAX + 1] = { [KEY_BRIGHTNESS_MIN] = "BrightnessMin", [KEY_BRIGHTNESS_MAX] = "BrightnessMax", [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", + [KEY_KBDINPUTASSIST_PREV] = "KbdInputAssistPrev", + [KEY_KBDINPUTASSIST_NEXT] = "KbdInputAssistNext", + [KEY_KBDINPUTASSIST_PREVGROUP] = "KbdInputAssistPrevGroup", + [KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup", + [KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept", + [KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel", }; static const char *relatives[REL_MAX + 1] = { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 2df7fddbd119bc..56c6c30f2c7df3 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -862,6 +862,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; case 0x28c: map_key_clear(KEY_SEND); break; + case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break; + case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break; + case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break; + case 0x2ca: map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); break; + case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); break; + case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL); break; + default: goto ignore; } break; diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 1874ebe9ac1e50..a1d7e931ab72cd 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -739,6 +739,13 @@ struct input_keymap_entry { #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ +#define KEY_KBDINPUTASSIST_PREV 0x260 +#define KEY_KBDINPUTASSIST_NEXT 0x261 +#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 +#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 +#define KEY_KBDINPUTASSIST_ACCEPT 0x264 +#define KEY_KBDINPUTASSIST_CANCEL 0x265 + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 From a5305ec41bee82400283382e0310a33d4e48d5ea Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Tue, 7 Oct 2014 21:18:14 +0200 Subject: [PATCH 402/889] ARM: pxa: fix hang on startup with DEBUG_LL The commit 2111667b4677 ("ARM: pxa: call debug_ll_io_init for earlyprintk") triggers in the current kernel the attached backtrace on PXA/tosa early in the boot time when DEBUG_LL is enabled. It is due to overlap between uart virtual memory defined in DEBUG_UART_VIRT and mapped by debug_ll_io_init() and peripheral bus mapped by pxa_map_io at the same address, 0xf2100000. As hinted by Arnd, map early virtual memory for low level debug on address 0xf6200000, even if that means 2 virtual mappings will give access to the pxa internal UARTs (FFUART, BTUART, STUART, ...). ------------[ cut here ]------------ kernel BUG at /home/lumag/linux/mm/vmalloc.c:1143! Internal error: Oops - BUG: 0 [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.17.0-00032-g8e0d202-dirty #23 task: c062a5a8 ti: c0620000 task.ti: c0620000 PC is at vm_area_add_early+0x54/0x84 LR is at add_static_vm_early+0xc/0x60 pc : [] lr : [] psr: 800001d3 sp : c0621f04 ip : c03efa74 fp : c03edf84 r10: c0637e98 r9 : 40000001 r8 : c03da57c r7 : c3ffcfb0 r6 : 00000000 r5 : c3ffcfb0 r4 : 02000000 r3 : c3ffcfd8 r2 : f2100000 r1 : f4000000 r0 : c3ffcfb0 Flags: Nzcv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel Control: 00007977 Table: a0004000 DAC: 00000017 Process swapper (pid: 0, stack limit = 0xc06201c8) Stack: (0xc0621f04 to 0xc0622000) 1f00: c3ffcfd8 40000001 c3ffcfd8 c03ee08c c03da570 c03db90c c0637d24 1f20: 00000000 c03ec7cc c066e654 a0700000 000a0700 c03db914 c03db90c c03daf84 1f40: 00000000 000a0000 c0000000 c03ec7cc 000a0700 c0700000 ffff1000 000a3fff 1f60: 00001000 00000007 00000000 c03ec7cc c0008000 c03ed748 c0621fd4 c03d5d18 1f80: 69052d00 a03ec48c 00000000 c03d8ad0 0000006c 00007977 c036c6e8 00000001 1fa0: c0621fd4 c03ed744 c0628000 a0004000 69052d00 a03ec48c 00000000 c03d68d4 1fc0: 00000000 00000000 00000000 00000000 00000000 c03ed748 c0649894 c062801c 1fe0: c03ed744 c062b2f0 a0004000 69052d00 a03ec48c a0008040 00000000 00000000 [] (vm_area_add_early) from [] (add_static_vm_early+0xc/0x60) [] (add_static_vm_early) from [] (iotable_init.part.6+0xa8/0xb4) [] (iotable_init.part.6) from [] (pxa25x_map_io+0x8/0x24) [] (pxa25x_map_io) from [] (paging_init+0x744/0x8d8) [] (paging_init) from [] (setup_arch+0x354/0x608) [] (setup_arch) from [] (start_kernel+0xa8/0x3dc) [] (start_kernel) from [] (0xa0008040) Code: e5904008 e0811004 e1520001 2a000005 (e7f001f2) ---[ end trace f24b6c88ae00fa9a ]--- Kernel panic - not syncing: Attempted to kill the idle task! ---[ end Kernel panic - not syncing: Attempted to kill the idle task! Cc: Reported-by: Dmitry Eremin-Solenikov Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann --- arch/arm/Kconfig.debug | 2 +- arch/arm/mach-pxa/include/mach/addr-map.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736e7..d8f6a2ec3d4e06 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1187,7 +1187,7 @@ config DEBUG_UART_VIRT default 0xf1c28000 if DEBUG_SUNXI_UART0 default 0xf1c28400 if DEBUG_SUNXI_UART1 default 0xf1f02800 if DEBUG_SUNXI_R_UART - default 0xf2100000 if DEBUG_PXA_UART1 + default 0xf6200000 if DEBUG_PXA_UART1 default 0xf4090000 if ARCH_LPC32XX default 0xf4200000 if ARCH_GEMINI default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ diff --git a/arch/arm/mach-pxa/include/mach/addr-map.h b/arch/arm/mach-pxa/include/mach/addr-map.h index bbf9df37ad4b6c..d28fe291233a55 100644 --- a/arch/arm/mach-pxa/include/mach/addr-map.h +++ b/arch/arm/mach-pxa/include/mach/addr-map.h @@ -38,6 +38,11 @@ #define DMEMC_VIRT IOMEM(0xf6100000) #define DMEMC_SIZE 0x00100000 +/* + * Reserved space for low level debug virtual addresses within + * 0xf6200000..0xf6201000 + */ + /* * Internal Memory Controller (PXA27x and later) */ From f330c0df210b83e3173350a7d379c8652833cf5c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 17 Sep 2014 16:28:38 -0500 Subject: [PATCH 403/889] usb: dwc3: trace: don't dereference pointers The way trace works is that it won't decode strings until we read the actual trace. Because of that, we can't make assumptions of pointers still being valid at the time we read the trace. In order to avoid that, just copy all fields from every struct pointer we need for our traces. Ths patch fixes the following bug: [ 2940.039229] Unable to handle kernel paging request at virtual address 814efa9e [ 2940.046904] pgd = ec3dc000 [ 2940.049737] [814efa9e] *pgd=00000000 [ 2940.053552] Internal error: Oops: 5 [#1] SMP ARM [ 2940.058379] Modules linked in: usb_f_acm u_serial g_serial usb_f_uac2 libcomposite configfs xhci_hcd dwc3 udc_core matrix_keypad dwc3_omap lis3lv02d_i2c lis3lv02d input_polldev [last unloaded: g_audio] [ 2940.077238] CPU: 0 PID: 3020 Comm: tail Tainted: G W 3.17.0-rc5-dirty #1097 [ 2940.085596] task: ed1b1040 ti: ed07c000 task.ti: ed07c000 [ 2940.091258] PC is at strnlen+0x18/0x68 [ 2940.095177] LR is at 0xfffffffe [ 2940.098454] pc : [] lr : [] psr: a0000013 [ 2940.098454] sp : ed07ddb0 ip : ed07ddc0 fp : ed07ddbc [ 2940.110445] r10: c070ff70 r9 : ed07de70 r8 : 00000000 [ 2940.115906] r7 : 814efa9e r6 : ffffffff r5 : ed4b6087 r4 : ed4b50c7 [ 2940.122726] r3 : 00000000 r2 : 814efa9e r1 : ffffffff r0 : 814efa9e [ 2940.129546] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 2940.137000] Control: 10c5387d Table: ac3dc059 DAC: 00000015 [ 2940.143006] Process tail (pid: 3020, stack limit = 0xed07c248) [ 2940.149098] Stack: (0xed07ddb0 to 0xed07e000) [ 2940.153660] dda0: ed07dde4 ed07ddc0 c0359628 c0356dec [ 2940.162203] ddc0: 00000000 ed4b50c7 bf03ae9c ed4b6087 bf03ae9e 00000002 ed07de3c ed07dde8 [ 2940.170740] dde0: c035ab50 c0359600 ffffffff ffffffff ff0a0000 ffffffff ed07de30 ed4b5088 [ 2940.179275] de00: ed4b50c7 00000fc0 ff0a0004 ffffffff ed4b5088 ed4b5088 00000000 00001000 [ 2940.187810] de20: 00001008 00000fc0 ed4b5088 00000000 ed07de68 ed07de40 c00f1e64 c035a9c4 [ 2940.196341] de40: bf03dae0 ed07de70 ed4b4000 ec25b280 ed4b4000 ec25b280 bf03dae0 ed07de9c [ 2940.204886] de60: ed07de78 bf033324 c00f1e0c bf03ae9c 814efa9e ed428bc0 814eca3e 00000000 [ 2940.213428] de80: 814eba3e ed4b4000 03bd1201 c0c34790 ed07ded4 ed07dea0 c00edc0c bf0332d0 [ 2940.221994] dea0: 000002c7 ed07df10 ed07decc ed07deb8 ed4b4000 0000209c ec278ac0 00000000 [ 2940.230536] dec0: 00002000 ec0db340 ed07def4 ed07ded8 c00ee7ec c00eda90 c00ee7b0 ec278ac0 [ 2940.239075] dee0: ed4b4000 000002d5 ed07df44 ed07def8 c018b8d0 c00ee7bc c0166d3c ec278af0 [ 2940.247621] df00: 0001f090 ed07df78 000002c7 00000000 000002c8 00000000 00000000 ec0db340 [ 2940.256173] df20: 0001f090 ed07df78 ec0db340 00002000 0001f090 00000000 ed07df74 ed07df48 [ 2940.264729] df40: c0166e98 c018b5f4 00000001 c018535c 000168c1 00000000 ec0db340 ec0db340 [ 2940.273284] df60: 00002000 0001f090 ed07dfa4 ed07df78 c01675c4 c0166e0c 000168c1 00000000 [ 2940.281829] df80: 00002000 0000000a 0001f090 00000003 c000f064 ed07c000 00000000 ed07dfa8 [ 2940.290365] dfa0: c000ede0 c0167584 00002000 0000000a 00000003 0001f090 00002000 00000000 [ 2940.298909] dfc0: 00002000 0000000a 0001f090 00000003 7fffe000 0001e1e0 00002004 0000002f [ 2940.307445] dfe0: 00000000 beed38ec 000104c8 b6e6397c 40000010 00000003 00000000 00000000 [ 2940.315992] [] (strnlen) from [] (string.isra.8+0x34/0xe8) [ 2940.323534] [] (string.isra.8) from [] (vsnprintf+0x198/0x3fc) [ 2940.331461] [] (vsnprintf) from [] (trace_seq_printf+0x68/0x94) [ 2940.339494] [] (trace_seq_printf) from [] (ftrace_raw_output_dwc3_log_request+0x60/0x78 [dwc3]) [ 2940.350424] [] (ftrace_raw_output_dwc3_log_request [dwc3]) from [] (print_trace_line+0x188/0x418) [ 2940.361507] [] (print_trace_line) from [] (s_show+0x3c/0x12c) [ 2940.369330] [] (s_show) from [] (seq_read+0x2e8/0x4a0) [ 2940.376519] [] (seq_read) from [] (vfs_read+0x98/0x158) [ 2940.383796] [] (vfs_read) from [] (SyS_read+0x4c/0xa0) [ 2940.390981] [] (SyS_read) from [] (ret_fast_syscall+0x0/0x48) [ 2940.398792] Code: e24cb004 e3510000 e241e001 0a000011 (e5d01000) [ 2940.406980] ---[ end trace d8b38370fbb531f3 ]--- Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/trace.h | 53 ++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 78aff1da089a7b..60b0f41eafc40b 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -73,15 +73,23 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, TP_PROTO(struct usb_ctrlrequest *ctrl), TP_ARGS(ctrl), TP_STRUCT__entry( - __field(struct usb_ctrlrequest *, ctrl) + __field(__u8, bRequestType) + __field(__u8, bRequest) + __field(__le16, wValue) + __field(__le16, wIndex) + __field(__le16, wLength) ), TP_fast_assign( - __entry->ctrl = ctrl; + __entry->bRequestType = ctrl->bRequestType; + __entry->bRequest = ctrl->bRequest; + __entry->wValue = ctrl->wValue; + __entry->wIndex = ctrl->wIndex; + __entry->wLength = ctrl->wLength; ), TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d", - __entry->ctrl->bRequestType, __entry->ctrl->bRequest, - le16_to_cpu(__entry->ctrl->wValue), le16_to_cpu(__entry->ctrl->wIndex), - le16_to_cpu(__entry->ctrl->wLength) + __entry->bRequestType, __entry->bRequest, + le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex), + le16_to_cpu(__entry->wLength) ) ); @@ -94,15 +102,22 @@ DECLARE_EVENT_CLASS(dwc3_log_request, TP_PROTO(struct dwc3_request *req), TP_ARGS(req), TP_STRUCT__entry( + __dynamic_array(char, name, DWC3_MSG_MAX) __field(struct dwc3_request *, req) + __field(unsigned, actual) + __field(unsigned, length) + __field(int, status) ), TP_fast_assign( + snprintf(__get_str(name), DWC3_MSG_MAX, "%s", req->dep->name); __entry->req = req; + __entry->actual = req->request.actual; + __entry->length = req->request.length; + __entry->status = req->request.status; ), TP_printk("%s: req %p length %u/%u ==> %d", - __entry->req->dep->name, __entry->req, - __entry->req->request.actual, __entry->req->request.length, - __entry->req->request.status + __get_str(name), __entry->req, __entry->actual, __entry->length, + __entry->status ) ); @@ -158,17 +173,17 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, struct dwc3_gadget_ep_cmd_params *params), TP_ARGS(dep, cmd, params), TP_STRUCT__entry( - __field(struct dwc3_ep *, dep) + __dynamic_array(char, name, DWC3_MSG_MAX) __field(unsigned int, cmd) __field(struct dwc3_gadget_ep_cmd_params *, params) ), TP_fast_assign( - __entry->dep = dep; + snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name); __entry->cmd = cmd; __entry->params = params; ), TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x\n", - __entry->dep->name, dwc3_gadget_ep_cmd_string(__entry->cmd), + __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd), __entry->cmd, __entry->params->param0, __entry->params->param1, __entry->params->param2 ) @@ -184,16 +199,24 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb), TP_ARGS(dep, trb), TP_STRUCT__entry( - __field(struct dwc3_ep *, dep) + __dynamic_array(char, name, DWC3_MSG_MAX) __field(struct dwc3_trb *, trb) + __field(u32, bpl) + __field(u32, bph) + __field(u32, size) + __field(u32, ctrl) ), TP_fast_assign( - __entry->dep = dep; + snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name); __entry->trb = trb; + __entry->bpl = trb->bpl; + __entry->bph = trb->bph; + __entry->size = trb->size; + __entry->ctrl = trb->ctrl; ), TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x\n", - __entry->dep->name, __entry->trb, __entry->trb->bph, - __entry->trb->bpl, __entry->trb->size, __entry->trb->ctrl + __get_str(name), __entry->trb, __entry->bph, __entry->bpl, + __entry->size, __entry->ctrl ) ); From 06c1055f12881cadb2716328548a43a0d626d758 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Sep 2014 10:46:46 -0500 Subject: [PATCH 404/889] usb: dwc3: ep0: hold our lock in dwc3_gadget_ep0_set_halt dwc3_gadget_ep0_set_halt() will be called without locks held in some cases, so we must hold the lock on our own. While at that, also add a version without locks to be called in certain conditions. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 16 +++++++++++++++- drivers/usb/dwc3/gadget.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index b35938777ddeaa..36f61582b5b557 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -271,7 +271,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dwc3_ep0_out_start(dwc); } -int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) { struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; @@ -281,6 +281,20 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) return 0; } +int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dwc->lock, flags); + ret = __dwc3_gadget_ep0_set_halt(ep, value); + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + void dwc3_ep0_out_start(struct dwc3 *dwc) { int ret; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 178ad898220658..f889008faa6336 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -82,6 +82,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); From 7cc58eee8dbfa1ab3742893108d209889100a7b7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Sep 2014 10:48:26 -0500 Subject: [PATCH 405/889] usb: dwc3: gadget: move isoc endpoint check to unlocked set_halt __dwc3_gadget_ep_set_halt() is the function which handles the actual halt feature. In order to cope with some extra cleanup comming as a follow-up patch let's move the isochronous endpoint check there too. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3818b26bfc05ab..fd92f63050913f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1208,6 +1208,11 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) struct dwc3 *dwc = dep->dwc; int ret; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); + return -EINVAL; + } + memset(¶ms, 0x00, sizeof(params)); if (value) { @@ -1241,15 +1246,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) int ret; spin_lock_irqsave(&dwc->lock, flags); - - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); - ret = -EINVAL; - goto out; - } - ret = __dwc3_gadget_ep_set_halt(dep, value); -out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; From 036e29e63e68ca4dee112d47f2d671da41c5129a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Sep 2014 10:50:14 -0500 Subject: [PATCH 406/889] usb: dwc3: gadget: hold the lock through set_wedge()'s life Instead of releasing the lock and calling locked versions of our set_halt() methods, let's hold the lock all the way through and call unlocked versions of those functions. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fd92f63050913f..b98295efd91279 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1257,15 +1257,18 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); dep->flags |= DWC3_EP_WEDGE; - spin_unlock_irqrestore(&dwc->lock, flags); if (dep->number == 0 || dep->number == 1) - return dwc3_gadget_ep0_set_halt(ep, 1); + ret = __dwc3_gadget_ep0_set_halt(ep, 1); else - return dwc3_gadget_ep_set_halt(ep, 1); + ret = __dwc3_gadget_ep_set_halt(dep, 1); + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; } /* -------------------------------------------------------------------------- */ From bd3d26df2f63f8801050f9b12e366570acb2c877 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Sep 2014 14:19:52 -0500 Subject: [PATCH 407/889] usb: dwc3: gadget: fix set_halt() bug with pending transfers According to our Gadget Framework API documentation, ->set_halt() *must* return -EAGAIN if we have pending transfers (on either direction) or FIFO isn't empty (on TX endpoints). Fix this bug so that the mass storage gadget can be used without stall=0 parameter. This patch should be backported to all kernels since v3.2. Cc: # v3.2+ Suggested-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 4 ++-- drivers/usb/dwc3/gadget.c | 16 ++++++++++++---- drivers/usb/dwc3/gadget.h | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 36f61582b5b557..ae6b5753fe670e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -256,7 +256,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) /* stall is always issued on EP0 */ dep = dwc->eps[0]; - __dwc3_gadget_ep_set_halt(dep, 1); + __dwc3_gadget_ep_set_halt(dep, 1, false); dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; @@ -480,7 +480,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, return -EINVAL; if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) break; - ret = __dwc3_gadget_ep_set_halt(dep, set); + ret = __dwc3_gadget_ep_set_halt(dep, set, true); if (ret) return -EINVAL; break; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b98295efd91279..f6d1dbafa2988b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -581,7 +581,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) /* make sure HW endpoint isn't stalled */ if (dep->flags & DWC3_EP_STALL) - __dwc3_gadget_ep_set_halt(dep, 0); + __dwc3_gadget_ep_set_halt(dep, 0, false); reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); @@ -1202,7 +1202,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, return ret; } -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) { struct dwc3_gadget_ep_cmd_params params; struct dwc3 *dwc = dep->dwc; @@ -1216,6 +1216,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) memset(¶ms, 0x00, sizeof(params)); if (value) { + if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || + (!list_empty(&dep->req_queued) || + !list_empty(&dep->request_list)))) { + dev_dbg(dwc->dev, "%s: pending request, cannot halt\n", + dep->name); + return -EAGAIN; + } + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_SETSTALL, ¶ms); if (ret) @@ -1246,7 +1254,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) int ret; spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_set_halt(dep, value); + ret = __dwc3_gadget_ep_set_halt(dep, value, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1265,7 +1273,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) if (dep->number == 0 || dep->number == 1) ret = __dwc3_gadget_ep0_set_halt(ep, 1); else - ret = __dwc3_gadget_ep_set_halt(dep, 1); + ret = __dwc3_gadget_ep_set_halt(dep, 1, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index f889008faa6336..18ae3eaa8b6fe4 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -86,7 +86,7 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW From f4089b803e6b79b79b24f3682dc7036de0468a6f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 09:19:59 -0500 Subject: [PATCH 408/889] usb: gadget: function: uvc: conditionally dequeue We shouldn't try to dequeue a NULL pointer. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/uvc_video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index c3e1f27dbbefd2..9cb86bc1a9a544 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -352,7 +352,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable) if (!enable) { for (i = 0; i < UVC_NUM_REQUESTS; ++i) - usb_ep_dequeue(video->ep, video->req[i]); + if (video->req[i]) + usb_ep_dequeue(video->ep, video->req[i]); uvc_video_free_requests(video); uvcg_queue_enable(&video->queue, 0); From fd44a69a1642bb3243803e9fd3d1dcadf3cd58b6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 09:20:35 -0500 Subject: [PATCH 409/889] usb: gadget: function: uvc: make sure to balance ep enable/disable If a set_alt() to the same alternate setting that's already selected is received, functions are required to reset the interface state, this means we must disable all endpoints and reenable them again. This is also documented on our kdoc for struct usb_function * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may * initialize usb_ep.driver data at this time (when it is used). * Note that setting an interface to its current altsetting resets * interface state, and that all interfaces have a disabled state. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index e126439e4b6509..e00e8b79390af1 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -286,11 +286,12 @@ static int uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) { struct uvc_device *uvc = to_uvc(f); + struct usb_composite_dev *cdev = f->config->cdev; struct v4l2_event v4l2_event; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; int ret; - INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); + INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); if (interface == uvc->control_intf) { if (alt) @@ -299,7 +300,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (uvc->state == UVC_STATE_DISCONNECTED) { memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_CONNECT; - uvc_event->speed = f->config->cdev->gadget->speed; + uvc_event->speed = cdev->gadget->speed; v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; @@ -321,8 +322,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (uvc->state != UVC_STATE_STREAMING) return 0; - if (uvc->video.ep) + if (uvc->video.ep) { usb_ep_disable(uvc->video.ep); + uvc->video.ep->driver_data = NULL; + } memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMOFF; @@ -335,14 +338,22 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (uvc->state != UVC_STATE_CONNECTED) return 0; - if (uvc->video.ep) { - ret = config_ep_by_speed(f->config->cdev->gadget, - &(uvc->func), uvc->video.ep); - if (ret) - return ret; - usb_ep_enable(uvc->video.ep); + if (!uvc->video.ep) + return -EINVAL; + + if (uvc->video.ep->driver_data) { + INFO(cdev, "reset UVC\n"); + usb_ep_disable(uvc->video.ep); + uvc->video.ep->driver_data = NULL; } + ret = config_ep_by_speed(f->config->cdev->gadget, + &(uvc->func), uvc->video.ep); + if (ret) + return ret; + usb_ep_enable(uvc->video.ep); + uvc->video.ep->driver_data = uvc; + memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event_queue(uvc->vdev, &v4l2_event); From a5e794a8650f6ee35aa07d1223496deca5313f5d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 11:13:26 -0500 Subject: [PATCH 410/889] usb: gadget: function: uvc: return correct alt-setting If our alternate setting has been selected, we must return that on a subsequent Get Interface request even if we're not streaming. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index e00e8b79390af1..4138ad5adb7735 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -279,7 +279,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface) else if (interface != uvc->streaming_intf) return -EINVAL; else - return uvc->state == UVC_STATE_STREAMING ? 1 : 0; + return uvc->video.ep->driver_data ? 1 : 0; } static int From c476d8d6ffd2661dc196439c3ad492d334705d66 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 13:35:54 -0500 Subject: [PATCH 411/889] usb: gadget: function: acm: make f_acm pass USB20CV Chapter9 During Halt Endpoint Test, our interrupt endpoint will be disabled, which will clear out ep->desc to NULL. Unless we call config_ep_by_speed() again, we will not be able to enable this endpoint which will make us fail that test. Fixes: f9c56cd (usb: gadget: Clear usb_endpoint_descriptor inside the struct usb_ep on disable) Cc: # v3.4+ Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_acm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 6da4685490ef76..aad8165e98ef84 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -433,12 +433,12 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) dev_vdbg(&cdev->gadget->dev, "reset acm control interface %d\n", intf); usb_ep_disable(acm->notify); - } else { - dev_vdbg(&cdev->gadget->dev, - "init acm ctrl interface %d\n", intf); + } + + if (!acm->notify->desc) if (config_ep_by_speed(cdev->gadget, f, acm->notify)) return -EINVAL; - } + usb_ep_enable(acm->notify); acm->notify->driver_data = acm; From 0f3fd21698709c378d2b9846b0b732b2d0a3a217 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 13:41:04 -0500 Subject: [PATCH 412/889] usb: gadget: function: uvc: manage our video control endpoint just like any other endpoint, we must enable/disable our video control endpoint based on calls to our ->set_alt() method. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 4138ad5adb7735..413a09f366c4e7 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -297,6 +297,19 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (alt) return -EINVAL; + if (uvc->control_ep->driver_data) { + INFO(cdev, "reset UVC Control\n"); + usb_ep_disable(uvc->control_ep); + uvc->control_ep->driver_data = NULL; + } + + if (!uvc->control_ep->desc) + if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep)) + return -EINVAL; + + usb_ep_enable(uvc->control_ep); + uvc->control_ep->driver_data = uvc; + if (uvc->state == UVC_STATE_DISCONNECTED) { memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_CONNECT; From 929a877180f2e04810ce7d2f599e57db6b1ae8d7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 13:43:20 -0500 Subject: [PATCH 413/889] usb: gadget: function: uvc: disable endpoints on ->disable() when our ->disable() method is called, we must make sure to teardown all our resources, including endpoints. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 413a09f366c4e7..945b3bd2ca98a4 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -390,6 +390,16 @@ uvc_function_disable(struct usb_function *f) v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_DISCONNECTED; + + if (uvc->video.ep->driver_data) { + usb_ep_disable(uvc->video.ep); + uvc->video.ep->driver_data = NULL; + } + + if (uvc->control_ep->driver_data) { + usb_ep_disable(uvc->control_ep); + uvc->control_ep->driver_data = NULL; + } } /* -------------------------------------------------------------------------- From 0a409a3ca0078f633d612c03afc88affa3a47496 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 14:18:14 -0500 Subject: [PATCH 414/889] usb: gadget: function: uac2: add wMaxPacketSize to ep desc Endpoint descriptors should pass wMaxPacketSize. Note that this also fixes USB20CV Other Speed Endpoint Descriptor Tests. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index a5a27a504d6709..fa511180c24150 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -772,6 +772,7 @@ struct usb_endpoint_descriptor fs_epout_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + .wMaxPacketSize = cpu_to_le16(1023), .bInterval = 1, }; @@ -780,6 +781,7 @@ struct usb_endpoint_descriptor hs_epout_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + .wMaxPacketSize = cpu_to_le16(1024), .bInterval = 4, }; @@ -847,6 +849,7 @@ struct usb_endpoint_descriptor fs_epin_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + .wMaxPacketSize = cpu_to_le16(1023), .bInterval = 1, }; @@ -855,6 +858,7 @@ struct usb_endpoint_descriptor hs_epin_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, + .wMaxPacketSize = cpu_to_le16(1024), .bInterval = 4, }; From 7fb43d63a9fbdf573e33b15e335340f5856fde3a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 14:23:41 -0500 Subject: [PATCH 415/889] usb: gadget: function: uac2: prevent double ep disable without this check, f_uac2 would try to disable the same endpoint twice. Fix that. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index fa511180c24150..1146f4d5f66de0 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -951,6 +951,9 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) struct snd_uac2_chip *uac2 = prm->uac2; int i; + if (!prm->ep_enabled) + return; + prm->ep_enabled = false; for (i = 0; i < USB_XFERS; i++) { From 7812438f11547620ad425741e39a9e14e2f7fd8a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 14:24:09 -0500 Subject: [PATCH 416/889] usb: gadget: function: uac2: add a release method devices are required to provide a release method. This patch fixes the following WARN(): [ 42.611159] ------------[ cut here ]------------ [ 42.616025] WARNING: CPU: 0 PID: 1453 at drivers/base/core.c:250 device_release+0x94/0xa0() [ 42.624820] Device 'snd_uac2.0' does not have a release() function, it is broken and must be fixed. [ 42.634328] Modules linked in: usb_f_uac2 g_audio(-) libcomposite configfs xhci_hcd snd_soc_davinci_mcasp snd_soc_edma snd_soc_tlv320aic3x snd_soc_omap snd_soc_evm snd_soc_core dwc3 snd_compress omapdrm snd_pcm_dmaengine snd_pcm snd_timer snd fb_sys_fops lis3lv02d_i2c matrix_keypad dwc3_omap lis3lv02d panel_dpi input_polldev soundcore [ 42.665687] CPU: 0 PID: 1453 Comm: modprobe Tainted: G D 3.17.0-rc6-00448-g9f3d0ec-dirty #188 [ 42.675756] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [ 42.683911] [] (show_stack) from [] (dump_stack+0x8c/0xa4) [ 42.691526] [] (dump_stack) from [] (warn_slowpath_common+0x7c/0xa0) [ 42.700004] [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x40/0x48) [ 42.709194] [] (warn_slowpath_fmt) from [] (device_release+0x94/0xa0) [ 42.717794] [] (device_release) from [] (kobject_cleanup+0x4c/0x7c) [ 42.726189] [] (kobject_cleanup) from [] (kobject_put+0x60/0x90) [ 42.734316] [] (kobject_put) from [] (put_device+0x24/0x28) [ 42.741995] [] (put_device) from [] (platform_device_unregister+0x2c/0x30) [ 42.751061] [] (platform_device_unregister) from [] (afunc_unbind+0x2c/0x68 [usb_f_uac2]) [ 42.761523] [] (afunc_unbind [usb_f_uac2]) from [] (remove_config.isra.8+0xe8/0x100 [libcomposite]) [ 42.772868] [] (remove_config.isra.8 [libcomposite]) from [] (__composite_unbind+0x48/0xb0 [libcomposite]) [ 42.784855] [] (__composite_unbind [libcomposite]) from [] (composite_unbind+0x1c/0x20 [libcomposite]) [ 42.796446] [] (composite_unbind [libcomposite]) from [] (usb_gadget_remove_driver+0x78/0xb0) [ 42.807224] [] (usb_gadget_remove_driver) from [] (usb_gadget_unregister_driver+0x74/0xb8) [ 42.817742] [] (usb_gadget_unregister_driver) from [] (usb_composite_unregister+0x1c/0x20 [libcomposite]) [ 42.829632] [] (usb_composite_unregister [libcomposite]) from [] (audio_driver_exit+0x14/0x1c [g_audio]) [ 42.841430] [] (audio_driver_exit [g_audio]) from [] (SyS_delete_module+0x120/0x1b0) [ 42.851415] [] (SyS_delete_module) from [] (ret_fast_syscall+0x0/0x48) [ 42.860075] ---[ end trace bb22e678d8d6db7b ]--- root@saruman:~# Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 1146f4d5f66de0..9296e598428c6e 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -512,6 +512,11 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } +static void snd_uac2_release(struct device *dev) +{ + dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); +} + static int alsa_uac2_init(struct audio_dev *agdev) { struct snd_uac2_chip *uac2 = &agdev->uac2; @@ -523,6 +528,7 @@ static int alsa_uac2_init(struct audio_dev *agdev) uac2->pdev.id = 0; uac2->pdev.name = uac2_name; + uac2->pdev.dev.release = snd_uac2_release; /* Register snd_uac2 driver */ err = platform_driver_register(&uac2->pdrv); From ca20b881888e2626c4477064cad78ea346a09412 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Sep 2014 15:18:20 -0500 Subject: [PATCH 417/889] usb: gadget: function: f_obex: fix Interface Descriptor Test On USB20CV's Interface Descriptor Test, a series of SetInterface/GetInterface requests are issued and gadget driver is required to always return correct alternate setting. In one step of the test, g_serial with f_obex was returning the wrong value (1 instead of 0). In order to fix this, we will now hold currently selected alternate setting inside our struct f_obex and just return that from our ->get_alt() implementation. Note that his also simplifies the code a bit. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_obex.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 5f40080c92ccfb..1a1a490415f49d 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -35,6 +35,7 @@ struct f_obex { struct gserial port; u8 ctrl_id; u8 data_id; + u8 cur_alt; u8 port_num; u8 can_activate; }; @@ -235,6 +236,8 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } else goto fail; + obex->cur_alt = alt; + return 0; fail: @@ -245,10 +248,7 @@ static int obex_get_alt(struct usb_function *f, unsigned intf) { struct f_obex *obex = func_to_obex(f); - if (intf == obex->ctrl_id) - return 0; - - return obex->port.in->driver_data ? 1 : 0; + return obex->cur_alt; } static void obex_disable(struct usb_function *f) From e35cd9fe30ff0743d86b20adcd00f6f523914ffe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Sep 2014 10:40:25 +0300 Subject: [PATCH 418/889] usb: dwc3: pci: Add PCI ID for Intel Braswell The device controller is the same but it has different PCI ID. Add this new ID to the driver's list of supported IDs. Signed-off-by: Alan Cox Signed-off-by: Mika Westerberg Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 436fb08c40b878..a36cf66302fbe5 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -30,6 +30,7 @@ #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e +#define PCI_DEVICE_ID_INTEL_BSW 0x22B7 struct dwc3_pci { struct device *dev; @@ -181,6 +182,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { } /* Terminating Entry */ From 661c299cb1905b7a7146626163ed63a3c081f880 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Sep 2014 11:43:20 -0500 Subject: [PATCH 419/889] usb: dwc3: ep0: return early on NULL requests if our list of requests is empty, return early. There's really nothing to be done in case our request list is empty anyway because the only situation where we our list is empty, is when we're transferring ZLPs. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index ae6b5753fe670e..a47cc1e97fae03 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -789,9 +789,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; - r = next_request(&ep0->request_list); - ur = &r->request; - trb = dwc->ep0_trb; status = DWC3_TRB_SIZE_TRBSTS(trb->size); @@ -804,6 +801,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, return; } + r = next_request(&ep0->request_list); + if (!r) + return; + + ur = &r->request; + length = trb->size & DWC3_TRB_SIZE_MASK; if (dwc->ep0_bounced) { From 05a632f73c68884e246363303d14abea8761066a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 21 Aug 2014 15:04:31 -0400 Subject: [PATCH 420/889] nfsd4: fix response size estimation for OP_SEQUENCE We added this new estimator function but forgot to hook it up. The effect is that NFSv4.1 (and greater) won't do zero-copy reads. The estimate was also wrong by 8 bytes. Fixes: ccae70a9ee41 "nfsd4: estimate sequence response size" Cc: stable@vger.kernel.org Reported-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index cdeb3cfd6f32b2..f4bd578bed5514 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1589,7 +1589,8 @@ static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op static inline u32 nfsd4_sequence_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) { - return NFS4_MAX_SESSIONID_LEN + 20; + return (op_encode_hdr_size + + XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) * sizeof(__be32); } static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) @@ -1893,6 +1894,7 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_func = (nfsd4op_func)nfsd4_sequence, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, .op_name = "OP_SEQUENCE", + .op_rsize_bop = (nfsd4op_rsize)nfsd4_sequence_rsize, }, [OP_DESTROY_CLIENTID] = { .op_func = (nfsd4op_func)nfsd4_destroy_clientid, From 86b255bdda9ffb8e57f8a4894c0fb728e84ac2f7 Mon Sep 17 00:00:00 2001 From: WANG Chao Date: Fri, 17 Oct 2014 16:47:26 +0800 Subject: [PATCH 421/889] Documentation/ABI/testing/sysfs-ibft: fix a typo Correct a sentence in Documentation/ABI/testing/sysfs-ibft. Signed-off-by: WANG Chao Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-ibft | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-ibft b/Documentation/ABI/testing/sysfs-ibft index c2b7d1154bec62..cac3930bdb04d9 100644 --- a/Documentation/ABI/testing/sysfs-ibft +++ b/Documentation/ABI/testing/sysfs-ibft @@ -20,4 +20,4 @@ Date: November 2007 Contact: Konrad Rzeszutek Description: The /sys/firmware/ibft/ethernetX directory will contain files that expose the iSCSI Boot Firmware Table NIC data. - This can this can the IP address, MAC, and gateway of the NIC. + Usually this contains the IP address, MAC, and gateway of the NIC. From efbd03a549fc067139311d3abbb04d867a218192 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 9 Oct 2014 20:24:07 +0200 Subject: [PATCH 422/889] Documentation: dt-bindings: Explain order in patch series When posting a patch series that includes both code implementing a Device Tree binding and its associated documentation, the DT docs should come in the series before the implementation. This not only avoids checkpatch.pl to complain about undocumented bindings but also makes the review process easier. Document this convention since it may not be obvious. Signed-off-by: Javier Martinez Canillas Acked-by: Mark Rutland Signed-off-by: Jonathan Corbet --- Documentation/devicetree/bindings/submitting-patches.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/submitting-patches.txt b/Documentation/devicetree/bindings/submitting-patches.txt index 042a0273b8bab8..b7ba01ad1426cf 100644 --- a/Documentation/devicetree/bindings/submitting-patches.txt +++ b/Documentation/devicetree/bindings/submitting-patches.txt @@ -12,6 +12,9 @@ I. For patch submitters devicetree@vger.kernel.org + 3) The Documentation/ portion of the patch should come in the series before + the code implementing the binding. + II. For kernel maintainers 1) If you aren't comfortable reviewing a given binding, reply to it and ask From 627ff3357260ef583375aeb14b9cab0e31b70c59 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Wed, 8 Oct 2014 15:49:24 -0400 Subject: [PATCH 423/889] Documentation: fix vdso_standalone_test_x86 on 32-bit vdso_standalone_test_x86 needs -lgcc_s to build succesfully on 32bit. Signed-off-by: Peter Foley [ Fixed missing separator issue reported by Paul Bolle ] Signed-off-by: Jonathan Corbet --- Documentation/vDSO/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/vDSO/Makefile b/Documentation/vDSO/Makefile index 2b99e57207c161..ee075c3d21248c 100644 --- a/Documentation/vDSO/Makefile +++ b/Documentation/vDSO/Makefile @@ -10,3 +10,6 @@ always := $(hostprogs-y) HOSTCFLAGS := -I$(objtree)/usr/include -std=gnu99 HOSTCFLAGS_vdso_standalone_test_x86.o := -fno-asynchronous-unwind-tables -fno-stack-protector HOSTLOADLIBES_vdso_standalone_test_x86 := -nostdlib +ifeq ($(CONFIG_X86_32),y) +HOSTLOADLIBES_vdso_standalone_test_x86 += -lgcc_s +endif From 84b32db2df95aaac6897b79679cbd740be11b84c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Oct 2014 22:42:42 +0100 Subject: [PATCH 424/889] ARM: fix some printk formats GCC 4.9 complains if we take the difference of two pointers, and it's printed with "%d". Fix this by using the proper flag - "t" for ptrdiff_t. Signed-off-by: Russell King --- arch/arm/mm/init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 92bba32d92304c..9481f85c56e6fd 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -559,10 +559,10 @@ void __init mem_init(void) #ifdef CONFIG_MODULES " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" #endif - " .text : 0x%p" " - 0x%p" " (%4d kB)\n" - " .init : 0x%p" " - 0x%p" " (%4d kB)\n" - " .data : 0x%p" " - 0x%p" " (%4d kB)\n" - " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", + " .text : 0x%p" " - 0x%p" " (%4td kB)\n" + " .init : 0x%p" " - 0x%p" " (%4td kB)\n" + " .data : 0x%p" " - 0x%p" " (%4td kB)\n" + " .bss : 0x%p" " - 0x%p" " (%4td kB)\n", MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + (PAGE_SIZE)), From 8f7a6fb5ed747f18280dd273059fdadeabfa10d3 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Sun, 19 Oct 2014 14:20:27 +0530 Subject: [PATCH 425/889] enic: fix possible deadlock in enic_stop/ enic_rfs_flw_tbl_free The following warning is shown when spinlock debug is enabled. This occurs when enic_flow_may_expire timer function is running and enic_stop is called on same CPU. Fix this by using spink_lock_bh(). ================================= [ INFO: inconsistent lock state ] 3.17.0-netnext-05504-g59f35b8 #268 Not tainted --------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. ifconfig/443 [HC0[0]:SC0[0]:HE1:SE1] takes: (&(&enic->rfs_h.lock)->rlock){+.?...}, at: enic_rfs_flw_tbl_free+0x34/0xd0 [enic] {IN-SOFTIRQ-W} state was registered at: [] __lock_acquire+0x83f/0x21c0 [] lock_acquire+0xa2/0xd0 [] _raw_spin_lock+0x3c/0x80 [] enic_flow_may_expire+0x25/0x130[enic] [] call_timer_fn+0x77/0x100 [] run_timer_softirq+0x1e3/0x270 [] __do_softirq+0x14e/0x280 [] irq_exit+0x8e/0xb0 [] smp_apic_timer_interrupt+0x3f/0x50 [] apic_timer_interrupt+0x72/0x80 [] default_idle+0x13/0x20 [] arch_cpu_idle+0xa/0x10 [] cpu_startup_entry+0x2c6/0x330 [] start_secondary+0x21d/0x290 irq event stamp: 2997 hardirqs last enabled at (2997): [] _raw_spin_unlock_irqrestore+0x65/0x90 hardirqs last disabled at (2996): [] _raw_spin_lock_irqsave+0x26/0x90 softirqs last enabled at (2968): [] dev_deactivate_many+0x213/0x260 softirqs last disabled at (2966): [] dev_deactivate_many+0x1f3/0x260 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&enic->rfs_h.lock)->rlock); lock(&(&enic->rfs_h.lock)->rlock); *** DEADLOCK *** Reported-by: Jan Stancek Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 69dfd3c9e5298a..0be6850be8a238 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -86,7 +86,7 @@ void enic_rfs_flw_tbl_free(struct enic *enic) int i; enic_rfs_timer_stop(enic); - spin_lock(&enic->rfs_h.lock); + spin_lock_bh(&enic->rfs_h.lock); enic->rfs_h.free = 0; for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { struct hlist_head *hhead; @@ -100,7 +100,7 @@ void enic_rfs_flw_tbl_free(struct enic *enic) kfree(n); } } - spin_unlock(&enic->rfs_h.lock); + spin_unlock_bh(&enic->rfs_h.lock); } struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id) @@ -128,7 +128,7 @@ void enic_flow_may_expire(unsigned long data) bool res; int j; - spin_lock(&enic->rfs_h.lock); + spin_lock_bh(&enic->rfs_h.lock); for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) { struct hlist_head *hhead; struct hlist_node *tmp; @@ -148,7 +148,7 @@ void enic_flow_may_expire(unsigned long data) } } } - spin_unlock(&enic->rfs_h.lock); + spin_unlock_bh(&enic->rfs_h.lock); mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); } @@ -183,7 +183,7 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, return -EPROTONOSUPPORT; tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK; - spin_lock(&enic->rfs_h.lock); + spin_lock_bh(&enic->rfs_h.lock); n = htbl_key_search(&enic->rfs_h.ht_head[tbl_idx], &keys); if (n) { /* entry already present */ @@ -277,7 +277,7 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } ret_unlock: - spin_unlock(&enic->rfs_h.lock); + spin_unlock_bh(&enic->rfs_h.lock); return res; } From a016d46d9c39f145e0bef96994f02712d88b2d0f Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Sun, 19 Oct 2014 14:20:28 +0530 Subject: [PATCH 426/889] enic: Do not call napi_disable when preemption is disabled. In enic_stop, we disable preemption using local_bh_disable(). We disable preemption to wait for busy_poll to finish. napi_disable should not be called here as it might sleep. Moving napi_disable() call out side of local_bh_disable. BUG: sleeping function called from invalid context at include/linux/netdevice.h:477 in_atomic(): 1, irqs_disabled(): 0, pid: 443, name: ifconfig INFO: lockdep is turned off. Preemption disabled at:[] enic_rfs_flw_tbl_free+0x34/0xd0 [enic] CPU: 31 PID: 443 Comm: ifconfig Not tainted 3.17.0-netnext-05504-g59f35b8 #268 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 ffff8800dac10000 ffff88020b8dfcb8 ffffffff8148a57c 0000000000000000 ffff88020b8dfcd0 ffffffff8107e253 ffff8800dac12a40 ffff88020b8dfd10 ffffffffa029305b ffff88020b8dfd48 ffff8800dac10000 ffff88020b8dfd48 Call Trace: [] dump_stack+0x4e/0x7a [] __might_sleep+0x123/0x1a0 [] enic_stop+0xdb/0x4d0 [enic] [] __dev_close_many+0x9d/0xf0 [] __dev_close+0x31/0x50 [] __dev_change_flags+0x98/0x160 [] dev_change_flags+0x24/0x60 [] devinet_ioctl+0x63d/0x710 [] ? might_fault+0x56/0xc0 [] inet_ioctl+0x65/0x90 [] sock_do_ioctl+0x20/0x50 [] sock_ioctl+0x20b/0x2e0 [] do_vfs_ioctl+0x2e0/0x500 [] ? sysret_check+0x22/0x5d [] ? __this_cpu_preempt_check+0x13/0x20 [] ? trace_hardirqs_on_caller+0x119/0x270 [] SyS_ioctl+0x3c/0x80 [] system_call_fastpath+0x1a/0x1f Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 929bfe70080ac0..180e53fa628fac 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1674,13 +1674,13 @@ static int enic_stop(struct net_device *netdev) enic_dev_disable(enic); - local_bh_disable(); for (i = 0; i < enic->rq_count; i++) { napi_disable(&enic->napi[i]); + local_bh_disable(); while (!enic_poll_lock_napi(&enic->rq[i])) mdelay(1); + local_bh_enable(); } - local_bh_enable(); netif_carrier_off(netdev); netif_tx_disable(netdev); From 805be85d5a56af702898c5f60f41b32336f51650 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 20 Oct 2014 14:44:25 +0800 Subject: [PATCH 427/889] tipc: fix a potential deadlock Locking dependency detected below possible unsafe locking scenario: CPU0 CPU1 T0: tipc_named_rcv() tipc_rcv() T1: [grab nametble write lock]* [grab node lock]* T2: tipc_update_nametbl() tipc_node_link_up() T3: tipc_nodesub_subscribe() tipc_nametbl_publish() T4: [grab node lock]* [grab nametble write lock]* The opposite order of holding nametbl write lock and node lock on above two different paths may result in a deadlock. If we move the the updating of the name table after link state named out of node lock, the reverse order of holding locks will be eliminated, and as a result, the deadlock risk. Signed-off-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/node.c | 46 ++++++++++++++++++++++++++++------------------ net/tipc/node.h | 7 ++++++- net/tipc/socket.c | 2 +- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 90cee4a6fce494..5781634e957d7b 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -219,11 +219,11 @@ void tipc_node_abort_sock_conns(struct list_head *conns) void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { struct tipc_link **active = &n_ptr->active_links[0]; - u32 addr = n_ptr->addr; n_ptr->working_links++; - tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE, - l_ptr->bearer_id, addr); + n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP; + n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; + pr_info("Established link <%s> on network plane %c\n", l_ptr->name, l_ptr->net_plane); @@ -284,10 +284,10 @@ static void node_select_active_links(struct tipc_node *n_ptr) void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { struct tipc_link **active; - u32 addr = n_ptr->addr; n_ptr->working_links--; - tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, l_ptr->bearer_id, addr); + n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN; + n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; if (!tipc_link_is_active(l_ptr)) { pr_info("Lost standby link <%s> on network plane %c\n", @@ -552,28 +552,30 @@ void tipc_node_unlock(struct tipc_node *node) LIST_HEAD(conn_sks); struct sk_buff_head waiting_sks; u32 addr = 0; - unsigned int flags = node->action_flags; + int flags = node->action_flags; + u32 link_id = 0; - if (likely(!node->action_flags)) { + if (likely(!flags)) { spin_unlock_bh(&node->lock); return; } + addr = node->addr; + link_id = node->link_id; __skb_queue_head_init(&waiting_sks); - if (node->action_flags & TIPC_WAKEUP_USERS) { + + if (flags & TIPC_WAKEUP_USERS) skb_queue_splice_init(&node->waiting_sks, &waiting_sks); - node->action_flags &= ~TIPC_WAKEUP_USERS; - } - if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { + + if (flags & TIPC_NOTIFY_NODE_DOWN) { list_replace_init(&node->nsub, &nsub_list); list_replace_init(&node->conn_sks, &conn_sks); - node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; } - if (node->action_flags & TIPC_NOTIFY_NODE_UP) { - node->action_flags &= ~TIPC_NOTIFY_NODE_UP; - addr = node->addr; - } - node->action_flags &= ~TIPC_WAKEUP_BCAST_USERS; + node->action_flags &= ~(TIPC_WAKEUP_USERS | TIPC_NOTIFY_NODE_DOWN | + TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_UP | + TIPC_NOTIFY_LINK_DOWN | + TIPC_WAKEUP_BCAST_USERS); + spin_unlock_bh(&node->lock); while (!skb_queue_empty(&waiting_sks)) @@ -588,6 +590,14 @@ void tipc_node_unlock(struct tipc_node *node) if (flags & TIPC_WAKEUP_BCAST_USERS) tipc_bclink_wakeup_users(); - if (addr) + if (flags & TIPC_NOTIFY_NODE_UP) tipc_named_node_up(addr); + + if (flags & TIPC_NOTIFY_LINK_UP) + tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, + TIPC_NODE_SCOPE, link_id, addr); + + if (flags & TIPC_NOTIFY_LINK_DOWN) + tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, + link_id, addr); } diff --git a/net/tipc/node.h b/net/tipc/node.h index 67513c3c852c41..04e91458bb29a1 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -53,6 +53,7 @@ * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down * TIPC_NOTIFY_NODE_DOWN: notify node is down * TIPC_NOTIFY_NODE_UP: notify node is up + * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type */ enum { TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1), @@ -60,7 +61,9 @@ enum { TIPC_NOTIFY_NODE_DOWN = (1 << 3), TIPC_NOTIFY_NODE_UP = (1 << 4), TIPC_WAKEUP_USERS = (1 << 5), - TIPC_WAKEUP_BCAST_USERS = (1 << 6) + TIPC_WAKEUP_BCAST_USERS = (1 << 6), + TIPC_NOTIFY_LINK_UP = (1 << 7), + TIPC_NOTIFY_LINK_DOWN = (1 << 8) }; /** @@ -100,6 +103,7 @@ struct tipc_node_bclink { * @working_links: number of working links to node (both active and standby) * @link_cnt: number of links to node * @signature: node instance identifier + * @link_id: local and remote bearer ids of changing link, if any * @nsub: list of "node down" subscriptions monitoring node * @rcu: rcu struct for tipc_node */ @@ -116,6 +120,7 @@ struct tipc_node { int link_cnt; int working_links; u32 signature; + u32 link_id; struct list_head nsub; struct sk_buff_head waiting_sks; struct list_head conn_sks; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 75275c5cf9291a..3043f10dc32804 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2673,7 +2673,7 @@ static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) case SIOCGETLINKNAME: if (copy_from_user(&lnr, argp, sizeof(lnr))) return -EFAULT; - if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer, + if (!tipc_node_get_linkname(lnr.bearer_id & 0xffff, lnr.peer, lnr.linkname, TIPC_MAX_LINK_NAME)) { if (copy_to_user(argp, &lnr, sizeof(lnr))) return -EFAULT; From 96fdf56454980cf32834787aab094f12ad5afc4b Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 20 Oct 2014 14:46:35 +0800 Subject: [PATCH 428/889] tipc: fix lockdep warning when intra-node messages are delivered When running tipcTC&tipcTS test suite, below lockdep unsafe locking scenario is reported: [ 1109.997854] [ 1109.997988] ================================= [ 1109.998290] [ INFO: inconsistent lock state ] [ 1109.998575] 3.17.0-rc1+ #113 Not tainted [ 1109.998762] --------------------------------- [ 1109.998762] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. [ 1109.998762] swapper/7/0 [HC0[0]:SC1[1]:HE1:SE0] takes: [ 1109.998762] (slock-AF_TIPC){+.?...}, at: [] tipc_sk_rcv+0x49/0x2b0 [tipc] [ 1109.998762] {SOFTIRQ-ON-W} state was registered at: [ 1109.998762] [] __lock_acquire+0x6a0/0x1d80 [ 1109.998762] [] lock_acquire+0x95/0x1e0 [ 1109.998762] [] _raw_spin_lock+0x3e/0x80 [ 1109.998762] [] tipc_sk_rcv+0x49/0x2b0 [tipc] [ 1109.998762] [] tipc_link_xmit+0xa8/0xc0 [tipc] [ 1109.998762] [] tipc_sendmsg+0x15f/0x550 [tipc] [ 1109.998762] [] tipc_connect+0x105/0x140 [tipc] [ 1109.998762] [] SYSC_connect+0xae/0xc0 [ 1109.998762] [] SyS_connect+0xe/0x10 [ 1109.998762] [] compat_SyS_socketcall+0xb8/0x200 [ 1109.998762] [] sysenter_dispatch+0x7/0x1f [ 1109.998762] irq event stamp: 241060 [ 1109.998762] hardirqs last enabled at (241060): [] __local_bh_enable_ip+0x6d/0xd0 [ 1109.998762] hardirqs last disabled at (241059): [] __local_bh_enable_ip+0x2f/0xd0 [ 1109.998762] softirqs last enabled at (241020): [] _local_bh_enable+0x22/0x50 [ 1109.998762] softirqs last disabled at (241021): [] irq_exit+0x96/0xc0 [ 1109.998762] [ 1109.998762] other info that might help us debug this: [ 1109.998762] Possible unsafe locking scenario: [ 1109.998762] [ 1109.998762] CPU0 [ 1109.998762] ---- [ 1109.998762] lock(slock-AF_TIPC); [ 1109.998762] [ 1109.998762] lock(slock-AF_TIPC); [ 1109.998762] [ 1109.998762] *** DEADLOCK *** [ 1109.998762] [ 1109.998762] 2 locks held by swapper/7/0: [ 1109.998762] #0: (rcu_read_lock){......}, at: [] __netif_receive_skb_core+0x69/0xb70 [ 1109.998762] #1: (rcu_read_lock){......}, at: [] tipc_l2_rcv_msg+0x40/0x260 [tipc] [ 1109.998762] [ 1109.998762] stack backtrace: [ 1109.998762] CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.17.0-rc1+ #113 [ 1109.998762] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 1109.998762] ffffffff82745830 ffff880016c03828 ffffffff81a209eb 0000000000000007 [ 1109.998762] ffff880017b3cac0 ffff880016c03888 ffffffff81a1c5ef 0000000000000001 [ 1109.998762] ffff880000000001 ffff880000000000 ffffffff81012d4f 0000000000000000 [ 1109.998762] Call Trace: [ 1109.998762] [] dump_stack+0x4e/0x68 [ 1109.998762] [] print_usage_bug+0x1f1/0x202 [ 1109.998762] [] ? save_stack_trace+0x2f/0x50 [ 1109.998762] [] mark_lock+0x28c/0x2f0 [ 1109.998762] [] ? print_irq_inversion_bug.part.46+0x1f0/0x1f0 [ 1109.998762] [] __lock_acquire+0x5ad/0x1d80 [ 1109.998762] [] ? trace_hardirqs_on+0xd/0x10 [ 1109.998762] [] ? sched_clock_cpu+0x98/0xc0 [ 1109.998762] [] ? local_clock+0x1b/0x30 [ 1109.998762] [] ? lock_release_holdtime.part.29+0x1c/0x1a0 [ 1109.998762] [] ? sched_clock_local+0x25/0x90 [ 1109.998762] [] ? tipc_sk_get+0x60/0x80 [tipc] [ 1109.998762] [] lock_acquire+0x95/0x1e0 [ 1109.998762] [] ? tipc_sk_rcv+0x49/0x2b0 [tipc] [ 1109.998762] [] ? trace_hardirqs_on_caller+0xa6/0x1c0 [ 1109.998762] [] _raw_spin_lock+0x3e/0x80 [ 1109.998762] [] ? tipc_sk_rcv+0x49/0x2b0 [tipc] [ 1109.998762] [] ? tipc_sk_get+0x60/0x80 [tipc] [ 1109.998762] [] tipc_sk_rcv+0x49/0x2b0 [tipc] [ 1109.998762] [] tipc_rcv+0x5ed/0x960 [tipc] [ 1109.998762] [] tipc_l2_rcv_msg+0xcc/0x260 [tipc] [ 1109.998762] [] ? tipc_l2_rcv_msg+0x40/0x260 [tipc] [ 1109.998762] [] __netif_receive_skb_core+0x5e5/0xb70 [ 1109.998762] [] ? __netif_receive_skb_core+0x69/0xb70 [ 1109.998762] [] ? dev_gro_receive+0x259/0x4e0 [ 1109.998762] [] __netif_receive_skb+0x26/0x70 [ 1109.998762] [] netif_receive_skb_internal+0x2d/0x1f0 [ 1109.998762] [] napi_gro_receive+0xd8/0x240 [ 1109.998762] [] e1000_clean_rx_irq+0x2c4/0x530 [ 1109.998762] [] e1000_clean+0x266/0x9c0 [ 1109.998762] [] ? local_clock+0x1b/0x30 [ 1109.998762] [] ? sched_clock_local+0x25/0x90 [ 1109.998762] [] net_rx_action+0x141/0x310 [ 1109.998762] [] ? handle_fasteoi_irq+0xe0/0x150 [ 1109.998762] [] __do_softirq+0x116/0x4d0 [ 1109.998762] [] irq_exit+0x96/0xc0 [ 1109.998762] [] do_IRQ+0x67/0x110 [ 1109.998762] [] common_interrupt+0x6f/0x6f [ 1109.998762] [] ? default_idle+0x37/0x250 [ 1109.998762] [] ? default_idle+0x35/0x250 [ 1109.998762] [] arch_cpu_idle+0xf/0x20 [ 1109.998762] [] cpu_startup_entry+0x27d/0x4d0 [ 1109.998762] [] start_secondary+0x188/0x1f0 When intra-node messages are delivered from one process to another process, tipc_link_xmit() doesn't disable BH before it directly calls tipc_sk_rcv() on process context to forward messages to destination socket. Meanwhile, if messages delivered by remote node arrive at the node and their destinations are also the same socket, tipc_sk_rcv() running on process context might be preempted by tipc_sk_rcv() running BH context. As a result, the latter cannot obtain the socket lock as the lock was obtained by the former, however, the former has no chance to be run as the latter is owning the CPU now, so headlock happens. To avoid it, BH should be always disabled in tipc_sk_rcv(). Signed-off-by: Ying Xue Reviewed-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3043f10dc32804..51bddc236a1558 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1776,7 +1776,7 @@ int tipc_sk_rcv(struct sk_buff *buf) sk = &tsk->sk; /* Queue message */ - bh_lock_sock(sk); + spin_lock_bh(&sk->sk_lock.slock); if (!sock_owned_by_user(sk)) { rc = filter_rcv(sk, buf); @@ -1787,7 +1787,7 @@ int tipc_sk_rcv(struct sk_buff *buf) if (sk_add_backlog(sk, buf, limit)) rc = -TIPC_ERR_OVERLOAD; } - bh_unlock_sock(sk); + spin_unlock_bh(&sk->sk_lock.slock); tipc_sk_put(tsk); if (likely(!rc)) return 0; From 61829994e3b86ffa9f0f668f3045bf061aa3b719 Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 21 Oct 2014 13:55:09 -0600 Subject: [PATCH 429/889] fs: merge I/O error prints into one line buffer.c uses two printk calls to print these messages: [67353.422338] Buffer I/O error on device sdr, logical block 212868488 [67353.422338] lost page write due to I/O error on sdr In a busy system, they may be interleaved with other prints, losing the context for the second message. Merge them into one line with one printk call so the prints are atomic. Also, differentiate between async page writes, sync page writes, and async page reads. Also, shorten "device" to "dev" to match the block layer prints: [67353.467906] blk_update_request: critical target error, dev sdr, sector 1707107328 Also, use %llu rather than %Lu. Resulting prints look like: [ 1356.437006] blk_update_request: critical target error, dev sdr, sector 1719693992 [ 1361.383522] quiet_error: 659876 callbacks suppressed [ 1361.385816] Buffer I/O error on dev sdr, logical block 256902912, lost async page write [ 1361.385819] Buffer I/O error on dev sdr, logical block 256903644, lost async page write Signed-off-by: Robert Elliott Reviewed-by: Webb Scales Signed-off-by: Jens Axboe --- fs/buffer.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 6c48f20eddd4b6..9d1da1d314a2b7 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -137,12 +137,12 @@ static int quiet_error(struct buffer_head *bh) } -static void buffer_io_error(struct buffer_head *bh) +static void buffer_io_error(struct buffer_head *bh, char *msg) { char b[BDEVNAME_SIZE]; - printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n", + printk(KERN_ERR "Buffer I/O error on dev %s, logical block %llu%s\n", bdevname(bh->b_bdev, b), - (unsigned long long)bh->b_blocknr); + (unsigned long long)bh->b_blocknr, msg); } /* @@ -177,17 +177,11 @@ EXPORT_SYMBOL(end_buffer_read_sync); void end_buffer_write_sync(struct buffer_head *bh, int uptodate) { - char b[BDEVNAME_SIZE]; - if (uptodate) { set_buffer_uptodate(bh); } else { - if (!quiet_error(bh)) { - buffer_io_error(bh); - printk(KERN_WARNING "lost page write due to " - "I/O error on %s\n", - bdevname(bh->b_bdev, b)); - } + if (!quiet_error(bh)) + buffer_io_error(bh, ", lost sync page write"); set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); } @@ -305,7 +299,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) } else { clear_buffer_uptodate(bh); if (!quiet_error(bh)) - buffer_io_error(bh); + buffer_io_error(bh, ", async page read"); SetPageError(page); } @@ -353,7 +347,6 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) */ void end_buffer_async_write(struct buffer_head *bh, int uptodate) { - char b[BDEVNAME_SIZE]; unsigned long flags; struct buffer_head *first; struct buffer_head *tmp; @@ -365,12 +358,8 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate) if (uptodate) { set_buffer_uptodate(bh); } else { - if (!quiet_error(bh)) { - buffer_io_error(bh); - printk(KERN_WARNING "lost page write due to " - "I/O error on %s\n", - bdevname(bh->b_bdev, b)); - } + if (!quiet_error(bh)) + buffer_io_error(bh, ", lost async page write"); set_bit(AS_EIO, &page->mapping->flags); set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); From 418bf52bc1946bd2f150331b6954bfa4a270ebaf Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Tue, 21 Oct 2014 13:55:11 -0600 Subject: [PATCH 430/889] fs: clarify rate limit suppressed buffer I/O errors When quiet_error applies rate limiting to buffer_io_error calls, what the they apply to is unclear because the name is so generic, particularly if the messages are interleaved with others: [ 1936.063572] quiet_error: 664293 callbacks suppressed [ 1936.065297] Buffer I/O error on dev sdr, logical block 257429952, lost async page write [ 1936.067814] Buffer I/O error on dev sdr, logical block 257429953, lost async page write Also, the function uses printk_ratelimit(), although printk.h includes a comment advising "Please don't use... Instead use printk_ratelimited()." Change buffer_io_error to check the BH_Quiet bit itself, drop the printk_ratelimit call, and print using printk_ratelimited. This makes the messages look like: [ 387.208839] buffer_io_error: 676394 callbacks suppressed [ 387.210693] Buffer I/O error on dev sdr, logical block 211291776, lost async page write [ 387.213432] Buffer I/O error on dev sdr, logical block 211291777, lost async page write Signed-off-by: Robert Elliott Reviewed-by: Webb Scales Signed-off-by: Jens Axboe --- fs/buffer.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 9d1da1d314a2b7..20805db2c98774 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -128,19 +128,13 @@ __clear_page_buffers(struct page *page) page_cache_release(page); } - -static int quiet_error(struct buffer_head *bh) -{ - if (!test_bit(BH_Quiet, &bh->b_state) && printk_ratelimit()) - return 0; - return 1; -} - - static void buffer_io_error(struct buffer_head *bh, char *msg) { char b[BDEVNAME_SIZE]; - printk(KERN_ERR "Buffer I/O error on dev %s, logical block %llu%s\n", + + if (!test_bit(BH_Quiet, &bh->b_state)) + printk_ratelimited(KERN_ERR + "Buffer I/O error on dev %s, logical block %llu%s\n", bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr, msg); } @@ -180,8 +174,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate) if (uptodate) { set_buffer_uptodate(bh); } else { - if (!quiet_error(bh)) - buffer_io_error(bh, ", lost sync page write"); + buffer_io_error(bh, ", lost sync page write"); set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); } @@ -298,8 +291,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) set_buffer_uptodate(bh); } else { clear_buffer_uptodate(bh); - if (!quiet_error(bh)) - buffer_io_error(bh, ", async page read"); + buffer_io_error(bh, ", async page read"); SetPageError(page); } @@ -358,8 +350,7 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate) if (uptodate) { set_buffer_uptodate(bh); } else { - if (!quiet_error(bh)) - buffer_io_error(bh, ", lost async page write"); + buffer_io_error(bh, ", lost async page write"); set_bit(AS_EIO, &page->mapping->flags); set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); From f35bca83a74654a12310ebc2e8802c45c45cc4d1 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 30 Sep 2014 03:14:55 +0100 Subject: [PATCH 431/889] mtd: m25p80,spi-nor: Fix module aliases for m25p80 m25p80's device ID table is now spi_nor_ids, defined in spi-nor. The MODULE_DEVICE_TABLE() macro doesn't work with extern definitions, but its use was also removed at the same time. Now if m25p80 is built as a module it doesn't get the necessary aliases to be loaded automatically. A clean solution to this will involve defining the list of device IDs in spi-nor.h and removing struct spi_device_id from the spi-nor API, but this is quite a large change. As a quick fix suitable for stable, copy the device IDs back into m25p80. Fixes: 03e296f613af ("mtd: m25p80: use the SPI nor framework") Cc: # 3.16.x: 32f1b7c8352f: mtd: move support for struct flash_platform_data into m25p80 Cc: # 3.16.x: 90e55b3812a1: mtd: m25p80: get rid of spi_get_device_id Cc: # 3.16.x: 70f3ce0510af: mtd: spi-nor: make spi_nor_scan() take a chip type name, not spi_device_id Cc: # 3.16.x Signed-off-by: Ben Hutchings Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 52 ++++++++++++++++++++++++++++++++++- drivers/mtd/spi-nor/spi-nor.c | 3 +- include/linux/mtd/spi-nor.h | 1 - 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index bd5e4c6edfd4bf..ed827cf894e4d8 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -261,12 +261,62 @@ static int m25p_remove(struct spi_device *spi) } +/* + * XXX This needs to be kept in sync with spi_nor_ids. We can't share + * it with spi-nor, because if this is built as a module then modpost + * won't be able to read it and add appropriate aliases. + */ +static const struct spi_device_id m25p_ids[] = { + {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, + {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, + {"at26df321"}, {"at45db081d"}, + {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, + {"en25q64"}, {"en25qh128"}, {"en25qh256"}, + {"f25l32pa"}, + {"mr25h256"}, {"mr25h10"}, + {"gd25q32"}, {"gd25q64"}, + {"160s33b"}, {"320s33b"}, {"640s33b"}, + {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, + {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, + {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, + {"mx66l1g55g"}, + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, + {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, + {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, + {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, + {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, + {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, + {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, + {"s25fl016k"}, {"s25fl064k"}, + {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, + {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, + {"sst25wf040"}, + {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, + {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, + {"m25p128"}, {"n25q032"}, + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, + {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, + {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, + {"m25px64"}, + {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, + {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, + {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, + {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, + {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, + { }, +}; +MODULE_DEVICE_TABLE(spi, m25p_ids); + + static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .owner = THIS_MODULE, }, - .id_table = spi_nor_ids, + .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 5c8e39977bc5b2..c51ee52386a71d 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -475,7 +475,7 @@ struct flash_info { * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ -const struct spi_device_id spi_nor_ids[] = { +static const struct spi_device_id spi_nor_ids[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, @@ -639,7 +639,6 @@ const struct spi_device_id spi_nor_ids[] = { { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { }, }; -EXPORT_SYMBOL_GPL(spi_nor_ids); static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index a5a7a086748d0c..046a0a2e4c4efd 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -199,6 +199,5 @@ struct spi_nor { * Return: 0 for success, others for failure. */ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); -extern const struct spi_device_id spi_nor_ids[]; #endif From 9f0d7a81b884d0225f0acd23ed5bc2ed5f25fe59 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 22 Oct 2014 08:30:30 +0800 Subject: [PATCH 432/889] blk-merge: recaculate segment if it isn't less than max segments The problem is introduced by commit 764f612c6c3c231b(blk-merge: don't compute bi_phys_segments from bi_vcnt for cloned bio), and merge is needed if number of current segment isn't less than max segments. Strictly speaking, bio->bi_vcnt shouldn't be used here since it may not be accurate in cases of both cloned bio or bio cloned from, but bio_segments() is a bit expensive, and bi_vcnt is still the biggest number, so the approach should work. Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- block/blk-merge.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index ba99351c0f5889..b3ac40aef46b31 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -99,16 +99,17 @@ void blk_recount_segments(struct request_queue *q, struct bio *bio) { bool no_sg_merge = !!test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); + bool merge_not_need = bio->bi_vcnt < queue_max_segments(q); if (no_sg_merge && !bio_flagged(bio, BIO_CLONED) && - bio->bi_vcnt < queue_max_segments(q)) + merge_not_need) bio->bi_phys_segments = bio->bi_vcnt; else { struct bio *nxt = bio->bi_next; bio->bi_next = NULL; bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, - no_sg_merge); + no_sg_merge && merge_not_need); bio->bi_next = nxt; } From 4379f5bb33556ef32ab92889e3fcb40d3bb8b7c5 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Oct 2014 22:05:38 +0200 Subject: [PATCH 433/889] netlink: Re-add locking to netlink_lookup() and seq walker The synchronize_rcu() in netlink_release() introduces unacceptable latency. Reintroduce minimal lookup so we can drop the synchronize_rcu() until socket destruction has been RCUfied. Cc: David S. Miller Cc: Eric Dumazet Reported-by: Steinar H. Gunderson Reported-and-tested-by: Heiko Carstens Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7a186e74b1b353..f1de72de273e20 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -96,6 +96,14 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static int netlink_dump(struct sock *sk); static void netlink_skb_destructor(struct sk_buff *skb); +/* nl_table locking explained: + * Lookup and traversal are protected with nl_sk_hash_lock or nl_table_lock + * combined with an RCU read-side lock. Insertion and removal are protected + * with nl_sk_hash_lock while using RCU list modification primitives and may + * run in parallel to nl_table_lock protected lookups. Destruction of the + * Netlink socket may only occur *after* nl_table_lock has been acquired + * either during or after the socket has been removed from the list. + */ DEFINE_RWLOCK(nl_table_lock); EXPORT_SYMBOL_GPL(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); @@ -109,10 +117,10 @@ EXPORT_SYMBOL_GPL(nl_sk_hash_lock); static int lockdep_nl_sk_hash_is_held(void) { #ifdef CONFIG_LOCKDEP - return (debug_locks) ? lockdep_is_held(&nl_sk_hash_lock) : 1; -#else - return 1; + if (debug_locks) + return lockdep_is_held(&nl_sk_hash_lock) || lockdep_is_held(&nl_table_lock); #endif + return 1; } static ATOMIC_NOTIFIER_HEAD(netlink_chain); @@ -1028,11 +1036,13 @@ static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) struct netlink_table *table = &nl_table[protocol]; struct sock *sk; + read_lock(&nl_table_lock); rcu_read_lock(); sk = __netlink_lookup(table, portid, net); if (sk) sock_hold(sk); rcu_read_unlock(); + read_unlock(&nl_table_lock); return sk; } @@ -1257,9 +1267,6 @@ static int netlink_release(struct socket *sock) } netlink_table_ungrab(); - /* Wait for readers to complete */ - synchronize_net(); - kfree(nlk->groups); nlk->groups = NULL; @@ -1281,6 +1288,7 @@ static int netlink_autobind(struct socket *sock) retry: cond_resched(); + netlink_table_grab(); rcu_read_lock(); if (__netlink_lookup(table, portid, net)) { /* Bind collision, search negative portid values. */ @@ -1288,9 +1296,11 @@ static int netlink_autobind(struct socket *sock) if (rover > -4097) rover = -4097; rcu_read_unlock(); + netlink_table_ungrab(); goto retry; } rcu_read_unlock(); + netlink_table_ungrab(); err = netlink_insert(sk, net, portid); if (err == -EADDRINUSE) @@ -2921,14 +2931,16 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) } static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) + __acquires(nl_table_lock) __acquires(RCU) { + read_lock(&nl_table_lock); rcu_read_lock(); return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; } static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct rhashtable *ht; struct netlink_sock *nlk; struct nl_seq_iter *iter; struct net *net; @@ -2943,19 +2955,19 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) iter = seq->private; nlk = v; - rht_for_each_entry_rcu(nlk, nlk->node.next, node) + i = iter->link; + ht = &nl_table[i].hash; + rht_for_each_entry(nlk, nlk->node.next, ht, node) if (net_eq(sock_net((struct sock *)nlk), net)) return nlk; - i = iter->link; j = iter->hash_idx + 1; do { - struct rhashtable *ht = &nl_table[i].hash; const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); for (; j < tbl->size; j++) { - rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { + rht_for_each_entry(nlk, tbl->buckets[j], ht, node) { if (net_eq(sock_net((struct sock *)nlk), net)) { iter->link = i; iter->hash_idx = j; @@ -2971,9 +2983,10 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void netlink_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) + __releases(RCU) __releases(nl_table_lock) { rcu_read_unlock(); + read_unlock(&nl_table_lock); } From b7759d43cc2a9d61b56e1a8fa6fc89feb3baf25d Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 20 Oct 2014 14:54:57 -0700 Subject: [PATCH 434/889] bpf: fix bug in eBPF verifier while comparing for verifier state equivalency the comparison was missing a check for uninitialized register. Make sure it does so and add a testcase. Fixes: f1bca824dabb ("bpf: add search pruning optimization to verifier") Cc: Hannes Frederic Sowa Signed-off-by: Alexei Starovoitov Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- kernel/bpf/verifier.c | 3 ++- samples/bpf/test_verifier.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 801f5f3b9307cc..9f81818f294185 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1409,7 +1409,8 @@ static bool states_equal(struct verifier_state *old, struct verifier_state *cur) if (memcmp(&old->regs[i], &cur->regs[i], sizeof(old->regs[0])) != 0) { if (old->regs[i].type == NOT_INIT || - old->regs[i].type == UNKNOWN_VALUE) + (old->regs[i].type == UNKNOWN_VALUE && + cur->regs[i].type != NOT_INIT)) continue; return false; } diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index f44ef11f65a787..eb4bec0ad8afd2 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -208,6 +208,17 @@ static struct bpf_test tests[] = { .errstr = "R0 !read_ok", .result = REJECT, }, + { + "program doesn't init R0 before exit in all branches", + .insns = { + BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .errstr = "R0 !read_ok", + .result = REJECT, + }, { "stack out of bounds", .insns = { From 40be63861c78bcefff95dd000550668ad5f71a91 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 21 Oct 2014 11:23:30 +0200 Subject: [PATCH 435/889] net: sched: initialize bstats syncp Use netdev_alloc_pcpu_stats to allocate percpu stats and initialize syncp. Fixes: 22e0f8b9322c "net: sched: make bstats per cpu and estimator RCU safe" Signed-off-by: Sabrina Dubroca Acked-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/sch_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 2cf61b3e633c25..76f402e05bd6f7 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -947,7 +947,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) { if (qdisc_is_percpu_stats(sch)) { sch->cpu_bstats = - alloc_percpu(struct gnet_stats_basic_cpu); + netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); if (!sch->cpu_bstats) goto err_out4; From 8b19298f6896601d9b3b2fca2788b87057e5c5d3 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 21 Oct 2014 14:25:38 +1100 Subject: [PATCH 436/889] powerpc/mm: Fix build error with hugetlfs disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/powerpc/mm/slice.c:704:5: error: expected identifier or ‘(’ before numeric constant int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, ^ make[1]: *** [arch/powerpc/mm/slice.o] Error 1 make: *** [arch/powerpc/mm/slice.o] Error 2 This got introduced via 1217d34b531c76362217057ca70a8ce8950574e0 "powerpc: Ensure global functions include their prototype". We started including linux/hugetlb.h with that patch and now we have #define is_hugepage_only_range(mm, addr, len) 0 with hugetlbfs disabled. Fixes: 1217d34b531c ("powerpc: Ensure global functions include their prototype") Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/mm/slice.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 8d7bda94d1969b..ded0ea1afde402 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -682,6 +682,7 @@ void slice_set_range_psize(struct mm_struct *mm, unsigned long start, slice_convert(mm, mask, psize); } +#ifdef CONFIG_HUGETLB_PAGE /* * is_hugepage_only_range() is used by generic code to verify whether * a normal mmap mapping (non hugetlbfs) is valid on a given area. @@ -726,4 +727,4 @@ int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, #endif return !slice_check_fit(mask, available); } - +#endif From 815ddbe9025e1ed97518233f7dcee4e535ac200b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 21 Oct 2014 14:25:59 +1100 Subject: [PATCH 437/889] powerpc/mm: Remove redundant #if case Remove the check of CONFIG_PPC_SUBPAGE_PROT when deciding if is_hugepage_only_range() is extern or inline. The extern version is in slice.c and is built if CONFIG_PPC_MM_SLICES=y. There was no build break possible because CONFIG_PPC_SUBPAGE_PROT is only selectable under conditions which also mean CONFIG_PPC_MM_SLICES will be selected. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/hugetlb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index 623f2971ce0ed8..766b77d527ac6e 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h @@ -71,7 +71,7 @@ pte_t *huge_pte_offset_and_shift(struct mm_struct *mm, void flush_dcache_icache_hugepage(struct page *page); -#if defined(CONFIG_PPC_MM_SLICES) || defined(CONFIG_PPC_SUBPAGE_PROT) +#if defined(CONFIG_PPC_MM_SLICES) int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, unsigned long len); #else From 169daddfb15b7220b47e408c94b3148433a82003 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Fri, 17 Oct 2014 19:19:59 -0400 Subject: [PATCH 438/889] MAINTAINERS: nx-842 driver maintainer change Change maintainer of nx-842 compression coprocessor driver to Dan Streetman. Signed-off-by: Dan Streetman Acked-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index eb9affb9745880..a415bc750c0878 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4608,7 +4608,7 @@ S: Supported F: drivers/crypto/nx/ IBM Power 842 compression accelerator -M: Nathan Fontenot +M: Dan Streetman S: Supported F: drivers/crypto/nx/nx-842.c F: include/linux/nx842.h From 7a0faa9dfdefcad4b9587fb09c2a37fb8ddaaf6e Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 10 Oct 2014 01:53:45 -0400 Subject: [PATCH 439/889] powerpc: Wire up sys_bpf() syscall This patch wires up the new syscall sys_bpf() on powerpc. Passes the tests in samples/bpf: #0 add+sub+mul OK #1 unreachable OK #2 unreachable2 OK #3 out of range jump OK #4 out of range jump2 OK #5 test1 ld_imm64 OK #6 test2 ld_imm64 OK #7 test3 ld_imm64 OK #8 test4 ld_imm64 OK #9 test5 ld_imm64 OK #10 no bpf_exit OK #11 loop (back-edge) OK #12 loop2 (back-edge) OK #13 conditional loop OK #14 read uninitialized register OK #15 read invalid register OK #16 program doesn't init R0 before exit OK #17 stack out of bounds OK #18 invalid call insn1 OK #19 invalid call insn2 OK #20 invalid function call OK #21 uninitialized stack1 OK #22 uninitialized stack2 OK #23 check valid spill/fill OK #24 check corrupted spill/fill OK #25 invalid src register in STX OK #26 invalid dst register in STX OK #27 invalid dst register in ST OK #28 invalid src register in LDX OK #29 invalid dst register in LDX OK #30 junk insn OK #31 junk insn2 OK #32 junk insn3 OK #33 junk insn4 OK #34 junk insn5 OK #35 misaligned read from stack OK #36 invalid map_fd for function call OK #37 don't check return value before access OK #38 access memory with incorrect alignment OK #39 sometimes access memory with incorrect alignment OK #40 jump test 1 OK #41 jump test 2 OK #42 jump test 3 OK #43 jump test 4 OK Signed-off-by: Pranith Kumar [mpe: test using samples/bpf] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/systbl.h | 1 + arch/powerpc/include/asm/unistd.h | 2 +- arch/powerpc/include/uapi/asm/unistd.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 7d8a600688058e..ce9577d693be1c 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -365,3 +365,4 @@ SYSCALL_SPU(renameat2) SYSCALL_SPU(seccomp) SYSCALL_SPU(getrandom) SYSCALL_SPU(memfd_create) +SYSCALL_SPU(bpf) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 4e9af3fd43e7d0..e0da021caa0042 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -12,7 +12,7 @@ #include -#define __NR_syscalls 361 +#define __NR_syscalls 362 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index 0688fc06e18394..f55351f2e66e96 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -383,5 +383,6 @@ #define __NR_seccomp 358 #define __NR_getrandom 359 #define __NR_memfd_create 360 +#define __NR_bpf 361 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ From 32c94fd582e34166b47095e537fbf9341efaae9c Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 9 Oct 2014 11:48:30 +0200 Subject: [PATCH 440/889] fbcon: Fix option parsing control flow in fb_console_setup Since strsep is used to tokenize the options string, after each option match the code should use "continue" to get the next token from strsep. This patch applies this pattern consistently. Previously, for "scrollback:" and "map:" the parse code would return (unconditionally: strsep ensures *options != ','), causing any following option to be ignored, while for "vc:" the parse code would go on to parse further options within the same token, which could lead to invalid input being accepted. Signed-off-by: Maarten ter Huurne Acked-by: Paul Cercueil Signed-off-by: Tomi Valkeinen --- drivers/video/console/fbcon.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 57b1d44acbfe3d..eb976ee3a02f30 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -448,8 +448,10 @@ static int __init fb_console_setup(char *this_opt) return 1; while ((options = strsep(&this_opt, ",")) != NULL) { - if (!strncmp(options, "font:", 5)) + if (!strncmp(options, "font:", 5)) { strlcpy(fontname, options + 5, sizeof(fontname)); + continue; + } if (!strncmp(options, "scrollback:", 11)) { options += 11; @@ -457,13 +459,9 @@ static int __init fb_console_setup(char *this_opt) fbcon_softback_size = simple_strtoul(options, &options, 0); if (*options == 'k' || *options == 'K') { fbcon_softback_size *= 1024; - options++; } - if (*options != ',') - return 1; - options++; - } else - return 1; + } + continue; } if (!strncmp(options, "map:", 4)) { @@ -478,8 +476,7 @@ static int __init fb_console_setup(char *this_opt) fbcon_map_override(); } - - return 1; + continue; } if (!strncmp(options, "vc:", 3)) { @@ -491,7 +488,8 @@ static int __init fb_console_setup(char *this_opt) if (*options++ == '-') last_fb_vc = simple_strtoul(options, &options, 10) - 1; fbcon_is_default = 0; - } + continue; + } if (!strncmp(options, "rotate:", 7)) { options += 7; @@ -499,6 +497,7 @@ static int __init fb_console_setup(char *this_opt) initial_rotation = simple_strtoul(options, &options, 0); if (initial_rotation > 3) initial_rotation = 0; + continue; } } return 1; From 4a8d9ccabd64dd8c07461557fe3bbfb3b038754a Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 14 Oct 2014 04:53:49 -0700 Subject: [PATCH 441/889] video/console: Resolve several shadow warnings Resolve shadow warnings that appear in W=2 builds by renaming the "state" global to "vgastate". Signed-off-by: Mark Rustad Signed-off-by: Jeff Kirsher Signed-off-by: Tomi Valkeinen --- drivers/video/console/vgacon.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 6e6aa704fe84a1..517f565b65d760 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -56,7 +56,7 @@ static int cursor_size_lastfrom; static int cursor_size_lastto; static u32 vgacon_xres; static u32 vgacon_yres; -static struct vgastate state; +static struct vgastate vgastate; #define BLANK 0x0020 @@ -400,7 +400,7 @@ static const char *vgacon_startup(void) vga_video_num_lines = screen_info.orig_video_lines; vga_video_num_columns = screen_info.orig_video_cols; - state.vgabase = NULL; + vgastate.vgabase = NULL; if (screen_info.orig_video_mode == 7) { /* Monochrome display */ @@ -851,12 +851,12 @@ static void vga_set_palette(struct vc_data *vc, unsigned char *table) { int i, j; - vga_w(state.vgabase, VGA_PEL_MSK, 0xff); + vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff); for (i = j = 0; i < 16; i++) { - vga_w(state.vgabase, VGA_PEL_IW, table[i]); - vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); - vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); - vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]); + vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); } } @@ -1008,7 +1008,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) switch (blank) { case 0: /* Unblank */ if (vga_vesa_blanked) { - vga_vesa_unblank(&state); + vga_vesa_unblank(&vgastate); vga_vesa_blanked = 0; } if (vga_palette_blanked) { @@ -1022,7 +1022,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) case 1: /* Normal blanking */ case -1: /* Obsolete */ if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { - vga_pal_blank(&state); + vga_pal_blank(&vgastate); vga_palette_blanked = 1; return 0; } @@ -1034,7 +1034,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) return 1; default: /* VESA blanking */ if (vga_video_type == VIDEO_TYPE_VGAC) { - vga_vesa_blank(&state, blank - 1); + vga_vesa_blank(&vgastate, blank - 1); vga_vesa_blanked = blank; } return 0; @@ -1280,7 +1280,7 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigne (charcount != 256 && charcount != 512)) return -EINVAL; - rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); + rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512); if (rc) return rc; @@ -1299,7 +1299,7 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) font->charcount = vga_512_chars ? 512 : 256; if (!font->data) return 0; - return vgacon_do_font_op(&state, font->data, 0, vga_512_chars); + return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars); } #else From d12a1bb0032381f38c2b7498459ce4ddd947f3df Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Oct 2014 14:19:15 +0200 Subject: [PATCH 442/889] drivers: video: fbdev: atmel_lcdfb.c: remove unnecessary header Remove unnecessary mach/cpu.h header to be able to converge to a multiplatform kernel. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/atmel_lcdfb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 3bf403150a2d6f..9ec81d46fc5785 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -27,7 +27,6 @@ #include #include