* [PATCH 1/9] hpsa: add new controllers
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 2/9] hpsa: Make "hpsa_allow_any=1" boot param enable Compaq Smart Arrays Stephen M. Cameron
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: add new controllers
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 1133b5f..ec9b3a2 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -86,6 +86,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
#define PCI_DEVICE_ID_HP_CISSF 0x333f
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -109,6 +114,11 @@ static struct board_type products[] = {
{0x324b103C, "Smart Array P711m", &SA5_access},
{0x3233103C, "StorageWorks P1210m", &SA5_access},
{0x333F103C, "StorageWorks P1210m", &SA5_access},
+ {0x3250103C, "Smart Array", &SA5_access},
+ {0x3250113C, "Smart Array", &SA5_access},
+ {0x3250123C, "Smart Array", &SA5_access},
+ {0x3250133C, "Smart Array", &SA5_access},
+ {0x3250143C, "Smart Array", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 2/9] hpsa: Make "hpsa_allow_any=1" boot param enable Compaq Smart Arrays.
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 1/9] hpsa: add new controllers Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 3/9] hpsa: make hpsa_find_memory_BAR not require the per HBA structure Stephen M. Cameron
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: Make "hpsa_allow_any=1" boot param enable Compaq Smart Arrays.
We were previously only accepting HP boards.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 00b5397..661a320 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -95,6 +95,8 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+ {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -3293,7 +3295,9 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
if (*board_id == products[i].board_id)
return i;
- if (subsystem_vendor_id != PCI_VENDOR_ID_HP || !hpsa_allow_any) {
+ if ((subsystem_vendor_id != PCI_VENDOR_ID_HP &&
+ subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) ||
+ !hpsa_allow_any) {
dev_warn(&pdev->dev, "unrecognized board ID: "
"0x%08x, ignoring.\n", *board_id);
return -ENODEV;
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/9] hpsa: make hpsa_find_memory_BAR not require the per HBA structure.
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 1/9] hpsa: add new controllers Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 2/9] hpsa: Make "hpsa_allow_any=1" boot param enable Compaq Smart Arrays Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 4/9] hpsa: factor out hpsa_find_cfg_addrs Stephen M. Cameron
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Rationale for this is that in order to fix the hard reset code used
by kdump, we need to use this function before we even have the per
HBA structure.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 661a320..1decf16 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3313,20 +3313,20 @@ static inline bool hpsa_board_disabled(struct pci_dev *pdev)
return ((command & PCI_COMMAND_MEMORY) == 0);
}
-static int __devinit hpsa_pci_find_memory_BAR(struct ctlr_info *h,
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar)
{
int i;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
- if (pci_resource_flags(h->pdev, i) & IORESOURCE_MEM) {
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
/* addressing mode bits already removed */
- *memory_bar = pci_resource_start(h->pdev, i);
- dev_dbg(&h->pdev->dev, "memory BAR = %lx\n",
+ *memory_bar = pci_resource_start(pdev, i);
+ dev_dbg(&pdev->dev, "memory BAR = %lx\n",
*memory_bar);
return 0;
}
- dev_warn(&h->pdev->dev, "no memory BAR found\n");
+ dev_warn(&pdev->dev, "no memory BAR found\n");
return -ENODEV;
}
@@ -3503,7 +3503,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
return err;
}
hpsa_interrupt_mode(h);
- err = hpsa_pci_find_memory_BAR(h, &h->paddr);
+ err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
if (err)
goto err_out_free_res;
h->vaddr = remap_pci_mem(h->paddr, 0x250);
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/9] hpsa: factor out hpsa_find_cfg_addrs.
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (2 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 3/9] hpsa: make hpsa_find_memory_BAR not require the per HBA structure Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 5/9] hpsa: factor out the code to reset controllers on driver load Stephen M. Cameron
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Rationale for this is that I will also need to use this code
in fixing kdump host reset code prior to having the hba structure.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 34 ++++++++++++++++++++++------------
1 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 1decf16..67439c1 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3345,29 +3345,39 @@ static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
return -ENODEV;
}
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset)
+{
+ *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
+ *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
+ *cfg_base_addr &= (u32) 0x0000ffff;
+ *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
+ if (*cfg_base_addr_index == -1) {
+ dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
{
u64 cfg_offset;
u32 cfg_base_addr;
u64 cfg_base_addr_index;
u32 trans_offset;
+ int rc;
- /* get the address index number */
- cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
- cfg_base_addr &= (u32) 0x0000ffff;
- cfg_base_addr_index = find_PCI_BAR_index(h->pdev, cfg_base_addr);
- if (cfg_base_addr_index == -1) {
- dev_warn(&h->pdev->dev, "cannot find cfg_base_addr_index\n");
- return -ENODEV;
- }
- cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ return rc;
h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
- cfg_base_addr_index) + cfg_offset,
- sizeof(h->cfgtable));
+ cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
if (!h->cfgtable)
return -ENOMEM;
/* Find performant mode table. */
- trans_offset = readl(&(h->cfgtable->TransMethodOffset));
+ trans_offset = readl(&h->cfgtable->TransMethodOffset);
h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
cfg_base_addr_index)+cfg_offset+trans_offset,
sizeof(*h->transtable));
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 5/9] hpsa: factor out the code to reset controllers on driver load
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (3 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 4/9] hpsa: factor out hpsa_find_cfg_addrs Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 6/9] hpsa: Fix hard reset code Stephen M. Cameron
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: factor out the code to reset controllers on driver load
for kdump support
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 49 ++++++++++++++++++++++++++++++-------------------
1 files changed, 30 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 67439c1..54b7fda 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3571,33 +3571,44 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
}
}
+static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+{
+ int i;
+
+ if (!reset_devices)
+ return 0;
+
+ /* Reset the controller with a PCI power-cycle */
+ if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
+ return -ENODEV;
+
+ /* Some devices (notably the HP Smart Array 5i Controller)
+ need a little pause here */
+ msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+ /* Now try to get the controller to respond to a no-op */
+ for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+ if (hpsa_noop(pdev) == 0)
+ break;
+ else
+ dev_warn(&pdev->dev, "no-op failed%s\n",
+ (i < 11 ? "; re-trying" : ""));
+ }
+ return 0;
+}
+
static int __devinit hpsa_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i, rc;
- int dac;
+ int dac, rc;
struct ctlr_info *h;
if (number_of_controllers == 0)
printk(KERN_INFO DRIVER_NAME "\n");
- if (reset_devices) {
- /* Reset the controller with a PCI power-cycle */
- if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
- return -ENODEV;
-
- /* Some devices (notably the HP Smart Array 5i Controller)
- need a little pause here */
- msleep(HPSA_POST_RESET_PAUSE_MSECS);
- /* Now try to get the controller to respond to a no-op */
- for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
- if (hpsa_noop(pdev) == 0)
- break;
- else
- dev_warn(&pdev->dev, "no-op failed%s\n",
- (i < 11 ? "; re-trying" : ""));
- }
- }
+ rc = hpsa_init_reset_devices(pdev);
+ if (rc)
+ return rc;
/* Command structures must be aligned on a 32-byte boundary because
* the 5 lower bits of the address are used by the hardware. and by
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 6/9] hpsa: Fix hard reset code.
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (4 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 5/9] hpsa: factor out the code to reset controllers on driver load Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 7/9] hpsa: forbid hard reset of 640x boards Stephen M. Cameron
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: Fix hard reset code.
Smart Array controllers newer than the P600 do not honor the
PCI power state method of resetting the controllers. Instead,
in these cases we can get them to reset via the "doorbell" register.
This escaped notice until we began using "performant" mode because
the fact that the controllers did not reset did not normally
impede subsequent operation, and so things generally appeared to
"work". Once the performant mode code was added, if the controller
does not reset, it remains in performant mode. The code immediately
after the reset presumes the controller is in "simple" mode
(which previously, it had remained in simple mode the whole time).
If the controller remains in performant mode any code which presumes
it is in simple mode will not work. So the reset needs to be fixed.
Unfortunately there are some controllers which cannot be reset by
either method. (eg. p800). We detect these cases by noticing that
the controller seems to remain in performant mode even after a
reset has been attempted. In those case, we proceed anyway,
as if the reset has happened (and skip the step of waiting for
the controller to become ready -- which is expecting it to be in
"simple" mode.) To sum up, we try to do a better job of resetting
the controller if "reset_devices" is set, and if it doesn't work,
we print a message and try to continue anyway.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 174 ++++++++++++++++++++++++++++++++++++-----------
drivers/scsi/hpsa_cmd.h | 4 +
2 files changed, 137 insertions(+), 41 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 54b7fda..58690dc 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -174,6 +174,11 @@ static void calc_bucket_map(int *bucket, int num_buckets,
int nsgs, int *bucket_map);
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h);
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset);
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+ unsigned long *memory_bar);
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
@@ -3078,17 +3083,75 @@ static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
return 0;
}
+static int hpsa_controller_hard_reset(struct pci_dev *pdev,
+ void * __iomem vaddr, bool use_doorbell)
+{
+ u16 pmcsr;
+ int pos;
+
+ if (use_doorbell) {
+ /* For everything after the P600, the PCI power state method
+ * of resetting the controller doesn't work, so we have this
+ * other way using the doorbell register.
+ */
+ dev_info(&pdev->dev, "using doorbell to reset controller\n");
+ writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
+ msleep(1000);
+ } else { /* Try to do it the PCI power state way */
+
+ /* Quoting from the Open CISS Specification: "The Power
+ * Management Control/Status Register (CSR) controls the power
+ * state of the device. The normal operating state is D0,
+ * CSR=00h. The software off state is D3, CSR=03h. To reset
+ * the controller, place the interface device in D3 then to D0,
+ * this causes a secondary PCI reset which will reset the
+ * controller." */
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pos == 0) {
+ dev_err(&pdev->dev,
+ "hpsa_reset_controller: "
+ "PCI PM not supported\n");
+ return -ENODEV;
+ }
+ dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+ /* enter the D3hot power management state */
+ pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D3hot;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+
+ /* enter the D0 power management state */
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D0;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+ }
+ return 0;
+}
+
/* This does a hard reset of the controller using PCI power management
- * states.
+ * states or the using the doorbell register.
*/
-static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
{
- u16 pmcsr, saved_config_space[32];
- int i, pos;
+ u16 saved_config_space[32];
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ void __iomem *vaddr;
+ unsigned long paddr;
+ u32 misc_fw_support, active_transport;
+ int rc, i;
+ struct CfgTable __iomem *cfgtable;
+ bool use_doorbell;
- dev_info(&pdev->dev, "using PCI PM to reset controller\n");
- /* This is very nearly the same thing as
+ /* For controllers as old as the P600, this is very nearly
+ * the same thing as
*
* pci_save_state(pci_dev);
* pci_set_power_state(pci_dev, PCI_D3hot);
@@ -3102,41 +3165,42 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
* violate the ordering requirements for restoring the
* configuration space from the CCISS document (see the
* comment below). So we roll our own ....
+ *
+ * For controllers newer than the P600, the pci power state
+ * method of resetting doesn't work so we have another way
+ * using the doorbell register.
*/
-
for (i = 0; i < 32; i++)
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
- pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pos == 0) {
- dev_err(&pdev->dev,
- "hpsa_reset_controller: PCI PM not supported\n");
- return -ENODEV;
- }
-
- /* Quoting from the Open CISS Specification: "The Power
- * Management Control/Status Register (CSR) controls the power
- * state of the device. The normal operating state is D0,
- * CSR=00h. The software off state is D3, CSR=03h. To reset
- * the controller, place the interface device in D3 then to
- * D0, this causes a secondary PCI reset which will reset the
- * controller."
- */
- /* enter the D3hot power management state */
- pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D3hot;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* find the first memory BAR, so we can find the cfg table */
+ rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
+ if (rc)
+ return rc;
+ vaddr = remap_pci_mem(paddr, 0x250);
+ if (!vaddr)
+ return -ENOMEM;
- msleep(500);
+ /* find cfgtable in order to check if reset via doorbell is supported */
+ rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ goto unmap_vaddr;
+ cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
+ if (!cfgtable) {
+ rc = -ENOMEM;
+ goto unmap_vaddr;
+ }
- /* enter the D0 power management state */
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D0;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* If reset via doorbell register is supported, use that. */
+ misc_fw_support = readl(&cfgtable->misc_fw_support);
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
- msleep(500);
+ rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
+ if (rc)
+ goto unmap_cfgtable;
/* Restore the PCI configuration space. The Open CISS
* Specification says, "Restore the PCI Configuration
@@ -3153,7 +3217,29 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
wmb();
pci_write_config_word(pdev, 4, saved_config_space[2]);
- return 0;
+ /* Some devices (notably the HP Smart Array 5i Controller)
+ need a little pause here */
+ msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+ /* Controller should be in simple mode at this point. If it's not,
+ * It means we're on one of those controllers which doesn't support
+ * the doorbell reset method and on which the PCI power management reset
+ * method doesn't work (P800, for example.)
+ * In those cases, pretend the reset worked and hope for the best.
+ */
+ active_transport = readl(&cfgtable->TransportActive);
+ if (active_transport & PERFORMANT_MODE) {
+ dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+ " proceeding anyway.\n");
+ rc = -ENOTSUPP;
+ }
+
+unmap_cfgtable:
+ iounmap(cfgtable);
+
+unmap_vaddr:
+ iounmap(vaddr);
+ return rc;
}
/*
@@ -3573,18 +3659,24 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
{
- int i;
+ int rc, i;
if (!reset_devices)
return 0;
- /* Reset the controller with a PCI power-cycle */
- if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
- return -ENODEV;
+ /* Reset the controller with a PCI power-cycle or via doorbell */
+ rc = hpsa_kdump_hard_reset_controller(pdev);
- /* Some devices (notably the HP Smart Array 5i Controller)
- need a little pause here */
- msleep(HPSA_POST_RESET_PAUSE_MSECS);
+ /* -ENOTSUPP here means we cannot reset the controller
+ * but it's already (and still) up and running in
+ * "performant mode".
+ */
+ if (rc == -ENOTSUPP)
+ return 0; /* just try to do the kdump anyhow. */
+ if (rc)
+ return -ENODEV;
+ if (hpsa_reset_msi(pdev))
+ return -ENODEV;
/* Now try to get the controller to respond to a no-op */
for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 78de9b6..f5c4c3c 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -100,6 +100,7 @@
/* Configuration Table */
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
+#define DOORBELL_CTLR_RESET 0x00000004l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -339,6 +340,9 @@ struct CfgTable {
u32 MaxPhysicalDevices;
u32 MaxPhysicalDrivesPerLogicalUnit;
u32 MaxPerformantModeCommands;
+ u8 reserved[0x78 - 0x58];
+ u32 misc_fw_support; /* offset 0x78 */
+#define MISC_FW_DOORBELL_RESET (0x02)
};
#define NUM_BLOCKFETCH_ENTRIES 8
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 7/9] hpsa: forbid hard reset of 640x boards
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (5 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 6/9] hpsa: Fix hard reset code Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 8/9] hpsa: separate intx and msi/msix interrupt handlers Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 9/9] hpsa: sanitize max commands Stephen M. Cameron
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: forbid hard reset of 640x boards
The 6402/6404 are two PCI devices -- two Smart Array controllers
-- that fit into one slot. It is possible to reset them independently,
however, they share a battery backed cache module. One of the pair
controls the cache and the 2nd one access the cache through the first
one. If you reset the one controlling the cache, the other one will
not be a happy camper. So we just forbid resetting this conjoined
mess.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 18 ++++++++++++++++--
1 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 58690dc..0600c8d 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -179,6 +179,7 @@ static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
u64 *cfg_offset);
static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar);
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
@@ -3148,7 +3149,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
int rc, i;
struct CfgTable __iomem *cfgtable;
bool use_doorbell;
-
+ u32 board_id;
/* For controllers as old as the P600, this is very nearly
* the same thing as
@@ -3170,6 +3171,18 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
* method of resetting doesn't work so we have another way
* using the doorbell register.
*/
+
+ /* Exclude 640x boards. These are two pci devices in one slot
+ * which share a battery backed cache module. One controls the
+ * cache, the other accesses the cache through the one that controls
+ * it. If we reset the one controlling the cache, the other will
+ * likely not be happy. Just forbid resetting this conjoined mess.
+ * The 640x isn't really supported by hpsa anyway.
+ */
+ hpsa_lookup_board_id(pdev, &board_id);
+ if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
+ return -ENOTSUPP;
+
for (i = 0; i < 32; i++)
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
@@ -3669,7 +3682,8 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
/* -ENOTSUPP here means we cannot reset the controller
* but it's already (and still) up and running in
- * "performant mode".
+ * "performant mode". Or, it might be 640x, which can't reset
+ * due to concerns about shared bbwc between 6402/6404 pair.
*/
if (rc == -ENOTSUPP)
return 0; /* just try to do the kdump anyhow. */
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 8/9] hpsa: separate intx and msi/msix interrupt handlers
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (6 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 7/9] hpsa: forbid hard reset of 640x boards Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
2010-06-16 18:51 ` [PATCH 9/9] hpsa: sanitize max commands Stephen M. Cameron
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: separate intx and msi/msix interrupt handlers
There are things which need to be done in the intx
interrupt handler which do not need to be done in
the msi/msix interrupt handler, like checking that
the interrupt is actually for us, and checking that the
interrupt pending bit on the hardware is set (which we
weren't previously doing at all, which means old controllers
wouldn't work), so it makes sense to separate these into
two functions.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 39 ++++++++++++++++++++++++++++++++-------
1 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0600c8d..8f11325 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -126,7 +126,8 @@ static struct board_type products[] = {
static int number_of_controllers;
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+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 start_io(struct ctlr_info *h);
@@ -2858,9 +2859,8 @@ static inline bool interrupt_pending(struct ctlr_info *h)
static inline long interrupt_not_for_us(struct ctlr_info *h)
{
- return !(h->msi_vector || h->msix_vector) &&
- ((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0));
+ return (h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0);
}
static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2934,7 +2934,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
return next_command(h);
}
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
{
struct ctlr_info *h = dev_id;
unsigned long flags;
@@ -2943,6 +2943,26 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
if (interrupt_not_for_us(h))
return IRQ_NONE;
spin_lock_irqsave(&h->lock, flags);
+ while (interrupt_pending(h)) {
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY) {
+ if (hpsa_tag_contains_index(raw_tag))
+ raw_tag = process_indexed_cmd(h, raw_tag);
+ else
+ raw_tag = process_nonindexed_cmd(h, raw_tag);
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ spin_lock_irqsave(&h->lock, flags);
raw_tag = get_next_completion(h);
while (raw_tag != FIFO_EMPTY) {
if (hpsa_tag_contains_index(raw_tag))
@@ -3754,8 +3774,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
- IRQF_DISABLED, h->devname, h);
+
+ if (h->msix_vector || h->msi_vector)
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+ IRQF_DISABLED, h->devname, h);
+ else
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+ IRQF_DISABLED, h->devname, h);
if (rc) {
dev_err(&pdev->dev, "unable to get irq %d for %s\n",
h->intr[PERF_MODE_INT], h->devname);
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 9/9] hpsa: sanitize max commands
2010-06-16 18:51 [PATCH 0/9] hpsa driver updates June 16, 2010 Stephen M. Cameron
` (7 preceding siblings ...)
2010-06-16 18:51 ` [PATCH 8/9] hpsa: separate intx and msi/msix interrupt handlers Stephen M. Cameron
@ 2010-06-16 18:51 ` Stephen M. Cameron
8 siblings, 0 replies; 10+ messages in thread
From: Stephen M. Cameron @ 2010-06-16 18:51 UTC (permalink / raw)
To: linux-scsi; +Cc: andriusb, James.Bottomley, dab, thenzl, mikem
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
hpsa: sanitize max commands
Some controllers might try to tell us they support 0 commands
in performant mode. This is a lie told by buggy firmware.
We have to be wary of this lest we try to allocate a negative
number of command blocks, which will be treated as unsigned,
and get an out of memory condition.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 16 ++++++++++++++--
1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 8f11325..304c908 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3505,13 +3505,25 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
return 0;
}
+static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
+ h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+ if (h->max_commands < 16) {
+ 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;
+ }
+}
+
/* Interrogate the hardware for some limits:
* max commands, max SG elements without chaining, and with chaining,
* SG chain block size, etc.
*/
static void __devinit hpsa_find_board_params(struct ctlr_info *h)
{
- h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+ hpsa_get_max_perf_mode_cmds(h);
h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
/*
@@ -4056,7 +4068,7 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
if (!(trans_support & PERFORMANT_MODE))
return;
- h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+ hpsa_get_max_perf_mode_cmds(h);
h->max_sg_entries = 32;
/* Performant mode ring buffer and supporting data structures */
h->reply_pool_size = h->max_commands * sizeof(u64);
^ permalink raw reply related [flat|nested] 10+ messages in thread