2011-02-15 21:32:50

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 0/6] hpsa: Feb 15, 2011 updates

The following series fixes a problem that commands were unintentionally
re-ordered within the driver, and another problem that the hpsa_simple_mode
module paramter didn't actually work. It adds a host attribute in /sys to
know which mode (simple or performant) the controller is in. It informs the
controller that we're only using 32-bit tags (needed for a couple of new
controllers to work properly). Finally, we shouldn't proceed with kdumping
if a controller cannot be reset, as there may be outstanding commands which
interfere with kdump's i/o.

---

Dan Carpenter (1):
hpsa: fix bad comparison

Stephen M. Cameron (5):
hpsa: do not re-order commands in internal queues
hpsa: make hpsa.hpsa_simple_mode=1 module parameter actually work
hpsa: Add transport_mode host attribute in /sys
hpsa: Inform controller we are using 32-bit tags.
hpsa: Do not attempt kdump if we detect resetting controller failed.


Documentation/scsi/hpsa.txt | 5 ++
drivers/scsi/hpsa.c | 104 +++++++++++++++++++++++++++----------------
drivers/scsi/hpsa.h | 5 +-
drivers/scsi/hpsa_cmd.h | 3 +
4 files changed, 75 insertions(+), 42 deletions(-)

--
-- steve


2011-02-15 21:33:06

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 2/6] hpsa: make hpsa.hpsa_simple_mode=1 module parameter actually work

From: Stephen M. Cameron <[email protected]>

It's not enough to simple avoid putting the board into performant
mode, as we have to set up the interrupts differently, etc. When
I originally tested this module parameter, I tested it incorrectly
without realizing it, and the driver was running in performant mode
the whole time unbeknownst to me.

Signed-off-by: Stephen M. Cameron <[email protected]>
---
drivers/scsi/hpsa.c | 37 +++++++++++++++++++++++--------------
drivers/scsi/hpsa.h | 1 +
2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0f40de2..66ccacf 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1186,7 +1186,7 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
- sh->irq = h->intr[PERF_MODE_INT];
+ sh->irq = h->intr[h->intr_mode];
sh->unique_id = sh->irq;
error = scsi_add_host(sh, &h->pdev->dev);
if (error)
@@ -2902,10 +2902,14 @@ static inline u32 hpsa_tag_to_index(u32 tag)
return tag >> DIRECT_LOOKUP_SHIFT;
}

-static inline u32 hpsa_tag_discard_error_bits(u32 tag)
+
+static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
{
-#define HPSA_ERROR_BITS 0x03
- return tag & ~HPSA_ERROR_BITS;
+#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
+#define HPSA_SIMPLE_ERROR_BITS 0x03
+ if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+ return tag & ~HPSA_SIMPLE_ERROR_BITS;
+ return tag & ~HPSA_PERF_ERROR_BITS;
}

/* process completion of an indexed ("direct lookup") command */
@@ -2930,7 +2934,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
u32 tag;
struct CommandList *c = NULL;

- tag = hpsa_tag_discard_error_bits(raw_tag);
+ tag = hpsa_tag_discard_error_bits(h, raw_tag);
list_for_each_entry(c, &h->cmpQ, list) {
if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
finish_cmd(c, raw_tag);
@@ -2981,7 +2985,10 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
return IRQ_HANDLED;
}

-/* Send a message CDB to the firmware. */
+/* Send a message CDB to the firmware. Careful, this only works
+ * in simple mode, not performant mode due to the tag lookup.
+ * We only ever use this immediately after a controller reset.
+ */
static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
unsigned char type)
{
@@ -3047,7 +3054,7 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,

for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
- if (hpsa_tag_discard_error_bits(tag) == paddr32)
+ if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32)
break;
msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
}
@@ -3379,7 +3386,7 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
default_int_mode:
#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- h->intr[PERF_MODE_INT] = h->pdev->irq;
+ h->intr[h->intr_mode] = h->pdev->irq;
}

static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
@@ -3760,6 +3767,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,

h->pdev = pdev;
h->busy_initializing = 1;
+ h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
+ printk(KERN_WARNING "hpsa_simple_mode is %d\n", hpsa_simple_mode);
INIT_LIST_HEAD(&h->cmpQ);
INIT_LIST_HEAD(&h->reqQ);
spin_lock_init(&h->lock);
@@ -3790,20 +3799,20 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
h->access.set_intr_mask(h, HPSA_INTR_OFF);

if (h->msix_vector || h->msi_vector)
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+ rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi,
IRQF_DISABLED, h->devname, h);
else
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+ rc = request_irq(h->intr[h->intr_mode], 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);
+ h->intr[h->intr_mode], h->devname);
goto clean2;
}

dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
h->devname, pdev->device,
- h->intr[PERF_MODE_INT], dac ? "" : " not");
+ h->intr[h->intr_mode], dac ? "" : " not");

h->cmd_pool_bits =
kmalloc(((h->nr_cmds + BITS_PER_LONG -
@@ -3854,7 +3863,7 @@ clean4:
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
- free_irq(h->intr[PERF_MODE_INT], h);
+ free_irq(h->intr[h->intr_mode], h);
clean2:
clean1:
h->busy_initializing = 0;
@@ -3898,7 +3907,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
*/
hpsa_flush_cache(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- free_irq(h->intr[PERF_MODE_INT], h);
+ free_irq(h->intr[h->intr_mode], h);
#ifdef CONFIG_PCI_MSI
if (h->msix_vector)
pci_disable_msix(h->pdev);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index e898193..621a153 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -72,6 +72,7 @@ struct ctlr_info {
unsigned int intr[4];
unsigned int msix_vector;
unsigned int msi_vector;
+ int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
struct access_method access;

/* queue and queue Info */

2011-02-15 21:33:13

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 5/6] hpsa: Do not attempt kdump if we detect resetting controller failed.

From: Stephen M. Cameron <[email protected]>

We can get completions left over from before the attempted reset which
will interfere with the kdump. Better to just not make the attempt in
that case.

Signed-off-by: Stephen M. Cameron <[email protected]>
---
drivers/scsi/hpsa.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index a778cb1..eb6938f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3264,13 +3264,13 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
* 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.
+ * In those cases, don't try to proceed, as it generally doesn't work.
*/
active_transport = readl(&cfgtable->TransportActive);
if (active_transport & PERFORMANT_MODE) {
dev_warn(&pdev->dev, "Unable to successfully reset controller,"
- " proceeding anyway.\n");
- rc = -ENOTSUPP;
+ " Ignoring controller.\n");
+ rc = -ENODEV;
}

unmap_cfgtable:

2011-02-15 21:33:10

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 3/6] hpsa: Add transport_mode host attribute in /sys

From: Stephen M. Cameron <[email protected]>

Signed-off-by: Stephen M. Cameron <[email protected]>
---
Documentation/scsi/hpsa.txt | 5 +++++
drivers/scsi/hpsa.c | 18 +++++++++++++++++-
2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt
index dca6583..ed524f1 100644
--- a/Documentation/scsi/hpsa.txt
+++ b/Documentation/scsi/hpsa.txt
@@ -39,6 +39,7 @@ HPSA specific entries in /sys

/sys/class/scsi_host/host*/rescan
/sys/class/scsi_host/host*/firmware_revision
+ /sys/class/scsi_host/host*/transport_mode

the host "rescan" attribute is a write only attribute. Writing to this
attribute will cause the driver to scan for new, changed, or removed devices
@@ -55,6 +56,10 @@ HPSA specific entries in /sys
root@host:/sys/class/scsi_host/host4# cat firmware_revision
7.14

+ The transport_mode indicates whether the controller is in "performant"
+ or "simple" mode. This is controlled by the "hpsa_simple_mode" module
+ parameter.
+
HPSA specific disk attributes:
------------------------------

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 66ccacf..563d439 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -161,6 +161,8 @@ static ssize_t host_show_firmware_revision(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t host_show_commands_outstanding(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t host_show_transport_mode(struct device *dev,
+ struct device_attribute *attr, char *buf);
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -192,6 +194,8 @@ static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
host_show_commands_outstanding, NULL);
+static DEVICE_ATTR(transport_mode, S_IRUGO,
+ host_show_transport_mode, NULL);

static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
@@ -204,6 +208,7 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_rescan,
&dev_attr_firmware_revision,
&dev_attr_commands_outstanding,
+ &dev_attr_transport_mode,
NULL,
};

@@ -313,6 +318,18 @@ static ssize_t host_show_commands_outstanding(struct device *dev,
return snprintf(buf, 20, "%d\n", h->commands_outstanding);
}

+static ssize_t host_show_transport_mode(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, "%s\n",
+ h->transMethod == CFGTBL_Trans_Performant ?
+ "performant" : "simple");
+}
+
/* Enqueuing and dequeuing functions for cmdlists. */
static inline void addQ(struct list_head *list, struct CommandList *c)
{
@@ -3768,7 +3785,6 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
h->pdev = pdev;
h->busy_initializing = 1;
h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
- printk(KERN_WARNING "hpsa_simple_mode is %d\n", hpsa_simple_mode);
INIT_LIST_HEAD(&h->cmpQ);
INIT_LIST_HEAD(&h->reqQ);
spin_lock_init(&h->lock);

2011-02-15 21:33:17

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 6/6] hpsa: fix bad comparison

From: Dan Carpenter <[email protected]>

'!' has higher precedence than '&'. CFGTBL_ChangeReq is 0x1 so the
original code is equivelent to if (!doorbell_value) {...

Signed-off-by: Dan Carpenter <[email protected]>
Acked-by: Stephen M. Cameron <[email protected]>
---
drivers/scsi/hpsa.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index eb6938f..c30591f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3614,7 +3614,7 @@ static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
spin_lock_irqsave(&h->lock, flags);
doorbell_value = readl(h->vaddr + SA5_DOORBELL);
spin_unlock_irqrestore(&h->lock, flags);
- if (!doorbell_value & CFGTBL_ChangeReq)
+ if (!(doorbell_value & CFGTBL_ChangeReq))
break;
/* delay and try again */
usleep_range(10000, 20000);

2011-02-15 21:33:04

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 1/6] hpsa: do not re-order commands in internal queues

From: Stephen M. Cameron <[email protected]>

Driver's internal queues should be FIFO, not LIFO.
This is a port of an almost identical patch from cciss by Jens Axboe.

Signed-off-by: Stephen M. Cameron <[email protected]>
---
drivers/scsi/hpsa.c | 23 +++++++++++------------
drivers/scsi/hpsa.h | 4 ++--
drivers/scsi/hpsa_cmd.h | 2 +-
3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 959eeb2..0f40de2 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -314,9 +314,9 @@ static ssize_t host_show_commands_outstanding(struct device *dev,
}

/* Enqueuing and dequeuing functions for cmdlists. */
-static inline void addQ(struct hlist_head *list, struct CommandList *c)
+static inline void addQ(struct list_head *list, struct CommandList *c)
{
- hlist_add_head(&c->list, list);
+ list_add_tail(&c->list, list);
}

static inline u32 next_command(struct ctlr_info *h)
@@ -366,9 +366,9 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,

static inline void removeQ(struct CommandList *c)
{
- if (WARN_ON(hlist_unhashed(&c->list)))
+ if (WARN_ON(list_empty(&c->list)))
return;
- hlist_del_init(&c->list);
+ list_del_init(&c->list);
}

static inline int is_hba_lunid(unsigned char scsi3addr[])
@@ -2228,7 +2228,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)

c->cmdindex = i;

- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2266,7 +2266,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
}
memset(c->err_info, 0, sizeof(*c->err_info));

- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2837,8 +2837,8 @@ static void start_io(struct ctlr_info *h)
{
struct CommandList *c;

- while (!hlist_empty(&h->reqQ)) {
- c = hlist_entry(h->reqQ.first, struct CommandList, list);
+ 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))) {
dev_warn(&h->pdev->dev, "fifo full\n");
@@ -2929,10 +2929,9 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
{
u32 tag;
struct CommandList *c = NULL;
- struct hlist_node *tmp;

tag = hpsa_tag_discard_error_bits(raw_tag);
- hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+ list_for_each_entry(c, &h->cmpQ, list) {
if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
finish_cmd(c, raw_tag);
return next_command(h);
@@ -3761,8 +3760,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,

h->pdev = pdev;
h->busy_initializing = 1;
- INIT_HLIST_HEAD(&h->cmpQ);
- INIT_HLIST_HEAD(&h->reqQ);
+ INIT_LIST_HEAD(&h->cmpQ);
+ INIT_LIST_HEAD(&h->reqQ);
spin_lock_init(&h->lock);
spin_lock_init(&h->scan_lock);
rc = hpsa_pci_init(h);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 074d237..e898193 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -75,8 +75,8 @@ struct ctlr_info {
struct access_method access;

/* queue and queue Info */
- struct hlist_head reqQ;
- struct hlist_head cmpQ;
+ struct list_head reqQ;
+ struct list_head cmpQ;
unsigned int Qdepth;
unsigned int maxQsinceinit;
unsigned int maxSG;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 7910c14..785abdd 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -292,7 +292,7 @@ struct CommandList {
struct ctlr_info *h;
int cmd_type;
long cmdindex;
- struct hlist_node list;
+ struct list_head list;
struct request *rq;
struct completion *waiting;
void *scsi_cmd;

2011-02-15 21:33:56

by Stephen M. Cameron

[permalink] [raw]
Subject: [PATCH 4/6] hpsa: Inform controller we are using 32-bit tags.

From: Stephen M. Cameron <[email protected]>

Controller will transfer only 32-bits on completion if it
knows we are only using 32-bit tags. Also, some newer controllers
apparently (and erroneously) require that we only use 32-bit tags,
and that we inform the controller of this.

Signed-off-by: Stephen M. Cameron <[email protected]>
---
drivers/scsi/hpsa.c | 24 +++++++++++++-----------
drivers/scsi/hpsa_cmd.h | 1 +
2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 563d439..a778cb1 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -326,7 +326,7 @@ static ssize_t host_show_transport_mode(struct device *dev,

h = shost_to_hba(shost);
return snprintf(buf, 20, "%s\n",
- h->transMethod == CFGTBL_Trans_Performant ?
+ h->transMethod & CFGTBL_Trans_Performant ?
"performant" : "simple");
}

@@ -340,7 +340,7 @@ static inline u32 next_command(struct ctlr_info *h)
{
u32 a;

- if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+ if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
return h->access.command_completed(h);

if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
@@ -364,7 +364,7 @@ static inline u32 next_command(struct ctlr_info *h)
*/
static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
{
- if (likely(h->transMethod == CFGTBL_Trans_Performant))
+ if (likely(h->transMethod & CFGTBL_Trans_Performant))
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
}

@@ -2924,7 +2924,7 @@ static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
{
#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
#define HPSA_SIMPLE_ERROR_BITS 0x03
- if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+ if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
return tag & ~HPSA_SIMPLE_ERROR_BITS;
return tag & ~HPSA_PERF_ERROR_BITS;
}
@@ -3640,6 +3640,7 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
"unable to get board into simple mode\n");
return -ENODEV;
}
+ h->transMethod = CFGTBL_Trans_Simple;
return 0;
}

@@ -4025,7 +4026,8 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}

-static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
+ u32 use_short_tags)
{
int i;
unsigned long register_value;
@@ -4073,7 +4075,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
writel(0, &h->transtable->RepQCtrAddrHigh32);
writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
writel(0, &h->transtable->RepQAddr0High32);
- writel(CFGTBL_Trans_Performant,
+ writel(CFGTBL_Trans_Performant | use_short_tags,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
@@ -4083,6 +4085,9 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
" performant mode\n");
return;
}
+ /* Change the access methods to the performant access methods */
+ h->access = SA5_performant_access;
+ h->transMethod = CFGTBL_Trans_Performant;
}

static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
@@ -4111,11 +4116,8 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|| (h->blockFetchTable == NULL))
goto clean_up;

- hpsa_enter_performant_mode(h);
-
- /* Change the access methods to the performant access methods */
- h->access = SA5_performant_access;
- h->transMethod = CFGTBL_Trans_Performant;
+ hpsa_enter_performant_mode(h,
+ trans_support & CFGTBL_Trans_use_short_tags);

return;

diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 785abdd..1846490 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -104,6 +104,7 @@

#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
+#define CFGTBL_Trans_use_short_tags 0x20000000l

#define CFGTBL_BusType_Ultra2 0x00000001l
#define CFGTBL_BusType_Ultra3 0x00000002l