* [PATCH 01/41] hpsa: revert bring logical drives online when format completes
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 02/41] hpsa: revert hide logical drives with format in progress from linux Stephen M. Cameron
` (39 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
This relies on a kernel thread which I wish to remove and
replace with a work queue based solution.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 128 ---------------------------------------------------
drivers/scsi/hpsa.h | 13 -----
2 files changed, 1 insertions(+), 140 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 604f5d0..06cb802 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -220,8 +220,6 @@ 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 unsigned char hpsa_format_in_progress(struct ctlr_info *h,
- unsigned char scsi3addr[]);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
@@ -946,112 +944,6 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_NOT_FOUND;
}
-#define OFFLINE_DEVICE_POLL_INTERVAL (120 * HZ)
-static int hpsa_offline_device_thread(void *v)
-{
- struct ctlr_info *h = v;
- unsigned long flags;
- struct offline_device_entry *d;
- unsigned char need_rescan = 0;
- struct list_head *this, *tmp;
-
- while (1) {
- schedule_timeout_interruptible(OFFLINE_DEVICE_POLL_INTERVAL);
- if (kthread_should_stop())
- break;
-
- /* Check if any of the offline devices have become ready */
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_for_each_safe(this, tmp, &h->offline_device_list) {
- d = list_entry(this, struct offline_device_entry,
- offline_list);
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- if (!hpsa_format_in_progress(h, d->scsi3addr)) {
- need_rescan = 1;
- goto do_rescan;
- }
- spin_lock_irqsave(&h->offline_device_lock, flags);
- }
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- }
-
-do_rescan:
-
- /* Remove all entries from the list and rescan and exit this thread.
- * If there are still offline devices, the rescan will make a new list
- * and create a new offline device monitor thread.
- */
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_for_each_safe(this, tmp, &h->offline_device_list) {
- d = list_entry(this, struct offline_device_entry, offline_list);
- list_del_init(this);
- kfree(d);
- }
- h->offline_device_monitor = NULL;
- h->offline_device_thread_state = OFFLINE_DEVICE_THREAD_STOPPED;
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- if (need_rescan)
- hpsa_scan_start(h->scsi_host);
- return 0;
-}
-
-static void hpsa_monitor_offline_device(struct ctlr_info *h,
- unsigned char scsi3addr[])
-{
- struct offline_device_entry *device;
- unsigned long flags;
-
- /* Check to see if device is already on the list */
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_for_each_entry(device, &h->offline_device_list, offline_list) {
- if (memcmp(device->scsi3addr, scsi3addr,
- sizeof(device->scsi3addr)) == 0) {
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- return;
- }
- }
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
-
- /* Device is not on the list, add it. */
- device = kmalloc(sizeof(*device), GFP_KERNEL);
- if (!device) {
- dev_warn(&h->pdev->dev, "out of memory in %s\n", __func__);
- return;
- }
- memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_add_tail(&device->offline_list, &h->offline_device_list);
- if (h->offline_device_thread_state == OFFLINE_DEVICE_THREAD_STOPPED) {
- h->offline_device_thread_state = OFFLINE_DEVICE_THREAD_RUNNING;
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- h->offline_device_monitor =
- kthread_run(hpsa_offline_device_thread, h, HPSA "-odm");
- spin_lock_irqsave(&h->offline_device_lock, flags);
- }
- if (!h->offline_device_monitor) {
- dev_warn(&h->pdev->dev, "failed to start offline device monitor thread.\n");
- h->offline_device_thread_state = OFFLINE_DEVICE_THREAD_STOPPED;
- }
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
-}
-
-static void stop_offline_device_monitor(struct ctlr_info *h)
-{
- unsigned long flags;
- int stop_thread;
-
- spin_lock_irqsave(&h->offline_device_lock, flags);
- stop_thread = (h->offline_device_thread_state ==
- OFFLINE_DEVICE_THREAD_RUNNING);
- if (stop_thread)
- /* STOPPING state prevents new thread from starting. */
- h->offline_device_thread_state =
- OFFLINE_DEVICE_THREAD_STOPPING;
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- if (stop_thread)
- kthread_stop(h->offline_device_monitor);
-}
-
static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
@@ -1124,10 +1016,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
*/
if (sd[i]->format_in_progress) {
dev_info(&h->pdev->dev,
- "c%db%dt%dl%d: Logical drive parity initialization, erase or format in progress\n",
- h->scsi_host->host_no,
- sd[i]->bus, sd[i]->target, sd[i]->lun);
- dev_info(&h->pdev->dev, "c%db%dt%dl%d: temporarily offline\n",
+ "Logical drive format in progress, device c%db%dt%dl%d offline.\n",
h->scsi_host->host_no,
sd[i]->bus, sd[i]->target, sd[i]->lun);
continue;
@@ -1151,17 +1040,6 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
}
spin_unlock_irqrestore(&h->devlock, flags);
- /* Monitor devices which are NOT READY, FORMAT IN PROGRESS to be
- * brought online later. This must be done without holding h->devlock,
- * so don't touch h->dev[]
- */
- for (i = 0; i < nsds; i++) {
- if (!sd[i]) /* if already added above. */
- continue;
- if (sd[i]->format_in_progress)
- hpsa_monitor_offline_device(h, sd[i]->scsi3addr);
- }
-
/* Don't notify scsi mid layer of any changes the first time through
* (or if there are no changes) scsi_scan_host will do it later the
* first time through.
@@ -5066,10 +4944,8 @@ reinit_after_soft_reset:
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->scan_lock);
- spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->passthru_count_lock);
rc = hpsa_pci_init(h);
if (rc != 0)
@@ -5078,7 +4954,6 @@ reinit_after_soft_reset:
sprintf(h->devname, HPSA "%d", number_of_controllers);
h->ctlr = number_of_controllers;
number_of_controllers++;
- h->offline_device_thread_state = OFFLINE_DEVICE_THREAD_STOPPED;
/* configure PCI DMA stuff */
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -5257,7 +5132,6 @@ static void hpsa_remove_one(struct pci_dev *pdev)
}
h = pci_get_drvdata(pdev);
stop_controller_lockup_detector(h);
- stop_offline_device_monitor(h);
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
iounmap(h->vaddr);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index bea2365..04074f5 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -161,20 +161,7 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TASK (1 << 23)
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
- spinlock_t offline_device_lock;
- struct list_head offline_device_list;
- struct task_struct *offline_device_monitor;
- unsigned char offline_device_thread_state;
-#define OFFLINE_DEVICE_THREAD_STOPPED 0
-#define OFFLINE_DEVICE_THREAD_STOPPING 1
-#define OFFLINE_DEVICE_THREAD_RUNNING 2
};
-
-struct offline_device_entry {
- unsigned char scsi3addr[8];
- struct list_head offline_list;
-};
-
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
#define HPSA_RESET_TYPE_CONTROLLER 0x00
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 02/41] hpsa: revert hide logical drives with format in progress from linux
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 01/41] hpsa: revert bring logical drives online when format completes Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 03/41] hpsa: use workqueue instead of kernel thread for lockup detection Stephen M. Cameron
` (38 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
This relies on a kernel thread which I wish to replace with a
work queue based solution.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 50 ++------------------------------------------------
drivers/scsi/hpsa.h | 1 -
2 files changed, 2 insertions(+), 49 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 06cb802..91e2d83 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1008,20 +1008,6 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
for (i = 0; i < nsds; i++) {
if (!sd[i]) /* if already added above. */
continue;
-
- /* Don't add devices which are NOT READY, FORMAT IN PROGRESS
- * as the SCSI mid-layer does not handle such devices well.
- * It relentlessly loops sending TUR at 3Hz, then READ(10)
- * at 160Hz, and prevents the system from coming up.
- */
- if (sd[i]->format_in_progress) {
- dev_info(&h->pdev->dev,
- "Logical drive format in progress, device c%db%dt%dl%d offline.\n",
- h->scsi_host->host_no,
- sd[i]->bus, sd[i]->target, sd[i]->lun);
- continue;
- }
-
device_change = hpsa_scsi_find_entry(sd[i], h->dev,
h->ndevices, &entry);
if (device_change == DEVICE_NOT_FOUND) {
@@ -1727,34 +1713,6 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
device->lun = lun;
}
-static unsigned char hpsa_format_in_progress(struct ctlr_info *h,
- unsigned char scsi3addr[])
-{
- struct CommandList *c;
- unsigned char *sense, sense_key, asc, ascq;
-#define ASC_LUN_NOT_READY 0x04
-#define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04
-
-
- c = cmd_special_alloc(h);
- if (!c)
- return 0;
- fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD);
- hpsa_scsi_do_simple_cmd_core(h, c);
- sense = c->err_info->SenseInfo;
- sense_key = sense[2];
- asc = sense[12];
- ascq = sense[13];
- if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
- c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION &&
- sense_key == NOT_READY &&
- asc == ASC_LUN_NOT_READY &&
- ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS)
- return 1;
- cmd_special_free(h, c);
- return 0;
-}
-
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)
@@ -1793,14 +1751,10 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->device_id));
if (this_device->devtype == TYPE_DISK &&
- is_logical_dev_addr_mode(scsi3addr)) {
+ is_logical_dev_addr_mode(scsi3addr))
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
- this_device->format_in_progress =
- hpsa_format_in_progress(h, scsi3addr);
- } else {
+ else
this_device->raid_level = RAID_UNKNOWN;
- this_device->format_in_progress = 0;
- }
if (is_OBDR_device) {
/* See if this is a One-Button-Disaster-Recovery device
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 04074f5..5f3f72f 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -46,7 +46,6 @@ struct hpsa_scsi_dev_t {
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
- unsigned char format_in_progress;
};
struct reply_pool {
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 03/41] hpsa: use workqueue instead of kernel thread for lockup detection
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 01/41] hpsa: revert bring logical drives online when format completes Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 02/41] hpsa: revert hide logical drives with format in progress from linux Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 04/41] hpsa: rename scsi prefetch field Stephen M. Cameron
` (37 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Much simpler and avoids races starting/stopping the thread.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 103 +++++++++++++--------------------------------------
drivers/scsi/hpsa.h | 3 +
2 files changed, 28 insertions(+), 78 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 91e2d83..f929875 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -168,10 +168,6 @@ static struct board_type products[] = {
static int number_of_controllers;
-static struct list_head hpsa_ctlr_list = LIST_HEAD_INIT(hpsa_ctlr_list);
-static spinlock_t lockup_detector_lock;
-static struct task_struct *hpsa_lockup_detector;
-
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);
@@ -4716,16 +4712,6 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
kfree(h);
}
-static void remove_ctlr_from_lockup_detector_list(struct ctlr_info *h)
-{
- assert_spin_locked(&lockup_detector_lock);
- if (!hpsa_lockup_detector)
- return;
- if (h->lockup_detected)
- return; /* already stopped the lockup detector */
- list_del(&h->lockup_list);
-}
-
/* Called when controller lockup detected. */
static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)
{
@@ -4744,8 +4730,6 @@ static void controller_lockup_detected(struct ctlr_info *h)
{
unsigned long flags;
- assert_spin_locked(&lockup_detector_lock);
- remove_ctlr_from_lockup_detector_list(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_lock_irqsave(&h->lock, flags);
h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
@@ -4765,7 +4749,6 @@ static void detect_controller_lockup(struct ctlr_info *h)
u32 heartbeat;
unsigned long flags;
- assert_spin_locked(&lockup_detector_lock);
now = get_jiffies_64();
/* If we've received an interrupt recently, we're ok. */
if (time_after64(h->last_intr_timestamp +
@@ -4795,68 +4778,22 @@ static void detect_controller_lockup(struct ctlr_info *h)
h->last_heartbeat_timestamp = now;
}
-static int detect_controller_lockup_thread(void *notused)
-{
- struct ctlr_info *h;
- unsigned long flags;
-
- while (1) {
- struct list_head *this, *tmp;
-
- schedule_timeout_interruptible(HEARTBEAT_SAMPLE_INTERVAL);
- if (kthread_should_stop())
- break;
- spin_lock_irqsave(&lockup_detector_lock, flags);
- list_for_each_safe(this, tmp, &hpsa_ctlr_list) {
- h = list_entry(this, struct ctlr_info, lockup_list);
- detect_controller_lockup(h);
- }
- spin_unlock_irqrestore(&lockup_detector_lock, flags);
- }
- return 0;
-}
-
-static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h)
+static void hpsa_monitor_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
-
- h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
- spin_lock_irqsave(&lockup_detector_lock, flags);
- list_add_tail(&h->lockup_list, &hpsa_ctlr_list);
- spin_unlock_irqrestore(&lockup_detector_lock, flags);
-}
-
-static void start_controller_lockup_detector(struct ctlr_info *h)
-{
- /* Start the lockup detector thread if not already started */
- if (!hpsa_lockup_detector) {
- spin_lock_init(&lockup_detector_lock);
- hpsa_lockup_detector =
- kthread_run(detect_controller_lockup_thread,
- NULL, HPSA);
- }
- if (!hpsa_lockup_detector) {
- dev_warn(&h->pdev->dev,
- "Could not start lockup detector thread\n");
+ struct ctlr_info *h = container_of(to_delayed_work(work),
+ struct ctlr_info, monitor_ctlr_work);
+ detect_controller_lockup(h);
+ if (h->lockup_detected)
+ return;
+ spin_lock_irqsave(&h->lock, flags);
+ if (h->remove_in_progress) {
+ spin_unlock_irqrestore(&h->lock, flags);
return;
}
- add_ctlr_to_lockup_detector_list(h);
-}
-
-static void stop_controller_lockup_detector(struct ctlr_info *h)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lockup_detector_lock, flags);
- remove_ctlr_from_lockup_detector_list(h);
- /* If the list of ctlr's to monitor is empty, stop the thread */
- if (list_empty(&hpsa_ctlr_list)) {
- spin_unlock_irqrestore(&lockup_detector_lock, flags);
- kthread_stop(hpsa_lockup_detector);
- spin_lock_irqsave(&lockup_detector_lock, flags);
- hpsa_lockup_detector = NULL;
- }
- spin_unlock_irqrestore(&lockup_detector_lock, flags);
+ schedule_delayed_work(&h->monitor_ctlr_work,
+ h->heartbeat_sample_interval);
+ spin_unlock_irqrestore(&h->lock, flags);
}
static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -5004,7 +4941,12 @@ reinit_after_soft_reset:
hpsa_hba_inquiry(h);
hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
- start_controller_lockup_detector(h);
+
+ /* Monitor the controller for firmware lockups */
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
+ INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
+ schedule_delayed_work(&h->monitor_ctlr_work,
+ h->heartbeat_sample_interval);
return 0;
clean4:
@@ -5079,13 +5021,20 @@ static void hpsa_free_device_info(struct ctlr_info *h)
static void hpsa_remove_one(struct pci_dev *pdev)
{
struct ctlr_info *h;
+ unsigned long flags;
if (pci_get_drvdata(pdev) == NULL) {
dev_err(&pdev->dev, "unable to remove device\n");
return;
}
h = pci_get_drvdata(pdev);
- stop_controller_lockup_detector(h);
+
+ /* 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);
+ spin_unlock_irqrestore(&h->lock, flags);
+
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
iounmap(h->vaddr);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 5f3f72f..01c3283 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -135,7 +135,8 @@ struct ctlr_info {
u32 heartbeat_sample_interval;
atomic_t firmware_flash_in_progress;
u32 lockup_detected;
- struct list_head lockup_list;
+ 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];
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 04/41] hpsa: rename scsi prefetch field
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (2 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 03/41] hpsa: use workqueue instead of kernel thread for lockup detection Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 05/41] hpsa: enable unit attention reporting Stephen M. Cameron
` (36 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
The field contains more bits than just the one
to indicate whether scsi prefetch should be turned on.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 14 +++++++-------
drivers/scsi/hpsa_cmd.h | 3 ++-
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index f929875..25afeb4 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -4382,15 +4382,15 @@ static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
return true;
}
-/* Need to enable prefetch in the SCSI core for 6400 in x86 */
-static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h)
+static inline void hpsa_set_driver_support_bits(struct ctlr_info *h)
{
#ifdef CONFIG_X86
- u32 prefetch;
+ /* Need to enable prefetch in the SCSI core for 6400 in x86 */
+ u32 driver_support;
- prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
- prefetch |= 0x100;
- writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
+ driver_support = readl(&(h->cfgtable->driver_support));
+ driver_support |= ENABLE_SCSI_PREFETCH;
+ writel(driver_support, &(h->cfgtable->driver_support));
#endif
}
@@ -4501,7 +4501,7 @@ static int hpsa_pci_init(struct ctlr_info *h)
err = -ENODEV;
goto err_out_free_res;
}
- hpsa_enable_scsi_prefetch(h);
+ hpsa_set_driver_support_bits(h);
hpsa_p600_dma_prefetch_quirk(h);
err = hpsa_enter_simple_mode(h);
if (err)
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index a894f2e..5158709 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -356,7 +356,8 @@ struct CfgTable {
u32 TransMethodOffset;
u8 ServerName[16];
u32 HeartBeat;
- u32 SCSI_Prefetch;
+ u32 driver_support;
+#define ENABLE_SCSI_PREFETCH 0x100
u32 MaxScatterGatherElements;
u32 MaxLogicalUnits;
u32 MaxPhysicalDevices;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 05/41] hpsa: enable unit attention reporting
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (3 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 04/41] hpsa: rename scsi prefetch field Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 06/41] hpsa: do not require board "not ready" status after hard reset Stephen M. Cameron
` (35 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
This used to be the default, but at some point the firmware guys
changed the default and I failed to notice. Now to get unit
attention notifications, you must twiddle a bit indicating you
want them.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 7 ++++---
drivers/scsi/hpsa_cmd.h | 1 +
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 25afeb4..d65567a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -4384,14 +4384,15 @@ static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
static inline void hpsa_set_driver_support_bits(struct ctlr_info *h)
{
-#ifdef CONFIG_X86
- /* Need to enable prefetch in the SCSI core for 6400 in x86 */
u32 driver_support;
driver_support = readl(&(h->cfgtable->driver_support));
+#ifdef CONFIG_X86
+ /* Need to enable prefetch in the SCSI core for 6400 in x86 */
driver_support |= ENABLE_SCSI_PREFETCH;
- writel(driver_support, &(h->cfgtable->driver_support));
#endif
+ driver_support |= ENABLE_UNIT_ATTN;
+ writel(driver_support, &(h->cfgtable->driver_support));
}
/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 5158709..bfc8c4e 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -358,6 +358,7 @@ struct CfgTable {
u32 HeartBeat;
u32 driver_support;
#define ENABLE_SCSI_PREFETCH 0x100
+#define ENABLE_UNIT_ATTN 0x01
u32 MaxScatterGatherElements;
u32 MaxLogicalUnits;
u32 MaxPhysicalDevices;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 06/41] hpsa: do not require board "not ready" status after hard reset
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (4 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 05/41] hpsa: enable unit attention reporting Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 07/41] hpsa: allow SCSI mid layer to handle unit attention Stephen M. Cameron
` (34 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Immediately following a hard board reset, There are some
mandatory delays during which we must not access the board
and during which we might miss the "not ready" status,
therefore it is a mistake to look for and expect to see
the "not ready" status.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 17 -----------------
1 files changed, 0 insertions(+), 17 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index d65567a..ef7614f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -4048,23 +4048,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
need a little pause here */
msleep(HPSA_POST_RESET_PAUSE_MSECS);
- if (!use_doorbell) {
- /* Wait for board to become not ready, then ready.
- * (if we used the doorbell, then we already waited 5 secs
- * so the "not ready" state is already gone by so we
- * won't catch it.)
- */
- dev_info(&pdev->dev, "Waiting for board to reset.\n");
- rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
- if (rc) {
- dev_warn(&pdev->dev,
- "failed waiting for board to reset."
- " Will try soft reset.\n");
- /* Not expected, but try soft reset later */
- rc = -ENOTSUPP;
- goto unmap_cfgtable;
- }
- }
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
if (rc) {
dev_warn(&pdev->dev,
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 07/41] hpsa: allow SCSI mid layer to handle unit attention
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (5 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 06/41] hpsa: do not require board "not ready" status after hard reset Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 08/41] hpsa: use extended report luns command for HP SSD SmartPath Stephen M. Cameron
` (33 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Matt Gates <matthew.gates@hp.com>
We were clobbering the SCSI status and setting
cmd->result = DID_SOFT_ERROR << 16; to get a retry,
but better to let the mid layer handle the unit
attention.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index ef7614f..6b53170 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1241,10 +1241,8 @@ static void complete_scsi_command(struct CommandList *cp)
}
if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
- if (check_for_unit_attention(h, cp)) {
- cmd->result = DID_SOFT_ERROR << 16;
+ if (check_for_unit_attention(h, cp))
break;
- }
if (sense_key == ILLEGAL_REQUEST) {
/*
* SCSI REPORT_LUNS is commonly unsupported on
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 08/41] hpsa: use extended report luns command for HP SSD SmartPath
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (6 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 07/41] hpsa: allow SCSI mid layer to handle unit attention Stephen M. Cameron
@ 2014-01-15 22:36 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 09/41] hpsa: mark last scatter gather element as the last Stephen M. Cameron
` (32 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:36 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Matt Gates <matthew.gates@hp.com>
There is an extended report luns command which contains
additional information about physical devices. In particular
we need to get the physical device handle so we can use an
alternate i/o path for fast physical devices like SSDs so
we can speed up certain i/o's by bypassing the RAID stack
code in the controller firmware.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 13 ++++++++-----
drivers/scsi/hpsa_cmd.h | 1 +
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6b53170..7eef25c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1888,11 +1888,12 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
struct ReportLUNdata *physdev, u32 *nphysicals,
struct ReportLUNdata *logdev, u32 *nlogicals)
{
- if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) {
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize,
+ HPSA_REPORT_PHYS_EXTENDED)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
+ *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,
@@ -1923,7 +1924,8 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
}
u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
- int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list,
+ int nphysicals, int nlogicals,
+ struct ReportExtendedLUNdata *physdev_list,
struct ReportLUNdata *logdev_list)
{
/* Helper function, figure out where the LUN ID info is coming from
@@ -1959,7 +1961,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
* tell which devices we already know about, vs. new
* devices, vs. disappearing devices.
*/
- struct ReportLUNdata *physdev_list = NULL;
+ struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
@@ -1982,7 +1984,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
}
memset(lunzerobits, 0, sizeof(lunzerobits));
- if (hpsa_gather_lun_info(h, reportlunsize, physdev_list, &nphysicals,
+ if (hpsa_gather_lun_info(h, reportlunsize,
+ (struct ReportLUNdata *) physdev_list, &nphysicals,
logdev_list, &nlogicals))
goto out;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index bfc8c4e..3f96b66 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -162,6 +162,7 @@ struct InquiryData {
#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
+#define HPSA_REPORT_PHYS_EXTENDED 0x02
struct ReportLUNdata {
u8 LUNListLength[4];
u32 reserved;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 09/41] hpsa: mark last scatter gather element as the last
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (7 preceding siblings ...)
2014-01-15 22:36 ` [PATCH 08/41] hpsa: use extended report luns command for HP SSD SmartPath Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 10/41] hpsa: add support for 'fastpath' i/o Stephen M. Cameron
` (31 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Matt Gates <matt.gates@hp.com>
This is normally optional, but for SSD Smart Path support (in
subsequent patches) it is required.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 8 ++++----
drivers/scsi/hpsa_cmd.h | 1 +
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 7eef25c..fd8158c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1438,6 +1438,7 @@ static int hpsa_map_one(struct pci_dev *pdev,
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->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
return 0;
@@ -2139,7 +2140,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
curr_sg->Len = len;
- curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST;
curr_sg++;
}
@@ -3041,7 +3042,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
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 = 0; /* we are not chaining*/
+ c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
if (iocommand.buf_size > 0)
@@ -3171,8 +3172,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[i].Addr.lower = temp64.val32.lower;
c->SG[i].Addr.upper = temp64.val32.upper;
c->SG[i].Len = buff_size[i];
- /* we are not chaining */
- c->SG[i].Ext = 0;
+ c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST;
}
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 3f96b66..22cf799 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -25,6 +25,7 @@
#define SENSEINFOBYTES 32 /* may vary between hbas */
#define SG_ENTRIES_IN_CMD 32 /* Max SG entries excluding chain blocks */
#define HPSA_SG_CHAIN 0x80000000
+#define HPSA_SG_LAST 0x40000000
#define MAXREPLYQS 256
/* Command Status value */
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 10/41] hpsa: add support for 'fastpath' i/o
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (8 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 09/41] hpsa: mark last scatter gather element as the last Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 11/41] hpsa: only allow REQ_TYPE_FS to use fast path Stephen M. Cameron
` (30 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Matt Gates <matthew.gates@hp.com>
For certain i/o's to certain devices (unmasked physical disks) we
can bypass the RAID stack firmware and do the i/o to the device
directly and it will be faster.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 296 ++++++++++++++++++++++++++++++++++++++++++++---
drivers/scsi/hpsa.h | 51 ++++++++
drivers/scsi/hpsa_cmd.h | 60 ++++++++++
3 files changed, 388 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index fd8158c..56b0b48 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -204,7 +204,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
struct CommandList *c);
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
- int nsgs, int *bucket_map);
+ int nsgs, int min_blocks, int *bucket_map);
static void hpsa_put_ctlr_into_performant_mode(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,
@@ -570,6 +570,9 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
struct reply_pool *rq = &h->reply_queue[q];
unsigned long flags;
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return h->access.command_completed(h, q);
+
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
return h->access.command_completed(h, q);
@@ -1203,7 +1206,8 @@ static void complete_scsi_command(struct CommandList *cp)
h = cp->h;
scsi_dma_unmap(cmd); /* undo the DMA mappings */
- if (cp->Header.SGTotal > h->max_cmd_sg_entries)
+ if ((cp->cmd_type == CMD_SCSI) &&
+ (cp->Header.SGTotal > h->max_cmd_sg_entries))
hpsa_unmap_sg_chain_block(h, cp);
cmd->result = (DID_OK << 16); /* host byte */
@@ -1227,6 +1231,19 @@ static void complete_scsi_command(struct CommandList *cp)
return;
}
+ /* For I/O accelerator commands, copy over some fields to the normal
+ * CISS header used below for error handling.
+ */
+ if (cp->cmd_type == CMD_IOACCEL1) {
+ 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;
+ memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
+ memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
+ }
+
/* an error has occurred */
switch (ei->CommandStatus) {
@@ -2070,6 +2087,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
case TYPE_DISK:
if (i < nphysicals)
break;
+ memcpy(&this_device->ioaccel_handle,
+ &lunaddrbytes[20],
+ sizeof(this_device->ioaccel_handle));
ncurrent++;
break;
case TYPE_TAPE:
@@ -2164,6 +2184,104 @@ sglist_finished:
return 0;
}
+/*
+ * Queue a command to the I/O accelerator path.
+ * This method does not currently support S/G chaining.
+ */
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
+ unsigned int len;
+ unsigned int total_len = 0;
+ struct scatterlist *sg;
+ u64 addr64;
+ int use_sg, i;
+ struct SGDescriptor *curr_sg;
+ u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
+
+ BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
+
+ c->cmd_type = CMD_IOACCEL1;
+
+ /* Adjust the DMA address to point to the accelerated command buffer */
+ c->busaddr = (u32) h->ioaccel_cmd_pool_dhandle +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ 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++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_IN;
+ break;
+ case DMA_NONE:
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ }
+
+ /* Fill out the command structure to submit */
+ cp->dev_handle = dev->ioaccel_handle;
+ cp->transfer_len = total_len;
+ cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ |
+ (cmd->cmd_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
+ cp->control = control;
+ memcpy(cp->CDB, cmd->cmnd, cmd->cmd_len);
+ memcpy(cp->CISS_LUN, dev->scsi3addr, 8);
+
+ /* 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;
+
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit (bit 0)
+ * - pull count (bits 1-3)
+ * - command type (bits 4-6)
+ */
+ c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[use_sg] << 1) |
+ IOACCEL1_BUSADDR_CMDTYPE;
+
+ /* execute command (bypassing cmd queue if possible) */
+ if (unlikely(h->access.fifo_full(h)))
+ enqueue_cmd_and_start_io(h, c);
+ else
+ h->access.submit_command(h, c);
+ return 0;
+}
static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
@@ -2207,6 +2325,14 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
+
+ /* Call alternate submit routine for I/O accelerated commands */
+ if ((likely(h->transMethod & CFGTBL_Trans_io_accel1)) &&
+ (dev->ioaccel_handle) &&
+ ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)) &&
+ (scsi_sg_count(cmd) <= IOACCEL1_MAXSGENTRIES))
+ return hpsa_scsi_ioaccel_queue_command(h, c);
+
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);
@@ -2780,6 +2906,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
return NULL;
memset(c, 0, sizeof(*c));
+ c->cmd_type = CMD_SCSI;
c->cmdindex = -1;
c->err_info = pci_alloc_consistent(h->pdev, sizeof(*c->err_info),
@@ -3565,7 +3692,7 @@ static inline void finish_cmd(struct CommandList *c)
spin_unlock_irqrestore(&h->lock, flags);
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
- if (likely(c->cmd_type == CMD_SCSI))
+ if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
@@ -4585,6 +4712,10 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
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 int hpsa_request_irq(struct ctlr_info *h,
@@ -4684,6 +4815,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_cmd_pool(h);
+ kfree(h->ioaccel1_blockFetchTable);
kfree(h->blockFetchTable);
pci_free_consistent(h->pdev, h->reply_pool_size,
h->reply_pool, h->reply_pool_dhandle);
@@ -5037,6 +5169,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
h->reply_pool, h->reply_pool_dhandle);
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
+ kfree(h->ioaccel1_blockFetchTable);
kfree(h->hba_inquiry_data);
pci_disable_device(pdev);
pci_release_regions(pdev);
@@ -5077,20 +5210,17 @@ static struct pci_driver hpsa_pci_driver = {
* bits of the command address.
*/
static void calc_bucket_map(int bucket[], int num_buckets,
- int nsgs, int *bucket_map)
+ int nsgs, int min_blocks, int *bucket_map)
{
int i, j, b, size;
- /* even a command with 0 SGs requires 4 blocks */
-#define MINIMUM_TRANSFER_BLOCKS 4
-#define NUM_BUCKETS 8
/* Note, bucket_map must have nsgs+1 entries. */
for (i = 0; i <= nsgs; i++) {
/* Compute size of a command with i SG entries */
- size = i + MINIMUM_TRANSFER_BLOCKS;
+ size = i + min_blocks;
b = num_buckets; /* Assume the biggest bucket */
/* Find the bucket that is just big enough */
- for (j = 0; j < 8; j++) {
+ for (j = 0; j < num_buckets; j++) {
if (bucket[j] >= size) {
b = j;
break;
@@ -5101,10 +5231,16 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
+static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
{
int i;
unsigned long register_value;
+ unsigned long transMethod = CFGTBL_Trans_Performant |
+ (trans_support & CFGTBL_Trans_use_short_tags) |
+ CFGTBL_Trans_enable_directed_msix |
+ (trans_support & CFGTBL_Trans_io_accel1);
+
+ struct access_method access = SA5_performant_access;
/* This is a bit complicated. There are 8 registers on
* the controller which we write to to tell it 8 different
@@ -5136,7 +5272,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
- SG_ENTRIES_IN_CMD, h->blockFetchTable);
+ SG_ENTRIES_IN_CMD, 4, h->blockFetchTable);
for (i = 0; i < 8; i++)
writel(bft[i], &h->transtable->BlockFetch[i]);
@@ -5153,9 +5289,15 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
&h->transtable->RepQAddr[i].lower);
}
- writel(CFGTBL_Trans_Performant | use_short_tags |
- CFGTBL_Trans_enable_directed_msix,
- &(h->cfgtable->HostWrite.TransportRequest));
+ writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest));
+ /*
+ * enable outbound interrupt coalescing in accelerator mode;
+ */
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ access = SA5_ioaccel_mode1_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ }
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
@@ -5165,13 +5307,88 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
return;
}
/* Change the access methods to the performant access methods */
- h->access = SA5_performant_access;
- h->transMethod = CFGTBL_Trans_Performant;
+ h->access = access;
+ h->transMethod = transMethod;
+
+ if (!(trans_support & CFGTBL_Trans_io_accel1))
+ return;
+
+ /* Set up I/O accelerator mode */
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
+ h->reply_queue[i].current_entry =
+ readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
+ }
+ bft[7] = IOACCEL1_MAXSGENTRIES + 8;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), IOACCEL1_MAXSGENTRIES, 8,
+ h->ioaccel1_blockFetchTable);
+
+ /* initialize all reply queue entries to unused */
+ memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED,
+ h->reply_pool_size);
+
+ /* set all the constant fields in the accelerator command
+ * frames once at init time to save CPU cycles later.
+ */
+ for (i = 0; i < h->nr_cmds; i++) {
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
+
+ cp->function = IOACCEL1_FUNCTION_SCSIIO;
+ cp->err_info = (u32) (h->errinfo_pool_dhandle +
+ (i * sizeof(struct ErrorInfo)));
+ cp->err_info_len = sizeof(struct ErrorInfo);
+ cp->sgl_offset = IOACCEL1_SGLOFFSET;
+ 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;
+ }
+}
+
+static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
+{
+ /* Command structures must be aligned on a 128-byte boundary
+ * because the 7 lower bits of the address are used by the
+ * hardware.
+ */
+#define IOACCEL1_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %
+ IOACCEL1_COMMANDLIST_ALIGNMENT);
+ h->ioaccel_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
+ &(h->ioaccel_cmd_pool_dhandle));
+
+ h->ioaccel1_blockFetchTable =
+ kmalloc(((IOACCEL1_MAXSGENTRIES + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel_cmd_pool == NULL) ||
+ (h->ioaccel1_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool));
+ 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);
+ return 1;
}
static void 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;
if (hpsa_simple_mode)
@@ -5181,6 +5398,15 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
if (!(trans_support & PERFORMANT_MODE))
return;
+ /* 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_ioaccel_cmd_and_bft(h))
+ goto clean_up;
+ }
+
+ /* TODO, check that this next line h->nreply_queues is correct */
h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1;
hpsa_get_max_perf_mode_cmds(h);
/* Performant mode ring buffer and supporting data structures */
@@ -5203,9 +5429,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|| (h->blockFetchTable == NULL))
goto clean_up;
- hpsa_enter_performant_mode(h,
- trans_support & CFGTBL_Trans_use_short_tags);
-
+ hpsa_enter_performant_mode(h, trans_support);
return;
clean_up:
@@ -5229,5 +5453,39 @@ static void __exit hpsa_cleanup(void)
pci_unregister_driver(&hpsa_pci_driver);
}
+static void __attribute__((unused)) verify_offsets(void)
+{
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel1_cmd, member) != offset)
+
+ VERIFY_OFFSET(dev_handle, 0x00);
+ VERIFY_OFFSET(reserved1, 0x02);
+ VERIFY_OFFSET(function, 0x03);
+ VERIFY_OFFSET(reserved2, 0x04);
+ VERIFY_OFFSET(err_info, 0x0C);
+ VERIFY_OFFSET(reserved3, 0x10);
+ VERIFY_OFFSET(err_info_len, 0x12);
+ VERIFY_OFFSET(reserved4, 0x13);
+ VERIFY_OFFSET(sgl_offset, 0x14);
+ VERIFY_OFFSET(reserved5, 0x15);
+ VERIFY_OFFSET(transfer_len, 0x1C);
+ VERIFY_OFFSET(reserved6, 0x20);
+ VERIFY_OFFSET(io_flags, 0x24);
+ VERIFY_OFFSET(reserved7, 0x26);
+ VERIFY_OFFSET(LUN, 0x34);
+ VERIFY_OFFSET(control, 0x3C);
+ VERIFY_OFFSET(CDB, 0x40);
+ VERIFY_OFFSET(reserved8, 0x50);
+ VERIFY_OFFSET(host_context_flags, 0x60);
+ VERIFY_OFFSET(timeout_sec, 0x62);
+ VERIFY_OFFSET(ReplyQueue, 0x64);
+ VERIFY_OFFSET(reserved9, 0x65);
+ VERIFY_OFFSET(Tag, 0x68);
+ VERIFY_OFFSET(host_addr, 0x70);
+ VERIFY_OFFSET(CISS_LUN, 0x78);
+ VERIFY_OFFSET(SG, 0x78 + 8);
+#undef VERIFY_OFFSET
+}
+
module_init(hpsa_init);
module_exit(hpsa_cleanup);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 01c3283..c7865f3 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -46,6 +46,7 @@ struct hpsa_scsi_dev_t {
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
+ u32 ioaccel_handle;
};
struct reply_pool {
@@ -95,6 +96,8 @@ struct ctlr_info {
/* pointers to command and error info pool */
struct CommandList *cmd_pool;
dma_addr_t cmd_pool_dhandle;
+ struct io_accel1_cmd *ioaccel_cmd_pool;
+ dma_addr_t ioaccel_cmd_pool_dhandle;
struct ErrorInfo *errinfo_pool;
dma_addr_t errinfo_pool_dhandle;
unsigned long *cmd_pool_bits;
@@ -128,6 +131,7 @@ struct ctlr_info {
u8 nreply_queues;
dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
+ u32 *ioaccel1_blockFetchTable;
unsigned char *hba_inquiry_data;
u64 last_intr_timestamp;
u32 last_heartbeat;
@@ -387,6 +391,45 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h)
return register_value & SA5_OUTDB_STATUS_PERF_BIT;
}
+#define SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT 0x100
+
+static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h)
+{
+ unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS);
+
+ return (register_value & SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT) ?
+ true : false;
+}
+
+#define IOACCEL_MODE1_REPLY_QUEUE_INDEX 0x1A0
+#define IOACCEL_MODE1_PRODUCER_INDEX 0x1B8
+#define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC
+#define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL
+
+static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h,
+ u8 q)
+{
+ u64 register_value;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags;
+
+ BUG_ON(q >= h->nreply_queues);
+
+ register_value = rq->head[rq->current_entry];
+ if (register_value != IOACCEL_MODE1_REPLY_UNUSED) {
+ rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED;
+ if (++rq->current_entry == rq->size)
+ rq->current_entry = 0;
+ spin_lock_irqsave(&h->lock, flags);
+ h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
+ } else {
+ writel((q << 24) | rq->current_entry,
+ h->vaddr + IOACCEL_MODE1_CONSUMER_INDEX);
+ }
+ return (unsigned long) register_value;
+}
+
static struct access_method SA5_access = {
SA5_submit_command,
SA5_intr_mask,
@@ -395,6 +438,14 @@ static struct access_method SA5_access = {
SA5_completed,
};
+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,
+};
+
static struct access_method SA5_performant_access = {
SA5_submit_command,
SA5_performant_intr_mask,
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 22cf799..e682d2e 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -129,6 +129,7 @@
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
+#define CFGTBL_Trans_io_accel1 0x00000080l
#define CFGTBL_Trans_use_short_tags 0x20000000l
#define CFGTBL_Trans_enable_directed_msix (1 << 30)
@@ -285,6 +286,7 @@ struct ErrorInfo {
/* Command types */
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
+#define CMD_IOACCEL1 0x04
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
@@ -335,6 +337,63 @@ struct CommandList {
u8 pad[COMMANDLIST_PAD];
};
+/* Max S/G elements in I/O accelerator command */
+#define IOACCEL1_MAXSGENTRIES 24
+
+/*
+ * Structure for I/O accelerator (mode 1) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel1_cmd {
+ u16 dev_handle; /* 0x00 - 0x01 */
+ u8 reserved1; /* 0x02 */
+ u8 function; /* 0x03 */
+ u8 reserved2[8]; /* 0x04 - 0x0B */
+ u32 err_info; /* 0x0C - 0x0F */
+ u8 reserved3[2]; /* 0x10 - 0x11 */
+ u8 err_info_len; /* 0x12 */
+ u8 reserved4; /* 0x13 */
+ u8 sgl_offset; /* 0x14 */
+ u8 reserved5[7]; /* 0x15 - 0x1B */
+ u32 transfer_len; /* 0x1C - 0x1F */
+ u8 reserved6[4]; /* 0x20 - 0x23 */
+ u16 io_flags; /* 0x24 - 0x25 */
+ u8 reserved7[14]; /* 0x26 - 0x33 */
+ u8 LUN[8]; /* 0x34 - 0x3B */
+ u32 control; /* 0x3C - 0x3F */
+ u8 CDB[16]; /* 0x40 - 0x4F */
+ u8 reserved8[16]; /* 0x50 - 0x5F */
+ u16 host_context_flags; /* 0x60 - 0x61 */
+ u16 timeout_sec; /* 0x62 - 0x63 */
+ u8 ReplyQueue; /* 0x64 */
+ u8 reserved9[3]; /* 0x65 - 0x67 */
+ struct vals32 Tag; /* 0x68 - 0x6F */
+ struct vals32 host_addr; /* 0x70 - 0x77 */
+ u8 CISS_LUN[8]; /* 0x78 - 0x7F */
+ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
+};
+
+#define IOACCEL1_FUNCTION_SCSIIO 0x00
+#define IOACCEL1_SGLOFFSET 32
+
+#define IOACCEL1_IOFLAGS_IO_REQ 0x4000
+#define IOACCEL1_IOFLAGS_CDBLEN_MASK 0x001F
+#define IOACCEL1_IOFLAGS_CDBLEN_MAX 16
+
+#define IOACCEL1_CONTROL_NODATAXFER 0x00000000
+#define IOACCEL1_CONTROL_DATA_OUT 0x01000000
+#define IOACCEL1_CONTROL_DATA_IN 0x02000000
+#define IOACCEL1_CONTROL_TASKPRIO_MASK 0x00007800
+#define IOACCEL1_CONTROL_TASKPRIO_SHIFT 11
+#define IOACCEL1_CONTROL_SIMPLEQUEUE 0x00000000
+#define IOACCEL1_CONTROL_HEADOFQUEUE 0x00000100
+#define IOACCEL1_CONTROL_ORDEREDQUEUE 0x00000200
+#define IOACCEL1_CONTROL_ACA 0x00000400
+
+#define IOACCEL1_HCFLAGS_CISS_FORMAT 0x0013
+
+#define IOACCEL1_BUSADDR_CMDTYPE 0x00000060
+
/* Configuration Table Structure */
struct HostWrite {
u32 TransportRequest;
@@ -346,6 +405,7 @@ struct HostWrite {
#define SIMPLE_MODE 0x02
#define PERFORMANT_MODE 0x04
#define MEMQ_MODE 0x08
+#define IOACCEL_MODE_1 0x80
struct CfgTable {
u8 Signature[4];
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 11/41] hpsa: only allow REQ_TYPE_FS to use fast path
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (9 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 10/41] hpsa: add support for 'fastpath' i/o Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 12/41] hpsa: fix task management for mode-1 ioaccell path Stephen M. Cameron
` (29 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
When commands sent down the "fast path" fail, they must be re-tried down the
normal RAID path. We do this by kicking i/o's back to the scsi mid layer with
a DID_SOFT_ERROR status, which causes them to be retried. This won't work for
SG_IO's and other non REQ_TYPE_FS i/o's which could get kicked all the way back
to the application, which may have no idea that the command needs resubmitting
and likely no way to resubmit it in such a way the that driver can recognize it
as a resubmit and send it down the normal RAID path. So we just always send
non REQ_TYPE_FS i/o's down the normal RAID path, never down the "fast path".
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 56b0b48..81545a7 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2330,7 +2330,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
if ((likely(h->transMethod & CFGTBL_Trans_io_accel1)) &&
(dev->ioaccel_handle) &&
((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)) &&
- (scsi_sg_count(cmd) <= IOACCEL1_MAXSGENTRIES))
+ (scsi_sg_count(cmd) <= IOACCEL1_MAXSGENTRIES) &&
+ likely(cmd->request->cmd_type == REQ_TYPE_FS))
return hpsa_scsi_ioaccel_queue_command(h, c);
c->Header.ReplyQueue = 0; /* unused in simple mode */
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 12/41] hpsa: fix task management for mode-1 ioaccell path
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (10 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 11/41] hpsa: only allow REQ_TYPE_FS to use fast path Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 13/41] hpsa: add ioaccell mode 1 RAID offload support Stephen M. Cameron
` (28 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
For "mode 1" io accelerated commands, the command tag is in
a different location than for commands that go down the normal
RAID path, so the abort handler needs to take this into account.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 27 +++++++++++++++++++++------
1 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 81545a7..9b4f5ff 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2602,12 +2602,27 @@ static void swizzle_abort_tag(u8 *tag)
tag[7] = original_tag[4];
}
+static void hpsa_get_tag(struct ctlr_info *h,
+ struct CommandList *c, u32 *taglower, u32 *tagupper)
+{
+ 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;
+ } else {
+ *tagupper = c->Header.Tag.upper;
+ *taglower = c->Header.Tag.lower;
+ }
+}
+
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *abort, int swizzle)
{
int rc = IO_OK;
struct CommandList *c;
struct ErrorInfo *ei;
+ u32 tagupper, taglower;
c = cmd_special_alloc(h);
if (c == NULL) { /* trouble... */
@@ -2621,8 +2636,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
if (swizzle)
swizzle_abort_tag(&c->Request.CDB[4]);
hpsa_scsi_do_simple_cmd_core(h, c);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
- __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
+ __func__, tagupper, taglower);
/* no unmap needed here because no data xfer. */
ei = c->err_info;
@@ -2634,8 +2650,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
break;
default:
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
- __func__, abort->Header.Tag.upper,
- abort->Header.Tag.lower);
+ __func__, tagupper, taglower);
hpsa_scsi_interpret_error(c);
rc = -1;
break;
@@ -2747,6 +2762,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
char msg[256]; /* For debug messaging. */
int ml = 0;
+ u32 tagupper, taglower;
/* Find the controller of the command to be aborted */
h = sdev_to_hba(sc->device);
@@ -2779,9 +2795,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
msg);
return FAILED;
}
-
- ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
+ ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
as = (struct scsi_cmnd *) abort->scsi_cmd;
if (as != NULL)
ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 13/41] hpsa: add ioaccell mode 1 RAID offload support.
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (11 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 12/41] hpsa: fix task management for mode-1 ioaccell path Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 14/41] hpsa: update raid offload status on device rescan Stephen M. Cameron
` (27 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
This enables sending i/o's destined for RAID logical drives
which can be serviced by a single physical disk down a different,
faster i/o path directly to physical drives for certain logical
volumes on SSDs bypassing the Smart Array RAID stack for a
performance improvement.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Signed-off-by: Don Brace <brace@beardog.cce.hp.com>
Signed-off-by: Joe Handzik <joseph.t.handzik@hp.com>
---
drivers/scsi/hpsa.c | 582 +++++++++++++++++++++++++++++++++++++++++++----
drivers/scsi/hpsa.h | 26 ++
drivers/scsi/hpsa_cmd.h | 65 +++++
3 files changed, 619 insertions(+), 54 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 9b4f5ff..c7e3d4d 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -49,6 +49,7 @@
#include <linux/atomic.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
+#include <asm/div64.h>
#include "hpsa_cmd.h"
#include "hpsa.h"
@@ -216,6 +217,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);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
@@ -1195,6 +1197,7 @@ static void complete_scsi_command(struct CommandList *cp)
struct scsi_cmnd *cmd;
struct ctlr_info *h;
struct ErrorInfo *ei;
+ struct hpsa_scsi_dev_t *dev;
unsigned char sense_key;
unsigned char asc; /* additional sense code */
@@ -1204,6 +1207,7 @@ static void complete_scsi_command(struct CommandList *cp)
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
h = cp->h;
+ dev = cmd->device->hostdata;
scsi_dma_unmap(cmd); /* undo the DMA mappings */
if ((cp->cmd_type == CMD_SCSI) &&
@@ -1242,6 +1246,19 @@ static void complete_scsi_command(struct CommandList *cp)
cp->Header.Tag.upper = c->Tag.upper;
memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ 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);
+ return;
+ }
}
/* an error has occurred */
@@ -1406,6 +1423,14 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "Command unabortable\n");
break;
+ case CMD_IOACCEL_DISABLED:
+ /* This only handles the direct pass-through case since RAID
+ * offload is handled above. Just attempt a retry.
+ */
+ cmd->result = DID_SOFT_ERROR << 16;
+ dev_warn(&h->pdev->dev,
+ "cp %p had HP SSD Smart Path error\n", cp);
+ break;
default:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
@@ -1650,6 +1675,147 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
return;
}
+#define HPSA_MAP_DEBUG
+#ifdef HPSA_MAP_DEBUG
+static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
+ struct raid_map_data *map_buff)
+{
+ struct raid_map_disk_data *dd = &map_buff->data[0];
+ int map, row, col;
+ u16 map_cnt, row_cnt, disks_per_row;
+
+ if (rc != 0)
+ return;
+
+ dev_info(&h->pdev->dev, "structure_size = %u\n",
+ le32_to_cpu(map_buff->structure_size));
+ dev_info(&h->pdev->dev, "volume_blk_size = %u\n",
+ le32_to_cpu(map_buff->volume_blk_size));
+ dev_info(&h->pdev->dev, "volume_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->volume_blk_cnt));
+ dev_info(&h->pdev->dev, "physicalBlockShift = %u\n",
+ map_buff->phys_blk_shift);
+ dev_info(&h->pdev->dev, "parity_rotation_shift = %u\n",
+ map_buff->parity_rotation_shift);
+ dev_info(&h->pdev->dev, "strip_size = %u\n",
+ le16_to_cpu(map_buff->strip_size));
+ dev_info(&h->pdev->dev, "disk_starting_blk = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_starting_blk));
+ dev_info(&h->pdev->dev, "disk_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_blk_cnt));
+ dev_info(&h->pdev->dev, "data_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->data_disks_per_row));
+ dev_info(&h->pdev->dev, "metadata_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->metadata_disks_per_row));
+ dev_info(&h->pdev->dev, "row_cnt = %u\n",
+ le16_to_cpu(map_buff->row_cnt));
+ dev_info(&h->pdev->dev, "layout_map_count = %u\n",
+ le16_to_cpu(map_buff->layout_map_count));
+
+ map_cnt = le16_to_cpu(map_buff->layout_map_count);
+ for (map = 0; map < map_cnt; map++) {
+ dev_info(&h->pdev->dev, "Map%u:\n", map);
+ row_cnt = le16_to_cpu(map_buff->row_cnt);
+ for (row = 0; row < row_cnt; row++) {
+ dev_info(&h->pdev->dev, " Row%u:\n", row);
+ disks_per_row =
+ le16_to_cpu(map_buff->data_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " D%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ disks_per_row =
+ le16_to_cpu(map_buff->metadata_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " M%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ }
+ }
+}
+#else
+static void hpsa_debug_map_buff(__attribute__((unused)) struct ctlr_info *h,
+ __attribute__((unused)) int rc,
+ __attribute__((unused)) struct raid_map_data *map_buff)
+{
+}
+#endif
+
+static int hpsa_get_raid_map(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc = 0;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) {
+ dev_warn(&h->pdev->dev, "cmd_special_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);
+ 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(c);
+ cmd_special_free(h, c);
+ return -1;
+ }
+ cmd_special_free(h, c);
+
+ /* @todo in the future, dynamically allocate RAID map memory */
+ if (le32_to_cpu(this_device->raid_map.structure_size) >
+ sizeof(this_device->raid_map)) {
+ dev_warn(&h->pdev->dev, "RAID map size is too large!\n");
+ rc = -1;
+ }
+ hpsa_debug_map_buff(h, rc, &this_device->raid_map);
+ return rc;
+}
+
+static void hpsa_get_ioaccel_status(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc;
+ unsigned char *buf;
+ u8 ioaccel_status;
+
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return;
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
+ if (rc != 0)
+ goto out;
+
+#define IOACCEL_STATUS_BYTE 4
+#define OFFLOAD_CONFIGURED_BIT 0x01
+#define OFFLOAD_ENABLED_BIT 0x02
+ ioaccel_status = buf[IOACCEL_STATUS_BYTE];
+ this_device->offload_config =
+ !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
+ if (this_device->offload_config) {
+ this_device->offload_enabled =
+ !!(ioaccel_status & OFFLOAD_ENABLED_BIT);
+ if (hpsa_get_raid_map(h, scsi3addr, this_device))
+ this_device->offload_enabled = 0;
+ }
+out:
+ kfree(buf);
+ return;
+}
+
/* Get the device id from inquiry page 0x83 */
static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
unsigned char *device_id, int buflen)
@@ -1698,6 +1864,14 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
ei->CommandStatus != CMD_DATA_UNDERRUN) {
hpsa_scsi_interpret_error(c);
rc = -1;
+ } else {
+ if (buf->extended_response_flag != extended_response) {
+ dev_err(&h->pdev->dev,
+ "report luns requested format %u, got %u\n",
+ extended_response,
+ buf->extended_response_flag);
+ rc = -1;
+ }
}
out:
cmd_special_free(h, c);
@@ -1763,10 +1937,15 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->device_id));
if (this_device->devtype == TYPE_DISK &&
- is_logical_dev_addr_mode(scsi3addr))
+ is_logical_dev_addr_mode(scsi3addr)) {
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
- else
+ if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
+ hpsa_get_ioaccel_status(h, scsi3addr, this_device);
+ } else {
this_device->raid_level = RAID_UNKNOWN;
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+ }
if (is_OBDR_device) {
/* See if this is a One-Button-Disaster-Recovery device
@@ -1903,15 +2082,25 @@ static int add_ext_target_dev(struct ctlr_info *h,
*/
static int hpsa_gather_lun_info(struct ctlr_info *h,
int reportlunsize,
- struct ReportLUNdata *physdev, u32 *nphysicals,
+ struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode,
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) {
+ *physical_mode = HPSA_REPORT_PHYS_EXTENDED;
+ physical_entry_size = 24;
+ }
if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize,
- HPSA_REPORT_PHYS_EXTENDED)) {
+ *physical_mode)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24;
+ *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) /
+ physical_entry_size;
if (*nphysicals > HPSA_MAX_PHYS_LUN) {
dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
" %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
@@ -1944,7 +2133,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
int nphysicals, int nlogicals,
struct ReportExtendedLUNdata *physdev_list,
- struct ReportLUNdata *logdev_list)
+ struct ReportLUNdata *logdev_list, int physical_mode)
{
/* Helper function, figure out where the LUN ID info is coming from
* given index i, lists of physical and logical devices, where in
@@ -1957,9 +2146,15 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
if (i == raid_ctlr_position)
return RAID_CTLR_LUNID;
- if (i < logicals_start)
- return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0];
-
+ if (i < logicals_start) {
+ if (physical_mode)
+ return &((struct ReportExtendedLUNdata *)
+ physdev_list)->LUN[i -
+ (raid_ctlr_position == 0)][0];
+ else
+ return &physdev_list->LUN[i -
+ (raid_ctlr_position == 0)][0];
+ }
if (i < last_device)
return &logdev_list->LUN[i - nphysicals -
(raid_ctlr_position == 0)][0];
@@ -1983,10 +2178,11 @@ 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;
- int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
+ int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
@@ -2004,7 +2200,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (hpsa_gather_lun_info(h, reportlunsize,
(struct ReportLUNdata *) physdev_list, &nphysicals,
- logdev_list, &nlogicals))
+ &physical_mode, logdev_list, &nlogicals))
goto out;
/* We might see up to the maximum number of logical and physical disks
@@ -2043,7 +2239,8 @@ 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);
+ i, nphysicals, nlogicals, physdev_list, logdev_list,
+ physical_mode);
/* skip masked physical devices. */
if (lunaddrbytes[3] & 0xC0 &&
i < nphysicals + (raid_ctlr_position == 0))
@@ -2085,12 +2282,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
case TYPE_DISK:
- if (i < nphysicals)
+ if (i >= nphysicals) {
+ ncurrent++;
break;
- memcpy(&this_device->ioaccel_handle,
- &lunaddrbytes[20],
- sizeof(this_device->ioaccel_handle));
- ncurrent++;
+ }
+ if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) {
+ memcpy(&this_device->ioaccel_handle,
+ &lunaddrbytes[20],
+ sizeof(this_device->ioaccel_handle));
+ ncurrent++;
+ }
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
@@ -2184,15 +2385,62 @@ sglist_finished:
return 0;
}
+#define IO_ACCEL_INELIGIBLE (1)
+static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
+{
+ int is_write = 0;
+ u32 block;
+ u32 block_cnt;
+
+ /* Perform some CDB fixups if needed using 10 byte reads/writes only */
+ switch (cdb[0]) {
+ case WRITE_6:
+ case WRITE_12:
+ is_write = 1;
+ case READ_6:
+ case READ_12:
+ if (*cdb_len == 6) {
+ block = (((u32) cdb[2]) << 8) | cdb[3];
+ block_cnt = cdb[4];
+ } else {
+ BUG_ON(*cdb_len != 12);
+ block = (((u32) cdb[2]) << 24) |
+ (((u32) cdb[3]) << 16) |
+ (((u32) cdb[4]) << 8) |
+ cdb[5];
+ block_cnt =
+ (((u32) cdb[6]) << 24) |
+ (((u32) cdb[7]) << 16) |
+ (((u32) cdb[8]) << 8) |
+ cdb[9];
+ }
+ if (block_cnt > 0xffff)
+ return IO_ACCEL_INELIGIBLE;
+
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (block >> 24);
+ cdb[3] = (u8) (block >> 16);
+ cdb[4] = (u8) (block >> 8);
+ cdb[5] = (u8) (block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (block_cnt >> 8);
+ cdb[8] = (u8) (block_cnt);
+ cdb[9] = 0;
+ *cdb_len = 10;
+ break;
+ }
+ return 0;
+}
+
/*
* Queue a command to the I/O accelerator path.
- * This method does not currently support S/G chaining.
*/
static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
- struct CommandList *c)
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
{
struct scsi_cmnd *cmd = c->scsi_cmd;
- struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
unsigned int len;
unsigned int total_len = 0;
@@ -2202,8 +2450,15 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct SGDescriptor *curr_sg;
u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
+ /* TODO: implement chaining support */
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ return IO_ACCEL_INELIGIBLE;
+
c->cmd_type = CMD_IOACCEL1;
/* Adjust the DMA address to point to the accelerated command buffer */
@@ -2254,13 +2509,13 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
}
/* Fill out the command structure to submit */
- cp->dev_handle = dev->ioaccel_handle;
+ cp->dev_handle = ioaccel_handle & 0xFFFF;
cp->transfer_len = total_len;
cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ |
- (cmd->cmd_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
+ (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
cp->control = control;
- memcpy(cp->CDB, cmd->cmnd, cmd->cmd_len);
- memcpy(cp->CISS_LUN, dev->scsi3addr, 8);
+ memcpy(cp->CDB, cdb, cdb_len);
+ memcpy(cp->CISS_LUN, scsi3addr, 8);
/* Tell the controller to post the reply to the queue for this
* processor. This seems to give the best I/O throughput.
@@ -2274,15 +2529,214 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
*/
c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[use_sg] << 1) |
IOACCEL1_BUSADDR_CMDTYPE;
-
- /* execute command (bypassing cmd queue if possible) */
- if (unlikely(h->access.fifo_full(h)))
- enqueue_cmd_and_start_io(h, c);
- else
- h->access.submit_command(h, c);
+ enqueue_cmd_and_start_io(h, c);
return 0;
}
+/*
+ * Queue a command directly to a device behind the controller using the
+ * I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ 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);
+}
+
+/*
+ * Attempt to perform offload RAID mapping for a logical volume I/O.
+ */
+static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct raid_map_data *map = &dev->raid_map;
+ struct raid_map_disk_data *dd = &map->data[0];
+ int is_write = 0;
+ u32 map_index;
+ u64 first_block, last_block;
+ u32 block_cnt;
+ u32 blocks_per_row;
+ u64 first_row, last_row;
+ u32 first_row_offset, last_row_offset;
+ u32 first_column, last_column;
+ u32 map_row;
+ u32 disk_handle;
+ u64 disk_block;
+ u32 disk_block_cnt;
+ u8 cdb[16];
+ u8 cdb_len;
+#if BITS_PER_LONG == 32
+ u64 tmpdiv;
+#endif
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* check for valid opcode, get LBA and block count */
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ is_write = 1;
+ case READ_6:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ block_cnt = cmd->cmnd[4];
+ break;
+ case WRITE_10:
+ is_write = 1;
+ case READ_10:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[7]) << 8) |
+ cmd->cmnd[8];
+ break;
+ case WRITE_12:
+ is_write = 1;
+ case READ_12:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ break;
+ case WRITE_16:
+ is_write = 1;
+ case READ_16:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ block_cnt =
+ (((u32) cmd->cmnd[10]) << 24) |
+ (((u32) cmd->cmnd[11]) << 16) |
+ (((u32) cmd->cmnd[12]) << 8) |
+ cmd->cmnd[13];
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE; /* process via normal I/O path */
+ }
+ BUG_ON(block_cnt == 0);
+ last_block = first_block + block_cnt - 1;
+
+ /* check for write to non-RAID-0 */
+ if (is_write && dev->raid_level != 0)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* check for invalid block or wraparound */
+ if (last_block >= map->volume_blk_cnt || last_block < first_block)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* calculate stripe information for the request */
+ blocks_per_row = map->data_disks_per_row * map->strip_size;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, blocks_per_row);
+ first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) do_div(tmpdiv, blocks_per_row);
+ last_row = tmpdiv;
+ first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
+ tmpdiv = first_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = tmpdiv;
+ tmpdiv = last_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ last_column = tmpdiv;
+#else
+ first_row = first_block / blocks_per_row;
+ last_row = last_block / blocks_per_row;
+ first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
+ first_column = first_row_offset / map->strip_size;
+ last_column = last_row_offset / map->strip_size;
+#endif
+
+ /* if this isn't a single row/column then give to the controller */
+ if ((first_row != last_row) || (first_column != last_column))
+ return IO_ACCEL_INELIGIBLE;
+
+ /* proceeding with driver mapping */
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+ map_index = (map_row * (map->data_disks_per_row +
+ map->metadata_disks_per_row)) + first_column;
+ if (dev->raid_level == 2) {
+ /* simple round-robin balancing of RAID 1+0 reads across
+ * primary and mirror members. this is appropriate for SSD
+ * but not optimal for HDD.
+ */
+ if (dev->offload_to_mirror)
+ map_index += map->data_disks_per_row;
+ dev->offload_to_mirror = !dev->offload_to_mirror;
+ }
+ 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));
+ disk_block_cnt = block_cnt;
+
+ /* handle differing logical/physical block sizes */
+ if (map->phys_blk_shift) {
+ disk_block <<= map->phys_blk_shift;
+ disk_block_cnt <<= map->phys_blk_shift;
+ }
+ BUG_ON(disk_block_cnt > 0xffff);
+
+ /* build the new CDB for the physical disk I/O */
+ if (disk_block > 0xffffffff) {
+ cdb[0] = is_write ? WRITE_16 : READ_16;
+ cdb[1] = 0;
+ cdb[2] = (u8) (disk_block >> 56);
+ cdb[3] = (u8) (disk_block >> 48);
+ cdb[4] = (u8) (disk_block >> 40);
+ cdb[5] = (u8) (disk_block >> 32);
+ cdb[6] = (u8) (disk_block >> 24);
+ cdb[7] = (u8) (disk_block >> 16);
+ cdb[8] = (u8) (disk_block >> 8);
+ cdb[9] = (u8) (disk_block);
+ cdb[10] = (u8) (disk_block_cnt >> 24);
+ cdb[11] = (u8) (disk_block_cnt >> 16);
+ cdb[12] = (u8) (disk_block_cnt >> 8);
+ cdb[13] = (u8) (disk_block_cnt);
+ cdb[14] = 0;
+ cdb[15] = 0;
+ cdb_len = 16;
+ } else {
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (disk_block >> 24);
+ cdb[3] = (u8) (disk_block >> 16);
+ cdb[4] = (u8) (disk_block >> 8);
+ cdb[5] = (u8) (disk_block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (disk_block_cnt >> 8);
+ cdb[8] = (u8) (disk_block_cnt);
+ cdb[9] = 0;
+ cdb_len = 10;
+ }
+ return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len,
+ dev->scsi3addr);
+}
+
static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -2291,6 +2745,7 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
unsigned char scsi3addr[8];
struct CommandList *c;
unsigned long flags;
+ int rc = 0;
/* Get the ptr to our adapter structure out of cmd->host. */
h = sdev_to_hba(cmd->device);
@@ -2326,13 +2781,29 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
- /* Call alternate submit routine for I/O accelerated commands */
- if ((likely(h->transMethod & CFGTBL_Trans_io_accel1)) &&
- (dev->ioaccel_handle) &&
- ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)) &&
- (scsi_sg_count(cmd) <= IOACCEL1_MAXSGENTRIES) &&
- likely(cmd->request->cmd_type == REQ_TYPE_FS))
- return hpsa_scsi_ioaccel_queue_command(h, c);
+ /* 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)) {
+ 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);
@@ -3515,6 +3986,18 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.Type.Direction = 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.Timeout = 0;
+ c->Request.CDB[0] = HPSA_CISS_READ;
+ c->Request.CDB[1] = cmd;
+ c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ c->Request.CDB[9] = size & 0xFF;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -4482,6 +4965,7 @@ 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->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
@@ -4566,18 +5050,19 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h)
return -ENOTSUPP;
h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+
/* Update the field, and then ring the doorbell */
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
print_cfg_table(&h->pdev->dev, h->cfgtable);
- if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
- dev_warn(&h->pdev->dev,
- "unable to get board into simple mode\n");
- return -ENODEV;
- }
+ if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
+ goto error;
h->transMethod = CFGTBL_Trans_Simple;
return 0;
+error:
+ dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
+ return -ENODEV;
}
static int hpsa_pci_init(struct ctlr_info *h)
@@ -4958,7 +5443,7 @@ reinit_after_soft_reset:
* the 5 lower bits of the address are used by the hardware. and by
* the driver. See comments in hpsa.h for more info.
*/
-#define COMMANDLIST_ALIGNMENT 32
+#define COMMANDLIST_ALIGNMENT 128
BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
@@ -5335,8 +5820,8 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
h->reply_queue[i].current_entry =
readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
}
- bft[7] = IOACCEL1_MAXSGENTRIES + 8;
- calc_bucket_map(bft, ARRAY_SIZE(bft), IOACCEL1_MAXSGENTRIES, 8,
+ bft[7] = h->ioaccel_maxsg + 8;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
h->ioaccel1_blockFetchTable);
/* initialize all reply queue entries to unused */
@@ -5367,6 +5852,11 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
{
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL1_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL1_MAXSGENTRIES;
+
/* Command structures must be aligned on a 128-byte boundary
* because the 7 lower bits of the address are used by the
* hardware.
@@ -5380,7 +5870,7 @@ static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
&(h->ioaccel_cmd_pool_dhandle));
h->ioaccel1_blockFetchTable =
- kmalloc(((IOACCEL1_MAXSGENTRIES + 1) *
+ kmalloc(((h->ioaccel_maxsg + 1) *
sizeof(u32)), GFP_KERNEL);
if ((h->ioaccel_cmd_pool == NULL) ||
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index c7865f3..ae08f1c 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -47,6 +47,13 @@ struct hpsa_scsi_dev_t {
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
u32 ioaccel_handle;
+ int offload_config; /* I/O accel RAID offload configured */
+ int offload_enabled; /* I/O accel RAID offload enabled */
+ int offload_to_mirror; /* Send next I/O accelerator RAID
+ * offload request to mirror drive
+ */
+ struct raid_map_data raid_map; /* I/O accelerator RAID map */
+
};
struct reply_pool {
@@ -133,6 +140,10 @@ struct ctlr_info {
u32 *blockFetchTable;
u32 *ioaccel1_blockFetchTable;
unsigned char *hba_inquiry_data;
+ u32 driver_support;
+ u32 fw_support;
+ int ioaccel_support;
+ int ioaccel_maxsg;
u64 last_intr_timestamp;
u32 last_heartbeat;
u64 last_heartbeat_timestamp;
@@ -406,8 +417,7 @@ static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h)
#define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC
#define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL
-static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h,
- u8 q)
+static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
{
u64 register_value;
struct reply_pool *rq = &h->reply_queue[q];
@@ -420,12 +430,18 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h,
rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED;
if (++rq->current_entry == rq->size)
rq->current_entry = 0;
+ /*
+ * @todo
+ *
+ * Don't really need to write the new index after each command,
+ * but with current driver design this is easiest.
+ */
+ 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);
- } else {
- writel((q << 24) | rq->current_entry,
- h->vaddr + IOACCEL_MODE1_CONSUMER_INDEX);
}
return (unsigned long) register_value;
}
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index e682d2e..c1ae8d2 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -42,6 +42,8 @@
#define CMD_UNSOLICITED_ABORT 0x000A
#define CMD_TIMEOUT 0x000B
#define CMD_UNABORTABLE 0x000C
+#define CMD_IOACCEL_DISABLED 0x000E
+
/* Unit Attentions ASC's as defined for the MSA2012sa */
#define POWER_OR_RESET 0x29
@@ -137,6 +139,11 @@
#define CFGTBL_BusType_Ultra3 0x00000002l
#define CFGTBL_BusType_Fibre1G 0x00000100l
#define CFGTBL_BusType_Fibre2G 0x00000200l
+
+/* VPD Inquiry types */
+#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
+#define HPSA_VPD_LV_IOACCEL_STATUS 0xC2
+
struct vals32 {
u32 lower;
u32 upper;
@@ -165,9 +172,46 @@ struct InquiryData {
#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
#define HPSA_REPORT_PHYS_EXTENDED 0x02
+#define HPSA_CISS_READ 0xc0 /* CISS Read */
+#define HPSA_GET_RAID_MAP 0xc8 /* CISS Get RAID Layout Map */
+
+#define RAID_MAP_MAX_ENTRIES 256
+
+struct raid_map_disk_data {
+ u32 ioaccel_handle; /**< Handle to access this disk via the
+ * I/O accelerator */
+ u8 xor_mult[2]; /**< XOR multipliers for this position,
+ * valid for data disks only */
+ u8 reserved[2];
+};
+
+struct raid_map_data {
+ u32 structure_size; /* Size of entire structure in bytes */
+ u32 volume_blk_size; /* bytes / block in the volume */
+ u64 volume_blk_cnt; /* logical blocks on the volume */
+ u8 phys_blk_shift; /* Shift factor to convert between
+ * units of logical blocks and physical
+ * disk blocks */
+ u8 parity_rotation_shift; /* Shift factor to convert between units
+ * of logical stripes and physical
+ * stripes */
+ u16 strip_size; /* blocks used on each disk / stripe */
+ u64 disk_starting_blk; /* First disk block used in volume */
+ u64 disk_blk_cnt; /* disk blocks used by volume / disk */
+ u16 data_disks_per_row; /* data disk entries / row in the map */
+ u16 metadata_disks_per_row; /* mirror/parity disk entries / row
+ * in the map */
+ u16 row_cnt; /* rows in each layout map */
+ u16 layout_map_count; /* layout maps (1 map per mirror/parity
+ * group) */
+ u8 reserved[20];
+ struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES];
+};
+
struct ReportLUNdata {
u8 LUNListLength[4];
- u32 reserved;
+ u8 extended_response_flag;
+ u8 reserved[3];
u8 LUN[HPSA_MAX_LUN][8];
};
@@ -331,7 +375,7 @@ struct CommandList {
*/
#define IS_32_BIT ((8 - sizeof(long))/4)
#define IS_64_BIT (!IS_32_BIT)
-#define PAD_32 (4)
+#define PAD_32 (36)
#define PAD_64 (4)
#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
u8 pad[COMMANDLIST_PAD];
@@ -371,6 +415,11 @@ struct io_accel1_cmd {
struct vals32 host_addr; /* 0x70 - 0x77 */
u8 CISS_LUN[8]; /* 0x78 - 0x7F */
struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
+#define IOACCEL1_PAD_64 0
+#define IOACCEL1_PAD_32 0
+#define IOACCEL1_PAD (IS_32_BIT * IOACCEL1_PAD_32 + \
+ IS_64_BIT * IOACCEL1_PAD_64)
+ u8 pad[IOACCEL1_PAD];
};
#define IOACCEL1_FUNCTION_SCSIIO 0x00
@@ -407,6 +456,8 @@ struct HostWrite {
#define MEMQ_MODE 0x08
#define IOACCEL_MODE_1 0x80
+#define DRIVER_SUPPORT_UA_ENABLE 0x00000001
+
struct CfgTable {
u8 Signature[4];
u32 SpecValence;
@@ -435,8 +486,16 @@ struct CfgTable {
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
#define MISC_FW_DOORBELL_RESET2 (0x010)
+#define MISC_FW_RAID_OFFLOAD_BASIC (0x020)
+#define MISC_FW_EVENT_NOTIFY (0x080)
u8 driver_version[32];
-
+ u32 max_cached_write_size;
+ u8 driver_scratchpad[16];
+ u32 max_error_info_length;
+ u32 io_accel_max_embedded_sg_count;
+ u32 io_accel_request_size_offset;
+ u32 event_notify;
+ u32 clear_event_notify;
};
#define NUM_BLOCKFETCH_ENTRIES 8
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 14/41] hpsa: update raid offload status on device rescan
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (12 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 13/41] hpsa: add ioaccell mode 1 RAID offload support Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 15/41] hpsa: poll controller to detect device change event Stephen M. Cameron
` (26 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
When rescanning for logical drives, store information about whather
raid offload is enabled for each logical drive, and update the driver's
internal record of this.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c7e3d4d..4c9dd2e 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -787,6 +787,11 @@ 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. */
+ h->dev[entry]->offload_config = new_entry->offload_config;
+ 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);
@@ -907,6 +912,10 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
*/
if (dev1->raid_level != dev2->raid_level)
return 1;
+ if (dev1->offload_config != dev2->offload_config)
+ return 1;
+ if (dev1->offload_enabled != dev2->offload_enabled)
+ return 1;
return 0;
}
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 15/41] hpsa: poll controller to detect device change event
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (13 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 14/41] hpsa: update raid offload status on device rescan Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 16/41] hpsa: do not rescan controllers known to be locked up Stephen M. Cameron
` (25 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
For shared SAS configurations, hosts need to poll Smart Arrays
periodically in order to be able to detect configuration changes
such as logical drives being added or removed from remote hosts.
A register on the controller indicates when such events have
occurred, and the driver polls the register via a workqueue
and kicks off a rescan of devices if such an event is detected.
Additionally, changes to logical drive raid offload eligibility
are autodetected in this way.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
---
drivers/scsi/hpsa.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/hpsa.h | 1
drivers/scsi/hpsa_cmd.h | 3 +
3 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 4c9dd2e..1383169 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -220,6 +220,8 @@ static inline void finish_cmd(struct CommandList *c);
static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
+static void hpsa_drain_commands(struct ctlr_info *h);
+static void hpsa_flush_cache(struct ctlr_info *h);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -5029,6 +5031,23 @@ 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)
+{
+ int i;
+ 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++) {
+ 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))
+ break;
+ /* delay and try again */
+ msleep(20);
+ }
+}
+
static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
{
int i;
@@ -5405,6 +5424,79 @@ static void detect_controller_lockup(struct ctlr_info *h)
h->last_heartbeat_timestamp = now;
}
+static int hpsa_kickoff_rescan(struct ctlr_info *h)
+{
+ int i;
+ char *event_type;
+
+ /* Ask the controller to clear the events we're handling. */
+ if (h->transMethod & (CFGTBL_Trans_io_accel1) &&
+ (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
+ h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
+
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
+ event_type = "state change";
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
+ event_type = "configuration change";
+ /* 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_commands(h);
+ /* Set 'accelerator path config change' bit */
+ dev_warn(&h->pdev->dev,
+ "Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
+ h->events, event_type);
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ /* Set the "clear event notify field update" bit 6 */
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ /* Wait until ctlr clears 'clear event notify field', bit 6 */
+ hpsa_wait_for_clear_event_notify_ack(h);
+ scsi_unblock_requests(h->scsi_host);
+ } else {
+ /* Acknowledge controller notification events. */
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_clear_event_notify_ack(h);
+#if 0
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+#endif
+ }
+
+ /* Something in the device list may have changed to trigger
+ * the event, so do a rescan.
+ */
+ hpsa_scan_start(h->scsi_host);
+ /* release reference taken on scsi host in check_controller_events */
+ scsi_host_put(h->scsi_host);
+ return 0;
+}
+
+/* Check a register on the controller to see if there are configuration
+ * changes (added/changed/removed logical drives, etc.) which mean that
+ * we should rescan the controller for devices. If so, add the controller
+ * to the list of controllers needing to be rescanned, and gets a
+ * reference to the associated scsi_host.
+ */
+static void hpsa_ctlr_needs_rescan(struct ctlr_info *h)
+{
+ if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
+ return;
+
+ h->events = readl(&(h->cfgtable->event_notify));
+ if (!h->events)
+ return;
+
+ /*
+ * Take a reference on scsi host for the duration of the scan
+ * Release in hpsa_kickoff_rescan(). No lock needed for scan_list
+ * as only a single thread accesses this list.
+ */
+ scsi_host_get(h->scsi_host);
+ hpsa_kickoff_rescan(h);
+}
+
static void hpsa_monitor_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
@@ -5413,6 +5505,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
detect_controller_lockup(h);
if (h->lockup_detected)
return;
+ hpsa_ctlr_needs_rescan(h);
spin_lock_irqsave(&h->lock, flags);
if (h->remove_in_progress) {
spin_unlock_irqrestore(&h->lock, flags);
@@ -5954,6 +6047,21 @@ clean_up:
kfree(h->blockFetchTable);
}
+static void hpsa_drain_commands(struct ctlr_info *h)
+{
+ int cmds_out;
+ unsigned long flags;
+
+ do { /* wait for all outstanding commands to drain out */
+ spin_lock_irqsave(&h->lock, flags);
+ cmds_out = h->commands_outstanding;
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (cmds_out <= 0)
+ break;
+ msleep(100);
+ } while (1);
+}
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index ae08f1c..df2f88d 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -176,6 +176,7 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TASK (1 << 23)
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
+ u32 events;
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index c1ae8d2..21f8a61 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -128,6 +128,7 @@
#define CFGTBL_AccCmds 0x00000001l
#define DOORBELL_CTLR_RESET 0x00000004l
#define DOORBELL_CTLR_RESET2 0x00000020l
+#define DOORBELL_CLEAR_EVENTS 0x00000040l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -495,6 +496,8 @@ struct CfgTable {
u32 io_accel_max_embedded_sg_count;
u32 io_accel_request_size_offset;
u32 event_notify;
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30)
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31)
u32 clear_event_notify;
};
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 16/41] hpsa: do not rescan controllers known to be locked up
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (14 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 15/41] hpsa: poll controller to detect device change event Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 17/41] hpsa: add hp_ssd_smart_path_enabled sysfs attribute Stephen M. Cameron
` (24 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
* Do not check event bits on locked up controllers to
see if they need to be rescanned.
* Do not initiate any device rescans on controllers
which are known to be locked up.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 39 +++++++++++++++++++++++++++++++++++----
1 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 1383169..f88bb73 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2875,11 +2875,38 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
+{
+ unsigned long flags;
+
+ /*
+ * Don't let rescans be initiated on a controller known
+ * to be locked up. If the controller locks up *during*
+ * a rescan, that thread is probably hosed, but at least
+ * we can prevent new rescan threads from piling up on a
+ * locked up controller.
+ */
+ spin_lock_irqsave(&h->lock, flags);
+ if (unlikely(h->lockup_detected)) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ spin_lock_irqsave(&h->scan_lock, flags);
+ h->scan_finished = 1;
+ wake_up_all(&h->scan_wait_queue);
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return 0;
+}
+
static void hpsa_scan_start(struct Scsi_Host *sh)
{
struct ctlr_info *h = shost_to_hba(sh);
unsigned long flags;
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
/* wait until any scan already in progress is finished. */
while (1) {
spin_lock_irqsave(&h->scan_lock, flags);
@@ -2896,6 +2923,9 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
h->scan_finished = 0; /* mark scan as in progress */
spin_unlock_irqrestore(&h->scan_lock, flags);
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
hpsa_update_scsi_devices(h, h->scsi_host->host_no);
spin_lock_irqsave(&h->scan_lock, flags);
@@ -5389,7 +5419,7 @@ static void controller_lockup_detected(struct ctlr_info *h)
spin_unlock_irqrestore(&h->lock, flags);
}
-static void detect_controller_lockup(struct ctlr_info *h)
+static int detect_controller_lockup(struct ctlr_info *h)
{
u64 now;
u32 heartbeat;
@@ -5399,7 +5429,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
/* If we've received an interrupt recently, we're ok. */
if (time_after64(h->last_intr_timestamp +
(h->heartbeat_sample_interval), now))
- return;
+ return 0;
/*
* If we've already checked the heartbeat recently, we're ok.
@@ -5408,7 +5438,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
*/
if (time_after64(h->last_heartbeat_timestamp +
(h->heartbeat_sample_interval), now))
- return;
+ return 0;
/* If heartbeat has not changed since we last looked, we're not ok. */
spin_lock_irqsave(&h->lock, flags);
@@ -5416,12 +5446,13 @@ static void detect_controller_lockup(struct ctlr_info *h)
spin_unlock_irqrestore(&h->lock, flags);
if (h->last_heartbeat == heartbeat) {
controller_lockup_detected(h);
- return;
+ return 1;
}
/* We're ok. */
h->last_heartbeat = heartbeat;
h->last_heartbeat_timestamp = now;
+ return 0;
}
static int hpsa_kickoff_rescan(struct ctlr_info *h)
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 17/41] hpsa: add hp_ssd_smart_path_enabled sysfs attribute
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (15 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 16/41] hpsa: do not rescan controllers known to be locked up Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 18/41] hpsa: complain if physical or logical aborts are not supported Stephen M. Cameron
` (23 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index f88bb73..39500d6 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -508,10 +508,34 @@ static ssize_t unique_id_show(struct device *dev,
sn[12], sn[13], sn[14], sn[15]);
}
+static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+ int offload_enabled;
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+ offload_enabled = hdev->offload_enabled;
+ spin_unlock_irqrestore(&h->lock, flags);
+ return snprintf(buf, 20, "%d\n", offload_enabled);
+}
+
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(hp_ssd_smart_path_enabled, S_IRUGO,
+ host_show_hp_ssd_smart_path_enabled, NULL);
static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
@@ -525,6 +549,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
&dev_attr_lunid,
&dev_attr_unique_id,
+ &dev_attr_hp_ssd_smart_path_enabled,
NULL,
};
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 18/41] hpsa: complain if physical or logical aborts are not supported
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (16 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 17/41] hpsa: add hp_ssd_smart_path_enabled sysfs attribute Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 19/41] hpsa: add ioaccel mode 2 structure definitions Stephen M. Cameron
` (22 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 39500d6..3db772f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -5048,6 +5048,10 @@ static void hpsa_find_board_params(struct ctlr_info *h)
/* Find out what task management functions are supported and cache */
h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
+ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags))
+ 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");
}
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 19/41] hpsa: add ioaccel mode 2 structure definitions
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (17 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 18/41] hpsa: complain if physical or logical aborts are not supported Stephen M. Cameron
@ 2014-01-15 22:37 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 20/41] hpsa: Acknowledge controller events in ioaccell mode 2 as well as mode 1 Stephen M. Cameron
` (21 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:37 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Mike Miller <mikem@beardog.cce.hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 22 ++++++++++
drivers/scsi/hpsa.h | 8 ++++
drivers/scsi/hpsa_cmd.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 3db772f..ebca59b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -6139,6 +6139,28 @@ static void __exit hpsa_cleanup(void)
static void __attribute__((unused)) verify_offsets(void)
{
#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, member) != offset)
+
+ VERIFY_OFFSET(IU_type, 0);
+ VERIFY_OFFSET(direction, 1);
+ VERIFY_OFFSET(reply_queue, 2);
+ /* VERIFY_OFFSET(reserved1, 3); */
+ VERIFY_OFFSET(scsi_nexus, 4);
+ VERIFY_OFFSET(Tag, 8);
+ VERIFY_OFFSET(cdb, 16);
+ VERIFY_OFFSET(cciss_lun, 32);
+ VERIFY_OFFSET(data_len, 40);
+ VERIFY_OFFSET(cmd_priority_task_attr, 44);
+ VERIFY_OFFSET(sg_count, 45);
+ /* VERIFY_OFFSET(reserved3 */
+ VERIFY_OFFSET(err_ptr, 48);
+ VERIFY_OFFSET(err_len, 56);
+ /* VERIFY_OFFSET(reserved4 */
+ VERIFY_OFFSET(sg, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
BUILD_BUG_ON(offsetof(struct io_accel1_cmd, member) != offset)
VERIFY_OFFSET(dev_handle, 0x00);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index df2f88d..74eb22a 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -258,6 +258,14 @@ struct ctlr_info {
#define HPSA_INTR_ON 1
#define HPSA_INTR_OFF 0
+
+/*
+ * Inbound Post Queue offsets for IO Accelerator Mode 2
+ */
+#define IOACCEL2_INBOUND_POSTQ_32 0x48
+#define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0
+#define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4
+
/*
Send the command to the hardware
*/
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 21f8a61..9e00988 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -332,6 +332,7 @@ struct ErrorInfo {
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
#define CMD_IOACCEL1 0x04
+#define CMD_IOACCEL2 0x05
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
@@ -384,6 +385,7 @@ struct CommandList {
/* Max S/G elements in I/O accelerator command */
#define IOACCEL1_MAXSGENTRIES 24
+#define IOACCEL2_MAXSGENTRIES 28
/*
* Structure for I/O accelerator (mode 1) commands.
@@ -444,6 +446,103 @@ struct io_accel1_cmd {
#define IOACCEL1_BUSADDR_CMDTYPE 0x00000060
+struct ioaccel2_sg_element {
+ u64 address;
+ u32 length;
+ u8 reserved[3];
+ u8 chain_indicator;
+#define IOACCEL2_CHAIN 0x80
+};
+
+/*
+ * SCSI Response Format structure for IO Accelerator Mode 2
+ */
+struct io_accel2_scsi_response {
+ u8 IU_type;
+#define IOACCEL2_IU_TYPE_SRF 0x60
+ u8 reserved1[3];
+ u8 req_id[4]; /* request identifier */
+ u8 reserved2[4];
+ u8 serv_response; /* service response */
+#define IOACCEL2_SERV_RESPONSE_COMPLETE 0x000
+#define IOACCEL2_SERV_RESPONSE_FAILURE 0x001
+#define IOACCEL2_SERV_RESPONSE_TMF_COMPLETE 0x002
+#define IOACCEL2_SERV_RESPONSE_TMF_SUCCESS 0x003
+#define IOACCEL2_SERV_RESPONSE_TMF_REJECTED 0x004
+#define IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN 0x005
+ u8 status; /* status */
+#define IOACCEL2_STATUS_SR_TASK_COMP_GOOD 0x00
+#define IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND 0x02
+#define IOACCEL2_STATUS_SR_TASK_COMP_BUSY 0x08
+#define IOACCEL2_STATUS_SR_TASK_COMP_RES_CON 0x18
+#define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28
+#define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40
+ u8 data_present; /* low 2 bits */
+#define IOACCEL2_NO_DATAPRESENT 0x000
+#define IOACCEL2_RESPONSE_DATAPRESENT 0x001
+#define IOACCEL2_SENSE_DATA_PRESENT 0x002
+#define IOACCEL2_RESERVED 0x003
+ u8 sense_data_len; /* sense/response data length */
+ u8 resid_cnt[4]; /* residual count */
+ u8 sense_data_buff[32]; /* sense/response data buffer */
+};
+
+#define IOACCEL2_64_PAD 76
+#define IOACCEL2_32_PAD 76
+#define IOACCEL2_PAD (IS_32_BIT * IOACCEL2_32_PAD + \
+ IS_64_BIT * IOACCEL2_64_PAD)
+/*
+ * Structure for I/O accelerator (mode 2 or m2) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel2_cmd {
+ u8 IU_type; /* IU Type */
+ u8 direction; /* Transfer direction, 2 bits */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 reserved1; /* Reserved */
+ u32 scsi_nexus; /* Device Handle */
+ struct vals32 Tag; /* cciss tag */
+ u8 cdb[16]; /* SCSI Command Descriptor Block */
+ u8 cciss_lun[8]; /* 8 byte SCSI address */
+ u32 data_len; /* Total bytes to transfer */
+ u8 cmd_priority_task_attr; /* priority and task attrs */
+#define IOACCEL2_PRIORITY_MASK 0x78
+#define IOACCEL2_ATTR_MASK 0x07
+ u8 sg_count; /* Number of sg elements */
+ u8 reserved3[2]; /* Reserved */
+ u64 err_ptr; /* Error Pointer */
+ u32 err_len; /* Error Length*/
+ u8 reserved4[4]; /* Reserved */
+ struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];
+ struct io_accel2_scsi_response error_data;
+ u8 pad[IOACCEL2_PAD];
+};
+
+/*
+ * defines for Mode 2 command struct
+ * FIXME: this can't be all I need mfm
+ */
+#define IOACCEL2_IU_TYPE 0x40
+#define IU_TYPE_TMF 0x41
+#define IOACCEL2_DIR_NO_DATA 0x00
+#define IOACCEL2_DIR_DATA_IN 0x01
+#define IOACCEL2_DIR_DATA_OUT 0x02
+/*
+ * SCSI Task Management Request format for Accelerator Mode 2
+ */
+struct hpsa_tmf_struct {
+ u8 iu_type; /* Information Unit Type */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 tmf; /* Task Management Function */
+ 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 error_ptr; /* Error Pointer */
+ u32 error_len; /* Error Length */
+};
+
/* Configuration Table Structure */
struct HostWrite {
u32 TransportRequest;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 20/41] hpsa: Acknowledge controller events in ioaccell mode 2 as well as mode 1
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (18 preceding siblings ...)
2014-01-15 22:37 ` [PATCH 19/41] hpsa: add ioaccel mode 2 structure definitions Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 21/41] hpsa: do ioaccel mode 2 resource allocations Stephen M. Cameron
` (20 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 3 ++-
drivers/scsi/hpsa_cmd.h | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index ebca59b..fbf41c7 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -5490,7 +5490,8 @@ static int hpsa_kickoff_rescan(struct ctlr_info *h)
char *event_type;
/* Ask the controller to clear the events we're handling. */
- if (h->transMethod & (CFGTBL_Trans_io_accel1) &&
+ if ((h->transMethod & (CFGTBL_Trans_io_accel1
+ | CFGTBL_Trans_io_accel2)) &&
(h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 9e00988..6b336e8 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -133,6 +133,7 @@
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
#define CFGTBL_Trans_io_accel1 0x00000080l
+#define CFGTBL_Trans_io_accel2 0x00000100l
#define CFGTBL_Trans_use_short_tags 0x20000000l
#define CFGTBL_Trans_enable_directed_msix (1 << 30)
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 21/41] hpsa: do ioaccel mode 2 resource allocations
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (19 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 20/41] hpsa: Acknowledge controller events in ioaccell mode 2 as well as mode 1 Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 22/41] hpsa: get physical device handles for io accel mode 2 as well as mode 1 Stephen M. Cameron
` (19 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/hpsa.h | 3 +++
2 files changed, 53 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index fbf41c7..f0bd511 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -5295,6 +5295,10 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
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),
@@ -5834,6 +5838,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
kfree(h->ioaccel1_blockFetchTable);
+ kfree(h->ioaccel2_blockFetchTable);
kfree(h->hba_inquiry_data);
pci_disable_device(pdev);
pci_release_regions(pdev);
@@ -6053,6 +6058,44 @@ clean_up:
return 1;
}
+static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h)
+{
+ /* Allocate ioaccel2 mode command blocks and block fetch table */
+
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES;
+
+#define IOACCEL2_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %
+ IOACCEL2_COMMANDLIST_ALIGNMENT);
+ h->ioaccel2_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ &(h->ioaccel2_cmd_pool_dhandle));
+
+ h->ioaccel2_blockFetchTable =
+ kmalloc(((h->ioaccel_maxsg + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel2_cmd_pool == NULL) ||
+ (h->ioaccel2_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel2_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool));
+ 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);
+ return 1;
+}
+
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
@@ -6073,6 +6116,13 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
CFGTBL_Trans_enable_directed_msix;
if (hpsa_alloc_ioaccel_cmd_and_bft(h))
goto clean_up;
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ transMethod |= CFGTBL_Trans_io_accel2 |
+ CFGTBL_Trans_enable_directed_msix;
+ if (ioaccel2_alloc_cmds_and_bft(h))
+ goto clean_up;
+ }
}
/* TODO, check that this next line h->nreply_queues is correct */
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 74eb22a..2a4a0cb 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -105,6 +105,8 @@ struct ctlr_info {
dma_addr_t cmd_pool_dhandle;
struct io_accel1_cmd *ioaccel_cmd_pool;
dma_addr_t ioaccel_cmd_pool_dhandle;
+ struct io_accel2_cmd *ioaccel2_cmd_pool;
+ dma_addr_t ioaccel2_cmd_pool_dhandle;
struct ErrorInfo *errinfo_pool;
dma_addr_t errinfo_pool_dhandle;
unsigned long *cmd_pool_bits;
@@ -139,6 +141,7 @@ struct ctlr_info {
dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
u32 *ioaccel1_blockFetchTable;
+ u32 *ioaccel2_blockFetchTable;
unsigned char *hba_inquiry_data;
u32 driver_support;
u32 fw_support;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 22/41] hpsa: get physical device handles for io accel mode 2 as well as mode 1
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (20 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 21/41] hpsa: do ioaccel mode 2 resource allocations Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 23/41] hpsa: initialize controller to perform io accelerator mode 2 Stephen M. Cameron
` (18 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Mike MIller <mikem@beardog.cce.hp.com>
Signed-off-by: Mike MIller <mikem@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index f0bd511..e471782 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2126,7 +2126,8 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
*physical_mode = 0;
/* For I/O accelerator mode we need to read physical device handles */
- if (h->transMethod & CFGTBL_Trans_io_accel1) {
+ if (h->transMethod & CFGTBL_Trans_io_accel1 ||
+ h->transMethod & CFGTBL_Trans_io_accel2) {
*physical_mode = HPSA_REPORT_PHYS_EXTENDED;
physical_entry_size = 24;
}
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 23/41] hpsa: initialize controller to perform io accelerator mode 2
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (21 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 22/41] hpsa: get physical device handles for io accel mode 2 as well as mode 1 Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 24/41] hpsa: get ioaccel mode 2 i/o working Stephen M. Cameron
` (17 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
---
drivers/scsi/hpsa.c | 111 ++++++++++++++++++++++++++++++++---------------
drivers/scsi/hpsa.h | 1
drivers/scsi/hpsa_cmd.h | 2 -
3 files changed, 78 insertions(+), 36 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index e471782..6c59b74 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -5141,6 +5141,7 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h)
/* Update the field, and then ring the doorbell */
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);
print_cfg_table(&h->pdev->dev, h->cfgtable);
@@ -5907,9 +5908,9 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
unsigned long register_value;
unsigned long transMethod = CFGTBL_Trans_Performant |
(trans_support & CFGTBL_Trans_use_short_tags) |
- CFGTBL_Trans_enable_directed_msix |
- (trans_support & CFGTBL_Trans_io_accel1);
-
+ CFGTBL_Trans_enable_directed_msix |
+ (trans_support & (CFGTBL_Trans_io_accel1 |
+ CFGTBL_Trans_io_accel2));
struct access_method access = SA5_performant_access;
/* This is a bit complicated. There are 8 registers on
@@ -5930,6 +5931,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
* sizes for small commands, and fewer sizes for larger commands.
*/
int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
+#define MIN_IOACCEL2_BFT_ENTRY 5
+#define HPSA_IOACCEL2_HEADER_SZ 4
+ int bft2[16] = {MIN_IOACCEL2_BFT_ENTRY, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19,
+ HPSA_IOACCEL2_HEADER_SZ + IOACCEL2_MAXSGENTRIES};
+ BUILD_BUG_ON(ARRAY_SIZE(bft2) != 16);
+ BUILD_BUG_ON(ARRAY_SIZE(bft) != 8);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) >
+ 16 * MIN_IOACCEL2_BFT_ENTRY);
+ BUILD_BUG_ON(sizeof(struct ioaccel2_sg_element) != 16);
BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
@@ -5959,6 +5970,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
&h->transtable->RepQAddr[i].lower);
}
+ writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest));
/*
* enable outbound interrupt coalescing in accelerator mode;
@@ -5980,43 +5992,72 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
h->access = access;
h->transMethod = transMethod;
- if (!(trans_support & CFGTBL_Trans_io_accel1))
+ if (!((trans_support & CFGTBL_Trans_io_accel1) ||
+ (trans_support & CFGTBL_Trans_io_accel2)))
return;
- /* Set up I/O accelerator mode */
- for (i = 0; i < h->nreply_queues; i++) {
- writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
- h->reply_queue[i].current_entry =
- readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
- }
- bft[7] = h->ioaccel_maxsg + 8;
- calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
- h->ioaccel1_blockFetchTable);
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ /* Set up I/O accelerator mode */
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
+ h->reply_queue[i].current_entry =
+ readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
+ }
+ bft[7] = h->ioaccel_maxsg + 8;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
+ h->ioaccel1_blockFetchTable);
- /* initialize all reply queue entries to unused */
- memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED,
- h->reply_pool_size);
+ /* initialize all reply queue entries to unused */
+ memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED,
+ h->reply_pool_size);
- /* set all the constant fields in the accelerator command
- * frames once at init time to save CPU cycles later.
- */
- for (i = 0; i < h->nr_cmds; i++) {
- struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
-
- cp->function = IOACCEL1_FUNCTION_SCSIIO;
- cp->err_info = (u32) (h->errinfo_pool_dhandle +
- (i * sizeof(struct ErrorInfo)));
- cp->err_info_len = sizeof(struct ErrorInfo);
- cp->sgl_offset = IOACCEL1_SGLOFFSET;
- 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;
+ /* set all the constant fields in the accelerator command
+ * frames once at init time to save CPU cycles later.
+ */
+ for (i = 0; i < h->nr_cmds; i++) {
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
+
+ cp->function = IOACCEL1_FUNCTION_SCSIIO;
+ cp->err_info = (u32) (h->errinfo_pool_dhandle +
+ (i * sizeof(struct ErrorInfo)));
+ cp->err_info_len = sizeof(struct ErrorInfo);
+ cp->sgl_offset = IOACCEL1_SGLOFFSET;
+ 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;
+ }
+ } else if (trans_support & CFGTBL_Trans_io_accel2) {
+ u64 cfg_offset, cfg_base_addr_index;
+ u32 bft2_offset, cfg_base_addr;
+ int rc;
+
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64);
+ bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ;
+ calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg,
+ 4, h->ioaccel2_blockFetchTable);
+ bft2_offset = readl(&h->cfgtable->io_accel_request_size_offset);
+ BUILD_BUG_ON(offsetof(struct CfgTable,
+ io_accel_request_size_offset) != 0xb8);
+ h->ioaccel2_bft2_regs =
+ remap_pci_mem(pci_resource_start(h->pdev,
+ cfg_base_addr_index) +
+ cfg_offset + bft2_offset,
+ ARRAY_SIZE(bft2) *
+ sizeof(*h->ioaccel2_bft2_regs));
+ for (i = 0; i < ARRAY_SIZE(bft2); i++)
+ writel(bft2[i], &h->ioaccel2_bft2_regs[i]);
}
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
}
static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 2a4a0cb..0e14e9b 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -142,6 +142,7 @@ struct ctlr_info {
u32 *blockFetchTable;
u32 *ioaccel1_blockFetchTable;
u32 *ioaccel2_blockFetchTable;
+ u32 *ioaccel2_bft2_regs;
unsigned char *hba_inquiry_data;
u32 driver_support;
u32 fw_support;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 6b336e8..dfdb4a5 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -547,7 +547,7 @@ struct hpsa_tmf_struct {
/* Configuration Table Structure */
struct HostWrite {
u32 TransportRequest;
- u32 Reserved;
+ u32 command_pool_addr_hi;
u32 CoalIntDelay;
u32 CoalIntCount;
};
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 24/41] hpsa: get ioaccel mode 2 i/o working
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (22 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 23/41] hpsa: initialize controller to perform io accelerator mode 2 Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset Stephen M. Cameron
` (16 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Signed-off-by: Joe Handzik <Joseph.T.Handzik@hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 325 ++++++++++++++++++++++++++++++++++++++++++++---
drivers/scsi/hpsa.h | 20 +++
drivers/scsi/hpsa_cmd.h | 1
3 files changed, 327 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6c59b74..9628e12 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -222,6 +222,9 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_READY 1
static void hpsa_drain_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);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -622,6 +625,32 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
return a;
}
+/*
+ * There are some special bits in the bus address of the
+ * command that we have to set for the controller to know
+ * how to process the command:
+ *
+ * Normal performant mode:
+ * bit 0: 1 means performant mode, 0 means simple mode.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 0)
+ *
+ * ioaccel1 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 110)
+ * (command type is needed because ioaccel1 mode
+ * commands are submitted through the same register as normal
+ * mode commands, so this is how the controller knows whether
+ * the command is normal mode or ioaccel1 mode.)
+ *
+ * ioaccel2 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-4 = block fetch table entry (note extra bit)
+ * bits 4-6 = not needed, because ioaccel2 mode has
+ * a separate special register for submitting commands.
+ */
+
/* set_performant_mode: Modify the tag for cciss performant
* set bit 0 for pull model, bits 3-1 for block fetch
* register number
@@ -636,6 +665,41 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
}
}
+static void set_ioaccel1_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ 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;
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit (bit 0)
+ * - pull count (bits 1-3)
+ * - command type (bits 4-6)
+ */
+ c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
+ IOACCEL1_BUSADDR_CMDTYPE;
+}
+
+static void set_ioaccel2_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ 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;
+ /* 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[cp->sg_count]);
+}
+
static int is_firmware_flash_cmd(u8 *cdb)
{
return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
@@ -670,7 +734,16 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
{
unsigned long flags;
- set_performant_mode(h, c);
+ switch (c->cmd_type) {
+ case CMD_IOACCEL1:
+ set_ioaccel1_performant_mode(h, c);
+ break;
+ case CMD_IOACCEL2:
+ set_ioaccel2_performant_mode(h, c);
+ break;
+ default:
+ set_performant_mode(h, c);
+ }
dial_down_lockup_detection_during_fw_flash(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
@@ -1228,6 +1301,123 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
}
+static void handle_ioaccel_mode2_error(struct ctlr_info *h,
+ struct CommandList *c,
+ struct scsi_cmnd *cmd,
+ struct io_accel2_cmd *c2)
+{
+ int data_len;
+
+ switch (c2->error_data.serv_response) {
+ case IOACCEL2_SERV_RESPONSE_COMPLETE:
+ switch (c2->error_data.status) {
+ 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");
+ if (c2->error_data.data_present !=
+ IOACCEL2_SENSE_DATA_PRESENT)
+ break;
+ /* copy the sense data */
+ data_len = c2->error_data.sense_data_len;
+ if (data_len > SCSI_SENSE_BUFFERSIZE)
+ data_len = SCSI_SENSE_BUFFERSIZE;
+ if (data_len > sizeof(c2->error_data.sense_data_buff))
+ data_len =
+ sizeof(c2->error_data.sense_data_buff);
+ memcpy(cmd->sense_buffer,
+ c2->error_data.sense_data_buff, data_len);
+ cmd->result |= SAM_STAT_CHECK_CONDITION;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_BUSY:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with BUSY status.\n",
+ "HP SSD Smart Path");
+ 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");
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL:
+ /* Make scsi midlayer do unlimited retries */
+ cmd->result = DID_IMM_RETRY << 16;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with aborted status.\n",
+ "HP SSD Smart Path");
+ break;
+ default:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with unrecognized status: 0x%02x\n",
+ "HP SSD Smart Path", c2->error_data.status);
+ break;
+ }
+ 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);
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_REJECTED:
+ dev_warn(&h->pdev->dev, "task management function rejected.\n");
+ 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);
+ break;
+ }
+}
+
+static void process_ioaccel2_completion(struct ctlr_info *h,
+ struct CommandList *c, struct scsi_cmnd *cmd,
+ struct hpsa_scsi_dev_t *dev)
+{
+ struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
+
+ /* 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;
+ }
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ if (is_logical_dev_addr_mode(dev->scsi3addr) &&
+ c2->error_data.serv_response ==
+ IOACCEL2_SERV_RESPONSE_FAILURE) {
+ if (c2->error_data.status !=
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev_warn(&h->pdev->dev,
+ "%s: Error 0x%02x, Retrying on standard path.\n",
+ "HP SSD Smart Path", c2->error_data.status);
+ dev->offload_enabled = 0;
+ cmd->result = DID_SOFT_ERROR << 16;
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ handle_ioaccel_mode2_error(h, c, cmd, c2);
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+}
+
static void complete_scsi_command(struct CommandList *cp)
{
struct scsi_cmnd *cmd;
@@ -1252,6 +1442,10 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+
+ if (cp->cmd_type == CMD_IOACCEL2)
+ return process_ioaccel2_completion(h, cp, cmd, dev);
+
cmd->result |= ei->ScsiStatus;
/* copy the sense data whether we need to or not. */
@@ -2470,10 +2664,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
return 0;
}
-/*
- * Queue a command to the I/O accelerator path.
- */
-static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
u8 *scsi3addr)
{
@@ -2545,6 +2736,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
control |= IOACCEL1_CONTROL_NODATAXFER;
}
+ c->Header.SGList = use_sg;
/* Fill out the command structure to submit */
cp->dev_handle = ioaccel_handle & 0xFFFF;
cp->transfer_len = total_len;
@@ -2553,19 +2745,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
cp->control = control;
memcpy(cp->CDB, cdb, cdb_len);
memcpy(cp->CISS_LUN, scsi3addr, 8);
-
- /* 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;
-
- /* Set the bits in the address sent down to include:
- * - performant mode bit (bit 0)
- * - pull count (bits 1-3)
- * - command type (bits 4-6)
- */
- c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[use_sg] << 1) |
- IOACCEL1_BUSADDR_CMDTYPE;
+ /* Tag was already set at init time. */
enqueue_cmd_and_start_io(h, c);
return 0;
}
@@ -2584,6 +2764,106 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
cmd->cmnd, cmd->cmd_len, dev->scsi3addr);
}
+static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
+ struct ioaccel2_sg_element *curr_sg;
+ int use_sg, i;
+ struct scatterlist *sg;
+ u64 addr64;
+ u32 len;
+ u32 total_len = 0;
+
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ 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 +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ memset(cp, 0, sizeof(*cp));
+ cp->IU_type = IOACCEL2_IU_TYPE;
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES);
+ 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->address = cpu_to_le64(addr64);
+ curr_sg->length = cpu_to_le32(len);
+ curr_sg->reserved[0] = 0;
+ curr_sg->reserved[1] = 0;
+ curr_sg->reserved[2] = 0;
+ curr_sg->chain_indicator = 0;
+ curr_sg++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ cp->direction = IOACCEL2_DIR_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ cp->direction = IOACCEL2_DIR_DATA_IN;
+ break;
+ case DMA_NONE:
+ cp->direction = IOACCEL2_DIR_NO_DATA;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ cp->direction = IOACCEL2_DIR_NO_DATA;
+ }
+ cp->scsi_nexus = ioaccel_handle;
+ cp->Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT;
+ memcpy(cp->cdb, cdb, sizeof(cp->cdb));
+ memset(cp->cciss_lun, 0, sizeof(cp->cciss_lun));
+ cp->cmd_priority_task_attr = 0;
+
+ /* 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));
+
+ enqueue_cmd_and_start_io(h, c);
+ return 0;
+}
+
+/*
+ * Queue a command to the correct I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+ else
+ return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+}
+
/*
* Attempt to perform offload RAID mapping for a logical volume I/O.
*/
@@ -4258,7 +4538,8 @@ static inline void finish_cmd(struct CommandList *c)
spin_unlock_irqrestore(&h->lock, flags);
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
- if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI))
+ 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);
@@ -5979,6 +6260,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
access = SA5_ioaccel_mode1_access;
writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ access = SA5_ioaccel_mode2_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ }
}
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 0e14e9b..45bb1ea 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -282,6 +282,18 @@ static void SA5_submit_command(struct ctlr_info *h,
(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
}
+static void SA5_submit_command_ioaccel2(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
+ c->Header.Tag.lower);
+ 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);
+ (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+}
+
/*
* This card is the opposite of the other cards.
* 0 turns interrupts on...
@@ -475,6 +487,14 @@ static struct access_method SA5_ioaccel_mode1_access = {
SA5_ioaccel_mode1_completed,
};
+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,
+};
+
static struct access_method SA5_performant_access = {
SA5_submit_command,
SA5_performant_intr_mask,
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index dfdb4a5..f6430b4 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -478,6 +478,7 @@ struct io_accel2_scsi_response {
#define IOACCEL2_STATUS_SR_TASK_COMP_RES_CON 0x18
#define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28
#define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40
+#define IOACCEL2_STATUS_SR_IOACCEL_DISABLED 0x0E
u8 data_present; /* low 2 bits */
#define IOACCEL2_NO_DATAPRESENT 0x000
#define IOACCEL2_RESPONSE_DATAPRESENT 0x001
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (23 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 24/41] hpsa: get ioaccel mode 2 i/o working Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-16 8:36 ` Hannes Reinecke
2014-01-15 22:38 ` [PATCH 26/41] hpsa: add task management for ioaccel mode 2 Stephen M. Cameron
` (15 subsequent siblings)
40 siblings, 1 reply; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 9628e12..7cab95f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1858,7 +1858,8 @@ out:
return rc;
}
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
+static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+ u8 reset_type)
{
int rc = IO_OK;
struct CommandList *c;
@@ -1872,8 +1873,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
}
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
- NULL, 0, 0, scsi3addr, TYPE_MSG);
+ (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 type */
hpsa_scsi_do_simple_cmd_core(h, c);
/* no unmap needed here because no data xfer. */
@@ -3397,7 +3398,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_send_reset(h, dev->scsi3addr);
+ 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;
^ permalink raw reply related [flat|nested] 46+ messages in thread* Re: [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset
2014-01-15 22:38 ` [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset Stephen M. Cameron
@ 2014-01-16 8:36 ` Hannes Reinecke
2014-01-16 13:33 ` Gates, Matt
0 siblings, 1 reply; 46+ messages in thread
From: Hannes Reinecke @ 2014-01-16 8:36 UTC (permalink / raw)
To: Stephen M. Cameron, jbottomley
Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
On 01/15/2014 11:38 PM, Stephen M. Cameron wrote:
> From: Scott Teel <scott.teel@hp.com>
>
> Signed-off-by: Scott Teel <scott.teel@hp.com>
> Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
> ---
> drivers/scsi/hpsa.c | 9 +++++----
> 1 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> index 9628e12..7cab95f 100644
> --- a/drivers/scsi/hpsa.c
> +++ b/drivers/scsi/hpsa.c
> @@ -1858,7 +1858,8 @@ out:
> return rc;
> }
>
> -static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
> +static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
> + u8 reset_type)
> {
> int rc = IO_OK;
> struct CommandList *c;
> @@ -1872,8 +1873,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
> }
>
> /* fill_cmd can't fail here, no data buffer to map. */
> - (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
> - NULL, 0, 0, scsi3addr, TYPE_MSG);
> + (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 type */
> hpsa_scsi_do_simple_cmd_core(h, c);
> /* no unmap needed here because no data xfer. */
>
> @@ -3397,7 +3398,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
> dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
> h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
> /* send a reset to the SCSI LUN which the command was sent to */
> - rc = hpsa_send_reset(h, dev->scsi3addr);
> + 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;
>
>
Would you mind using the correct eh_X callbacks here?
LUN Reset is _not_ identical to TARGET Reset (conceptually, at
least). And I'm currently trying to disentangle those;
idea is to have the actual device as the argument, not the command.
Having yet another driver which mangles those only serves to
increase the patch here ...
Thanks.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread* RE: [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset
2014-01-16 8:36 ` Hannes Reinecke
@ 2014-01-16 13:33 ` Gates, Matt
0 siblings, 0 replies; 46+ messages in thread
From: Gates, Matt @ 2014-01-16 13:33 UTC (permalink / raw)
To: Hannes Reinecke, Stephen M. Cameron, jbottomley@parallels.com
Cc: stephenmcameron@gmail.com, mikem@beardog.cce.hp.com,
linux-scsi@vger.kernel.org, Teel, Scott Stacy
Hi Hannes,
Just want to chime in to clarify that in the case of a 'device reset', I think the driver's use of LUN Reset to the Smart Array controller is the correct choice here. This is because the 'device' is actually a single logical unit on the controller (logical RAID volume). Sending a Target Reset to the controller would cause it to reset *all* its logical units (i.e., abort *all* pending commands on the entire controller, not just this single device), which isn't what we want here, I don't think.
So, I like the code as written in the sense that it's doing a LUN Reset to the controller. I wasn't sure if your reply below implied you thought a Target Reset was correct instead, or if you were just suggesting the correct use of eh_X callbacks... so again, just wanted to clarify this one detail.
Thanks,
Matt
> -----Original Message-----
> From: Hannes Reinecke [mailto:hare@suse.de]
> Sent: Thursday, January 16, 2014 2:37 AM
> To: Stephen M. Cameron; jbottomley@parallels.com
> Cc: stephenmcameron@gmail.com; mikem@beardog.cce.hp.com; Gates, Matt;
> linux-scsi@vger.kernel.org; Teel, Scott Stacy
> Subject: Re: [PATCH 25/41] hpsa: teach hpsa_device_reset to do either
> target or lun reset
>
> On 01/15/2014 11:38 PM, Stephen M. Cameron wrote:
> > From: Scott Teel <scott.teel@hp.com>
> >
> > Signed-off-by: Scott Teel <scott.teel@hp.com>
> > Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
> > ---
> > drivers/scsi/hpsa.c | 9 +++++----
> > 1 files changed, 5 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> > index 9628e12..7cab95f 100644
> > --- a/drivers/scsi/hpsa.c
> > +++ b/drivers/scsi/hpsa.c
> > @@ -1858,7 +1858,8 @@ out:
> > return rc;
> > }
> >
> > -static int hpsa_send_reset(struct ctlr_info *h, unsigned char
> *scsi3addr)
> > +static int hpsa_send_reset(struct ctlr_info *h, unsigned char
> *scsi3addr,
> > + u8 reset_type)
> > {
> > int rc = IO_OK;
> > struct CommandList *c;
> > @@ -1872,8 +1873,8 @@ static int hpsa_send_reset(struct ctlr_info *h,
> unsigned char *scsi3addr)
> > }
> >
> > /* fill_cmd can't fail here, no data buffer to map. */
> > - (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
> > - NULL, 0, 0, scsi3addr, TYPE_MSG);
> > + (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
> type */
> > hpsa_scsi_do_simple_cmd_core(h, c);
> > /* no unmap needed here because no data xfer. */
> >
> > @@ -3397,7 +3398,7 @@ static int hpsa_eh_device_reset_handler(struct
> scsi_cmnd *scsicmd)
> > dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
> > h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
> > /* send a reset to the SCSI LUN which the command was sent to */
> > - rc = hpsa_send_reset(h, dev->scsi3addr);
> > + 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;
> >
> >
> Would you mind using the correct eh_X callbacks here?
> LUN Reset is _not_ identical to TARGET Reset (conceptually, at
> least). And I'm currently trying to disentangle those;
> idea is to have the actual device as the argument, not the command.
>
> Having yet another driver which mangles those only serves to
> increase the patch here ...
>
> Thanks.
>
> Cheers,
>
> Hannes
> --
> Dr. Hannes Reinecke zSeries & Storage
> hare@suse.de +49 911 74053 688
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
> GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply [flat|nested] 46+ messages in thread
* [PATCH 26/41] hpsa: add task management for ioaccel mode 2
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (24 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 27/41] hpsa: make device update copy the raid map also Stephen M. Cameron
` (14 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Underlying firmware cannot handle task abort on accelerated path (SSD Smart Path).
Change abort requests for accelerated path commands to physical target reset.
Send reset request on normal IO path.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/scsi/hpsa_cmd.h | 7 +-
2 files changed, 170 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 7cab95f..6a6026b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2306,6 +2306,85 @@ static int add_ext_target_dev(struct ctlr_info *h,
}
/*
+ * Get address of physical disk used for an ioaccel2 mode command:
+ * 1. Extract ioaccel2 handle from the command.
+ * 2. Find a matching ioaccel2 handle from list of physical disks.
+ * 3. Return:
+ * 1 and set scsi3addr to address of matching physical
+ * 0 if no matching physical disk was found.
+ */
+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 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) */
+ u32 find; /* handle we need to match */
+ 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;
+
+ /* Get the list of physical devices */
+ physicals = kzalloc(reportsize, GFP_KERNEL);
+ if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
+ reportsize, extended)) {
+ 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++) {
+ /* handle is in bytes 28-31 of each lun */
+ if (memcmp(&((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20], &find, 4) != 0) {
+ continue; /* didn't match */
+ }
+ found = 1;
+ memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][0], 8);
+ break; /* found it */
+ }
+
+ kfree(physicals);
+ if (found)
+ return 1;
+ else
+ 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
* *nphysicals and *nlogicals, respectively.
@@ -3429,12 +3508,20 @@ static void hpsa_get_tag(struct ctlr_info *h,
&h->ioaccel_cmd_pool[c->cmdindex];
*tagupper = cm1->Tag.upper;
*taglower = cm1->Tag.lower;
- } else {
- *tagupper = c->Header.Tag.upper;
- *taglower = c->Header.Tag.lower;
+ return;
+ }
+ if (c->cmd_type == CMD_IOACCEL2) {
+ struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
+ &h->ioaccel2_cmd_pool[c->cmdindex];
+ *tagupper = cm2->Tag.upper;
+ *taglower = cm2->Tag.lower;
+ return;
}
+ *tagupper = c->Header.Tag.upper;
+ *taglower = c->Header.Tag.lower;
}
+
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *abort, int swizzle)
{
@@ -3530,6 +3617,74 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
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.
+ * Return 0 on success (IO_OK)
+ * -1 on failure
+ */
+
+static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct CommandList *abort)
+{
+ int rc = IO_OK;
+ struct scsi_cmnd *scmd; /* scsi command within request being aborted */
+ struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
+ unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
+ unsigned char *psa = &phys_scsi3addr[0];
+
+ /* Get a pointer to the hpsa logical device. */
+ scmd = (struct scsi_cmnd *) abort->scsi_cmd;
+ dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
+ if (dev == NULL) {
+ dev_warn(&h->pdev->dev,
+ "Cannot abort: no device pointer for command.\n");
+ return -1; /* not abortable */
+ }
+
+ if (!dev->offload_enabled) {
+ dev_warn(&h->pdev->dev,
+ "Can't abort: device is not operating in HP SSD Smart Path mode.\n");
+ return -1; /* not abortable */
+ }
+
+ /* Incoming scsi3addr is logical addr. We need physical disk addr. */
+ if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
+ dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
+ return -1; /* not abortable */
+ }
+
+ /* send the reset */
+ rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET);
+ 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",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+ return rc; /* failed to reset */
+ }
+
+ /* wait for device to recover */
+ if (wait_for_device_to_become_ready(h, psa) != 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],
+ psa[4], psa[5], psa[6], psa[7]);
+ return -1; /* failed to recover */
+ }
+
+ /* device recovered */
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Device recovered from reset: "
+ "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]);
+
+ 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
@@ -3543,6 +3698,14 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
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.
+ * Change abort to physical device reset.
+ */
+ 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.
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index f6430b4..e048167 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -82,8 +82,9 @@
#define ATTR_ACA 0x07
/* cdb type */
-#define TYPE_CMD 0x00
-#define TYPE_MSG 0x01
+#define TYPE_CMD 0x00
+#define TYPE_MSG 0x01
+#define TYPE_IOACCEL2_CMD 0x81 /* 0x81 is not used by hardware */
/* Message Types */
#define HPSA_TASK_MANAGEMENT 0x00
@@ -525,7 +526,7 @@ struct io_accel2_cmd {
* FIXME: this can't be all I need mfm
*/
#define IOACCEL2_IU_TYPE 0x40
-#define IU_TYPE_TMF 0x41
+#define IOACCEL2_IU_TMF_TYPE 0x41
#define IOACCEL2_DIR_NO_DATA 0x00
#define IOACCEL2_DIR_DATA_IN 0x01
#define IOACCEL2_DIR_DATA_OUT 0x02
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 27/41] hpsa: make device update copy the raid map also
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (25 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 26/41] hpsa: add task management for ioaccel mode 2 Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 28/41] hpsa: complete the ioaccel raidmap code Stephen M. Cameron
` (13 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Otherwise we could wind up using incorrect raid map data, and
then very bad things would likely happen.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6a6026b..cf208e5 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -891,6 +891,9 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
/* Raid offload parameters changed. */
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;
dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 28/41] hpsa: complete the ioaccel raidmap code
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (26 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 27/41] hpsa: make device update copy the raid map also Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 29/41] hpsa: allow user to disable accelerated i/o path Stephen M. Cameron
` (12 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Load balance across members of a N-way mirror set, and
handle the meta-RAID levels: R10, R50, R60.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 168 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index cf208e5..0109bf7 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -423,6 +423,13 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"1(ADM)", "UNKNOWN"
};
+#define HPSA_RAID_0 0
+#define HPSA_RAID_4 1
+#define HPSA_RAID_1 2 /* also used for RAID 10 */
+#define HPSA_RAID_5 3 /* also used for RAID 50 */
+#define HPSA_RAID_51 4
+#define HPSA_RAID_6 5 /* also used for RAID 60 */
+#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
static ssize_t raid_level_show(struct device *dev,
@@ -2947,6 +2954,31 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
cdb, cdb_len, scsi3addr);
}
+static void raid_map_helper(struct raid_map_data *map,
+ int offload_to_mirror, u32 *map_index, u32 *current_group)
+{
+ if (offload_to_mirror == 0) {
+ /* use physical disk in the first mirrored group. */
+ *map_index %= map->data_disks_per_row;
+ return;
+ }
+ do {
+ /* determine mirror group that *map_index indicates */
+ *current_group = *map_index / map->data_disks_per_row;
+ if (offload_to_mirror == *current_group)
+ continue;
+ if (*current_group < (map->layout_map_count - 1)) {
+ /* select map index from next group */
+ *map_index += map->data_disks_per_row;
+ (*current_group)++;
+ } else {
+ /* select map index from first group */
+ *map_index %= map->data_disks_per_row;
+ *current_group = 0;
+ }
+ } while (offload_to_mirror != *current_group);
+}
+
/*
* Attempt to perform offload RAID mapping for a logical volume I/O.
*/
@@ -2965,6 +2997,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
u64 first_row, last_row;
u32 first_row_offset, last_row_offset;
u32 first_column, last_column;
+ u64 r0_first_row, r0_last_row;
+ u32 r5or6_blocks_per_row;
+ u64 r5or6_first_row, r5or6_last_row;
+ u32 r5or6_first_row_offset, r5or6_last_row_offset;
+ u32 r5or6_first_column, r5or6_last_column;
+ u32 total_disks_per_row;
+ u32 stripesize;
+ u32 first_group, last_group, current_group;
u32 map_row;
u32 disk_handle;
u64 disk_block;
@@ -2974,6 +3014,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
#if BITS_PER_LONG == 32
u64 tmpdiv;
#endif
+ int offload_to_mirror;
BUG_ON(!(dev->offload_config && dev->offload_enabled));
@@ -3076,19 +3117,140 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
return IO_ACCEL_INELIGIBLE;
/* proceeding with driver mapping */
+ total_disks_per_row = map->data_disks_per_row +
+ map->metadata_disks_per_row;
map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
map->row_cnt;
- map_index = (map_row * (map->data_disks_per_row +
- map->metadata_disks_per_row)) + first_column;
- if (dev->raid_level == 2) {
- /* simple round-robin balancing of RAID 1+0 reads across
- * primary and mirror members. this is appropriate for SSD
- * but not optimal for HDD.
+ map_index = (map_row * total_disks_per_row) + first_column;
+
+ switch (dev->raid_level) {
+ case HPSA_RAID_0:
+ break; /* nothing special to do */
+ case HPSA_RAID_1:
+ /* Handles load balance across RAID 1 members.
+ * (2-drive R1 and R10 with even # of drives.)
+ * Appropriate for SSDs, not optimal for HDDs
*/
+ BUG_ON(map->layout_map_count != 2);
if (dev->offload_to_mirror)
map_index += map->data_disks_per_row;
dev->offload_to_mirror = !dev->offload_to_mirror;
+ break;
+ case HPSA_RAID_ADM:
+ /* Handles N-way mirrors (R1-ADM)
+ * and R10 with # of drives divisible by 3.)
+ */
+ BUG_ON(map->layout_map_count != 3);
+
+ offload_to_mirror = dev->offload_to_mirror;
+ raid_map_helper(map, offload_to_mirror,
+ &map_index, ¤t_group);
+ /* set mirror group to use next time */
+ 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
+ * increment it beyond the range of dev->layout_map_count -1.
+ */
+ break;
+ case HPSA_RAID_5:
+ case HPSA_RAID_6:
+ if (map->layout_map_count <= 1)
+ break;
+
+ /* Verify first and last block are in same RAID group */
+ r5or6_blocks_per_row =
+ map->strip_size * map->data_disks_per_row;
+ BUG_ON(r5or6_blocks_per_row == 0);
+ stripesize = r5or6_blocks_per_row * map->layout_map_count;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_group = do_div(tmpdiv, stripesize);
+ tmpdiv = first_group;
+ (void) do_div(tmpdiv, r5or6_blocks_per_row);
+ first_group = tmpdiv;
+ tmpdiv = last_block;
+ last_group = do_div(tmpdiv, stripesize);
+ tmpdiv = last_group;
+ (void) do_div(tmpdiv, r5or6_blocks_per_row);
+ last_group = tmpdiv;
+#else
+ first_group = (first_block % stripesize) / r5or6_blocks_per_row;
+ last_group = (last_block % stripesize) / r5or6_blocks_per_row;
+ if (first_group != last_group)
+#endif
+ return IO_ACCEL_INELIGIBLE;
+
+ /* Verify request is in a single row of RAID 5/6 */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, stripesize);
+ first_row = r5or6_first_row = r0_first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) do_div(tmpdiv, stripesize);
+ r5or6_last_row = r0_last_row = tmpdiv;
+#else
+ first_row = r5or6_first_row = r0_first_row =
+ first_block / stripesize;
+ r5or6_last_row = r0_last_row = last_block / stripesize;
+#endif
+ if (r5or6_first_row != r5or6_last_row)
+ return IO_ACCEL_INELIGIBLE;
+
+
+ /* Verify request is in a single column */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = first_row_offset;
+ first_row_offset = (u32) do_div(tmpdiv, r5or6_blocks_per_row);
+ r5or6_first_row_offset = first_row_offset;
+ tmpdiv = last_block;
+ r5or6_last_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = r5or6_last_row_offset;
+ r5or6_last_row_offset = do_div(tmpdiv, r5or6_blocks_per_row);
+ tmpdiv = r5or6_first_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = r5or6_first_column = tmpdiv;
+ tmpdiv = r5or6_last_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ r5or6_last_column = tmpdiv;
+#else
+ first_row_offset = r5or6_first_row_offset =
+ (u32)((first_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ r5or6_last_row_offset =
+ (u32)((last_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ first_column = r5or6_first_column =
+ r5or6_first_row_offset / map->strip_size;
+ r5or6_last_column =
+ r5or6_last_row_offset / map->strip_size;
+#endif
+ if (r5or6_first_column != r5or6_last_column)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* Request is eligible */
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+
+ map_index = (first_group *
+ (map->row_cnt * total_disks_per_row)) +
+ (map_row * total_disks_per_row) + first_column;
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE;
}
+
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));
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 29/41] hpsa: allow user to disable accelerated i/o path
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (27 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 28/41] hpsa: complete the ioaccel raidmap code Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 30/41] hpsa: rescan devices on ioaccel2 error Stephen M. Cameron
` (11 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Allow SSD Smart Path for a controller to be disabled by
the user, regardless of settings in controller firmware
or array configuration.
To disable: echo 0 > /sys/class/scsi_host/host<id>/acciopath_status
To re-enable: echo 1 > /sys/class/scsi_host/host<id>/acciopath_status
To check state: cat /sys/class/scsi_host/host<id>/acciopath_status
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
Documentation/ABI/testing/sysfs-class-scsi_host | 16 ++++++++
drivers/scsi/hpsa.c | 45 ++++++++++++++++++++++-
drivers/scsi/hpsa.h | 1 +
3 files changed, 61 insertions(+), 1 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host
index 29a4f89..0eb255e 100644
--- a/Documentation/ABI/testing/sysfs-class-scsi_host
+++ b/Documentation/ABI/testing/sysfs-class-scsi_host
@@ -11,3 +11,19 @@ Description:
guaranteed. The 'isci_id' attribute unambiguously identifies
the controller index: '0' for the first controller,
'1' for the second.
+
+What: /sys/class/scsi_host/hostX/acciopath_status
+Date: November 2013
+Contact: Stephen M. Cameron <scameron@beardog.cce.hp.com>
+Description: This file contains the current status of the "SSD Smart Path"
+ feature of HP Smart Array RAID controllers using the hpsa
+ driver. SSD Smart Path, when enabled permits the driver to
+ send i/o requests directly to physical devices that are part
+ of a logical drive, bypassing the controllers firmware RAID
+ stack for a performance advantage when possible. A value of
+ '1' indicates the feature is enabled, and the controller may
+ use the direct i/o path to physical devices. A value of zero
+ means the feature is disabled and the controller may not use
+ the direct i/o path to physical devices. This setting is
+ controller wide, affecting all configured logical drives on the
+ controller. This file is readable and writable.
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0109bf7..8e357f0 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -287,6 +287,30 @@ static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
return 1;
}
+static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int status, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ 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", &status) != 1)
+ return -EINVAL;
+ h = shost_to_hba(shost);
+ h->acciopath_status = !!status;
+ dev_warn(&h->pdev->dev,
+ "hpsa: HP SSD Smart Path %s via sysfs update.\n",
+ h->acciopath_status ? "enabled" : "disabled");
+ return count;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -334,6 +358,17 @@ static ssize_t host_show_transport_mode(struct device *dev,
"performant" : "simple");
}
+static ssize_t host_show_hp_ssd_smart_path_status(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, 30, "HP SSD Smart Path %s\n",
+ (h->acciopath_status == 1) ? "enabled" : "disabled");
+}
+
/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
0x324a103C, /* Smart Array P712m */
@@ -546,6 +581,9 @@ static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
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,
+ host_show_hp_ssd_smart_path_status,
+ host_store_hp_ssd_smart_path_status);
static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
@@ -569,6 +607,7 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_commands_outstanding,
&dev_attr_transport_mode,
&dev_attr_resettable,
+ &dev_attr_hp_ssd_smart_path_status,
NULL,
};
@@ -3347,7 +3386,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
* Retries always go down the normal I/O path.
*/
if (likely(cmd->retries == 0 &&
- cmd->request->cmd_type == REQ_TYPE_FS)) {
+ 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)
@@ -6333,6 +6373,9 @@ reinit_after_soft_reset:
goto reinit_after_soft_reset;
}
+ /* Enable Accelerated IO path at driver layer */
+ h->acciopath_status = 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 45bb1ea..1d3340d 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -181,6 +181,7 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
u32 events;
+ int acciopath_status;
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 30/41] hpsa: rescan devices on ioaccel2 error
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (28 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 29/41] hpsa: allow user to disable accelerated i/o path Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 31/41] hpsa: allow VPD page zero to be queried Stephen M. Cameron
` (10 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Allow driver to schedule a rescan whenever a request fails on the ioaccel2 path.
This eliminates the possibility of driver getting stuck in non-ioaccel mode.
IOaccel mode (HP SSD Smart Path) is disabled by driver upon error detection.
Driver relied on idea that request would be retried through normal path, and
a subsequent error would occur on that path, and be processed by controller firmware.
As part of that process, controller disables ioaccel mode and later reinstates it,
signalling driver to change modes.
In some error cases, the error will not duplicate on the standard path,
so the driver could get stuck in non-ioaccel mode.
To avoid that, we allow driver to request a rescan during the next run of the
rescan thread.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 12 ++++++++++--
drivers/scsi/hpsa.h | 1 +
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 8e357f0..8f9a9fe 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1457,6 +1457,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
"%s: Error 0x%02x, Retrying on standard path.\n",
"HP SSD Smart Path", c2->error_data.status);
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);
@@ -6145,6 +6146,9 @@ static int hpsa_kickoff_rescan(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)) &&
@@ -6192,7 +6196,9 @@ static int hpsa_kickoff_rescan(struct ctlr_info *h)
/* Check a register on the controller to see if there are configuration
* changes (added/changed/removed logical drives, etc.) which mean that
- * we should rescan the controller for devices. If so, add the controller
+ * we should rescan the controller for devices.
+ * Also check flag for driver-initiated rescan.
+ * If either flag or controller event indicate rescan, add the controller
* to the list of controllers needing to be rescanned, and gets a
* reference to the associated scsi_host.
*/
@@ -6202,7 +6208,7 @@ static void hpsa_ctlr_needs_rescan(struct ctlr_info *h)
return;
h->events = readl(&(h->cfgtable->event_notify));
- if (!h->events)
+ if (!h->events && !h->drv_req_rescan)
return;
/*
@@ -6376,6 +6382,8 @@ reinit_after_soft_reset:
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
+ h->drv_req_rescan = 0;
+
/* 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 1d3340d..2e7521f 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -182,6 +182,7 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
u32 events;
int acciopath_status;
+ int drv_req_rescan; /* flag for driver to request rescan event */
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 31/41] hpsa: allow VPD page zero to be queried
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (29 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 30/41] hpsa: rescan devices on ioaccel2 error Stephen M. Cameron
@ 2014-01-15 22:38 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 32/41] hpsa: do not inquire for unsupported ioaccel status vpd page Stephen M. Cameron
` (9 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:38 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Code was confused and assumed that page zero was not
VPD page and all non-zero pages were VPD pages.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 8f9a9fe..14862f9 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -183,8 +183,9 @@ 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, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type);
+#define VPD_PAGE (1 << 8)
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
@@ -1878,7 +1879,7 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
}
static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
- unsigned char page, unsigned char *buf,
+ u16 page, unsigned char *buf,
unsigned char bufsize)
{
int rc = IO_OK;
@@ -1947,7 +1948,7 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0xC1, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0xC1, buf, 64);
if (rc == 0)
*raid_level = buf[8];
if (*raid_level > RAID_UNKNOWN)
@@ -2076,7 +2077,7 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h,
if (!buf)
return;
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
- HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
+ VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
if (rc != 0)
goto out;
@@ -2109,7 +2110,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return -1;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0x83, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
if (rc == 0)
memcpy(device_id, &buf[8], buflen);
kfree(buf);
@@ -4638,7 +4639,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
}
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type)
{
int pci_dir = XFER_NONE;
@@ -4661,10 +4662,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
switch (cmd) {
case HPSA_INQUIRY:
/* are we trying to read a vital product page */
- if (page_code != 0) {
+ if (page_code & VPD_PAGE)
c->Request.CDB[1] = 0x01;
- c->Request.CDB[2] = page_code;
- }
+ c->Request.CDB[2] = (page_code & 0xff);
c->Request.CDBLen = 6;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 32/41] hpsa: do not inquire for unsupported ioaccel status vpd page
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (30 preceding siblings ...)
2014-01-15 22:38 ` [PATCH 31/41] hpsa: allow VPD page zero to be queried Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 33/41] hpsa: retry certain ioaccel error cases on the RAID path Stephen M. Cameron
` (8 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/hpsa_cmd.h | 2 ++
2 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 14862f9..f78d08b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2063,6 +2063,49 @@ static int hpsa_get_raid_map(struct ctlr_info *h,
return rc;
}
+static int hpsa_vpd_page_supported(struct ctlr_info *h,
+ unsigned char scsi3addr[], u8 page)
+{
+ int rc;
+ int i;
+ int pages;
+ unsigned char *buf, bufsize;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Get the size of the page list first */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, HPSA_VPD_HEADER_SZ);
+ if (rc != 0)
+ goto exit_unsupported;
+ pages = buf[3];
+ if ((pages + HPSA_VPD_HEADER_SZ) <= 255)
+ bufsize = pages + HPSA_VPD_HEADER_SZ;
+ else
+ bufsize = 255;
+
+ /* Get the whole VPD page list */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, bufsize);
+ if (rc != 0)
+ goto exit_unsupported;
+
+ pages = buf[3];
+ for (i = 1; i <= pages; i++)
+ if (buf[3 + i] == page)
+ goto exit_supported;
+exit_unsupported:
+ kfree(buf);
+ return 0;
+exit_supported:
+ kfree(buf);
+ return 1;
+}
+
static void hpsa_get_ioaccel_status(struct ctlr_info *h,
unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
{
@@ -2076,6 +2119,8 @@ static void hpsa_get_ioaccel_status(struct ctlr_info *h,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return;
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_IOACCEL_STATUS))
+ goto out;
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
if (rc != 0)
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index e048167..769fd2a 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -144,8 +144,10 @@
#define CFGTBL_BusType_Fibre2G 0x00000200l
/* VPD Inquiry types */
+#define HPSA_VPD_SUPPORTED_PAGES 0x00
#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
#define HPSA_VPD_LV_IOACCEL_STATUS 0xC2
+#define HPSA_VPD_HEADER_SZ 4
struct vals32 {
u32 lower;
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 33/41] hpsa: retry certain ioaccel error cases on the RAID path
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (31 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 32/41] hpsa: do not inquire for unsupported ioaccel status vpd page Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 34/41] hpsa: update source file copyrights Stephen M. Cameron
` (7 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Change the handling of HP SSD Smart Path errors with status:
0x02 CHECK CONDITION
0x08 BUSY
0x18 RESERVATION CONFLICT
0x40 TASK ABORTED
So that they get retried on the RAID Path.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 45 +++++++++++++++++++++++++++++++++++++++------
1 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index f78d08b..6ff47ba 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1351,12 +1351,18 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
}
-static void handle_ioaccel_mode2_error(struct ctlr_info *h,
+
+/* Decode the various types of errors on ioaccel2 path.
+ * Return 1 for any error that should generate a RAID path retry.
+ * Return 0 for errors that don't require a RAID path retry.
+ */
+static int handle_ioaccel_mode2_error(struct ctlr_info *h,
struct CommandList *c,
struct scsi_cmnd *cmd,
struct io_accel2_cmd *c2)
{
int data_len;
+ int retry = 0;
switch (c2->error_data.serv_response) {
case IOACCEL2_SERV_RESPONSE_COMPLETE:
@@ -1380,16 +1386,19 @@ static void handle_ioaccel_mode2_error(struct ctlr_info *h,
memcpy(cmd->sense_buffer,
c2->error_data.sense_data_buff, data_len);
cmd->result |= SAM_STAT_CHECK_CONDITION;
+ 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:
/* Make scsi midlayer do unlimited retries */
@@ -1399,11 +1408,13 @@ static void handle_ioaccel_mode2_error(struct ctlr_info *h,
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;
}
break;
@@ -1412,6 +1423,7 @@ static void handle_ioaccel_mode2_error(struct ctlr_info *h,
dev_warn(&h->pdev->dev,
"unexpected delivery or target failure, "
"status = 0x%02x\n", c2->error_data.status);
+ retry = 1;
break;
case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
break;
@@ -1419,6 +1431,7 @@ static void handle_ioaccel_mode2_error(struct ctlr_info *h,
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");
@@ -1426,9 +1439,13 @@ static void handle_ioaccel_mode2_error(struct ctlr_info *h,
default:
dev_warn(&h->pdev->dev,
"%s: Unrecognized server response: 0x%02x\n",
- "HP SSD Smart Path", c2->error_data.serv_response);
+ "HP SSD Smart Path",
+ c2->error_data.serv_response);
+ retry = 1;
break;
}
+
+ return retry; /* retry on raid path? */
}
static void process_ioaccel2_completion(struct ctlr_info *h,
@@ -1436,6 +1453,7 @@ 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 &&
@@ -1452,11 +1470,16 @@ 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) {
- if (c2->error_data.status !=
- IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ if (c2->error_data.status ==
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev_warn(&h->pdev->dev,
+ "%s: Path is unavailable, retrying on standard path.\n",
+ "HP SSD Smart Path");
+ else
dev_warn(&h->pdev->dev,
- "%s: Error 0x%02x, Retrying on standard path.\n",
+ "%s: Error 0x%02x, retrying on standard path.\n",
"HP SSD Smart Path", c2->error_data.status);
+
dev->offload_enabled = 0;
h->drv_req_rescan = 1; /* schedule controller for a rescan */
cmd->result = DID_SOFT_ERROR << 16;
@@ -1464,7 +1487,17 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
cmd->scsi_done(cmd);
return;
}
- handle_ioaccel_mode2_error(h, c, cmd, c2);
+ 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 (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);
cmd->scsi_done(cmd);
}
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 34/41] hpsa: update source file copyrights
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (32 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 33/41] hpsa: retry certain ioaccel error cases on the RAID path Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 35/41] hpsa: add controller base data-at-rest encryption compatibility ioaccel2 Stephen M. Cameron
` (6 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 2 +-
drivers/scsi/hpsa.h | 2 +-
drivers/scsi/hpsa_cmd.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6ff47ba..5278cf0 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 2e7521f..fe813e9 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 769fd2a..7768092 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 35/41] hpsa: add controller base data-at-rest encryption compatibility ioaccel2
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (33 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 34/41] hpsa: update source file copyrights Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 36/41] hpsa: when switching out of accel mode await only accel command completions Stephen M. Cameron
` (5 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Scott Teel <scott.teel@hp.com>
Add controller-based data-at-rest encryption compatibility
to ioaccel2 path (HP SSD Smart Path).
Encryption feature requires driver to supply additional fields
for encryption enable, tweak index, and data encryption key index
in the ioaccel2 request structure.
Encryption enable flag and data encryption key index come from
raid_map data structure from raid offload command.
During ioaccel2 submission, check device structure's raid map to see if
encryption is enabled for the device. If so, call new function below.
Add function set_encrypt_ioaccel2 to set encryption flag, data encryption key
index, and calculate tweak value from request's logical block address.
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 179 +++++++++++++++++++++++++++++++++++++++++++++--
drivers/scsi/hpsa_cmd.h | 19 ++++-
2 files changed, 184 insertions(+), 14 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 5278cf0..7764e5c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2026,6 +2026,14 @@ static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
le16_to_cpu(map_buff->row_cnt));
dev_info(&h->pdev->dev, "layout_map_count = %u\n",
le16_to_cpu(map_buff->layout_map_count));
+ dev_info(&h->pdev->dev, "flags = %u\n",
+ le16_to_cpu(map_buff->flags));
+ if (map_buff->flags & RAID_MAP_FLAG_ENCRYPT_ON)
+ dev_info(&h->pdev->dev, "encrypytion = ON\n");
+ else
+ dev_info(&h->pdev->dev, "encrypytion = OFF\n");
+ dev_info(&h->pdev->dev, "dekindex = %u\n",
+ le16_to_cpu(map_buff->dekindex));
map_cnt = le16_to_cpu(map_buff->layout_map_count);
for (map = 0; map < map_cnt; map++) {
@@ -2973,6 +2981,128 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
cmd->cmnd, cmd->cmd_len, dev->scsi3addr);
}
+/*
+ * 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 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;
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* 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;
+
+ /* Set the encryption enable flag, encoded into direction field. */
+ cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK;
+
+ /* Set encryption tweak values based on logical block address
+ * If block size is 512, tweak value is LBA.
+ * For other block sizes, tweak is (LBA * block size)/ 512)
+ */
+ switch (cmd->cmnd[0]) {
+ /* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_6:
+ case READ_6:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_10:
+ case READ_10:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ /* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_12:
+ case READ_12:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_16:
+ case READ_16:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ cp->tweak_upper =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ default:
+ dev_err(&h->pdev->dev,
+ "ERROR: %s: IOACCEL request CDB size not supported for encryption\n",
+ __func__);
+ BUG();
+ break;
+ }
+}
+
static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
u8 *scsi3addr)
@@ -3022,13 +3152,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
switch (cmd->sc_data_direction) {
case DMA_TO_DEVICE:
- cp->direction = IOACCEL2_DIR_DATA_OUT;
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_OUT;
break;
case DMA_FROM_DEVICE:
- cp->direction = IOACCEL2_DIR_DATA_IN;
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_IN;
break;
case DMA_NONE:
- cp->direction = IOACCEL2_DIR_NO_DATA;
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
break;
default:
dev_err(&h->pdev->dev, "unknown data direction: %d\n",
@@ -3037,10 +3170,15 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
break;
}
} else {
- cp->direction = IOACCEL2_DIR_NO_DATA;
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
}
+
+ /* Set encryption parameters, if necessary */
+ set_encrypt_ioaccel2(h, c, cp);
+
cp->scsi_nexus = ioaccel_handle;
- cp->Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
+ cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
DIRECT_LOOKUP_BIT;
memcpy(cp->cdb, cdb, sizeof(cp->cdb));
memset(cp->cciss_lun, 0, sizeof(cp->cciss_lun));
@@ -3798,8 +3936,9 @@ static void hpsa_get_tag(struct ctlr_info *h,
if (c->cmd_type == CMD_IOACCEL2) {
struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
&h->ioaccel2_cmd_pool[c->cmdindex];
- *tagupper = cm2->Tag.upper;
- *taglower = cm2->Tag.lower;
+ /* upper tag not used in ioaccel2 mode */
+ memset(tagupper, 0, sizeof(*tagupper));
+ *taglower = cm2->Tag;
return;
}
*tagupper = c->Header.Tag.upper;
@@ -3847,8 +3986,8 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
break;
}
cmd_special_free(h, c);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
+ __func__, tagupper, taglower);
return rc;
}
@@ -6977,6 +7116,28 @@ static void __exit hpsa_cleanup(void)
static void __attribute__((unused)) verify_offsets(void)
{
#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct raid_map_data, member) != offset)
+
+ VERIFY_OFFSET(structure_size, 0);
+ VERIFY_OFFSET(volume_blk_size, 4);
+ VERIFY_OFFSET(volume_blk_cnt, 8);
+ VERIFY_OFFSET(phys_blk_shift, 16);
+ VERIFY_OFFSET(parity_rotation_shift, 17);
+ VERIFY_OFFSET(strip_size, 18);
+ VERIFY_OFFSET(disk_starting_blk, 20);
+ VERIFY_OFFSET(disk_blk_cnt, 28);
+ VERIFY_OFFSET(data_disks_per_row, 36);
+ VERIFY_OFFSET(metadata_disks_per_row, 38);
+ VERIFY_OFFSET(row_cnt, 40);
+ VERIFY_OFFSET(layout_map_count, 42);
+ VERIFY_OFFSET(flags, 44);
+ VERIFY_OFFSET(dekindex, 46);
+ /* VERIFY_OFFSET(reserved, 48 */
+ VERIFY_OFFSET(data, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
BUILD_BUG_ON(offsetof(struct io_accel2_cmd, member) != offset)
VERIFY_OFFSET(IU_type, 0);
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 7768092..eaa7fda 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -209,7 +209,10 @@ struct raid_map_data {
u16 row_cnt; /* rows in each layout map */
u16 layout_map_count; /* layout maps (1 map per mirror/parity
* group) */
- u8 reserved[20];
+ u16 flags; /* Bit 0 set if encryption enabled */
+#define RAID_MAP_FLAG_ENCRYPT_ON 0x01
+ u16 dekindex; /* Data encryption key index. */
+ u8 reserved[16];
struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES];
};
@@ -502,11 +505,17 @@ struct io_accel2_scsi_response {
*/
struct io_accel2_cmd {
u8 IU_type; /* IU Type */
- u8 direction; /* Transfer direction, 2 bits */
+ u8 direction; /* direction, memtype, and encryption */
+#define IOACCEL2_DIRECTION_MASK 0x03 /* bits 0,1: direction */
+#define IOACCEL2_DIRECTION_MEMTYPE_MASK 0x04 /* bit 2: memtype source/dest */
+ /* 0b=PCIe, 1b=DDR */
+#define IOACCEL2_DIRECTION_ENCRYPT_MASK 0x08 /* bit 3: encryption flag */
+ /* 0=off, 1=on */
u8 reply_queue; /* Reply Queue ID */
u8 reserved1; /* Reserved */
u32 scsi_nexus; /* Device Handle */
- struct vals32 Tag; /* cciss tag */
+ u32 Tag; /* cciss tag, lower 4 bytes only */
+ u32 tweak_lower; /* Encryption tweak, lower 4 bytes */
u8 cdb[16]; /* SCSI Command Descriptor Block */
u8 cciss_lun[8]; /* 8 byte SCSI address */
u32 data_len; /* Total bytes to transfer */
@@ -514,10 +523,10 @@ struct io_accel2_cmd {
#define IOACCEL2_PRIORITY_MASK 0x78
#define IOACCEL2_ATTR_MASK 0x07
u8 sg_count; /* Number of sg elements */
- u8 reserved3[2]; /* Reserved */
+ u16 dekindex; /* Data encryption key index */
u64 err_ptr; /* Error Pointer */
u32 err_len; /* Error Length*/
- u8 reserved4[4]; /* Reserved */
+ u32 tweak_upper; /* Encryption tweak, upper 4 bytes */
struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];
struct io_accel2_scsi_response error_data;
u8 pad[IOACCEL2_PAD];
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 36/41] hpsa: when switching out of accel mode await only accel command completions
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (34 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 35/41] hpsa: add controller base data-at-rest encryption compatibility ioaccel2 Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 37/41] hpsa: only do device rescan for certain events Stephen M. Cameron
` (4 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Don't wait for *all* commands to complete, only for accelerated mode
commands.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 22 ++++++++++++++++------
1 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 7764e5c..0082baa 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -221,7 +221,7 @@ static inline void finish_cmd(struct CommandList *c);
static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
-static void hpsa_drain_commands(struct ctlr_info *h);
+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,
@@ -6380,7 +6380,7 @@ static int hpsa_kickoff_rescan(struct ctlr_info *h)
scsi_block_requests(h->scsi_host);
for (i = 0; i < h->ndevices; i++)
h->dev[i]->offload_enabled = 0;
- hpsa_drain_commands(h);
+ hpsa_drain_accel_commands(h);
/* Set 'accelerator path config change' bit */
dev_warn(&h->pdev->dev,
"Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
@@ -7084,16 +7084,26 @@ clean_up:
kfree(h->blockFetchTable);
}
-static void hpsa_drain_commands(struct ctlr_info *h)
+static int is_accelerated_cmd(struct CommandList *c)
{
- int cmds_out;
+ return c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_IOACCEL2;
+}
+
+static void hpsa_drain_accel_commands(struct ctlr_info *h)
+{
+ struct CommandList *c = NULL;
unsigned long flags;
+ int accel_cmds_out;
do { /* wait for all outstanding commands to drain out */
+ accel_cmds_out = 0;
spin_lock_irqsave(&h->lock, flags);
- cmds_out = h->commands_outstanding;
+ list_for_each_entry(c, &h->cmpQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
+ list_for_each_entry(c, &h->reqQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
spin_unlock_irqrestore(&h->lock, flags);
- if (cmds_out <= 0)
+ if (accel_cmds_out <= 0)
break;
msleep(100);
} while (1);
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 37/41] hpsa: only do device rescan for certain events
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (35 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 36/41] hpsa: when switching out of accel mode await only accel command completions Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 38/41] hpsa: improve error messages for driver initiated commands Stephen M. Cameron
` (3 subsequent siblings)
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Do no rescan on every events -- way too many rescans are
triggered if we don't filter the events. Limit rescans
to be triggered by the following set of events:
* controller state change
* enclosure hot plug
* physical drive state change
* logical drive state change
* redundant controller state change
* accelerated io enabled/disabled
* accelerated io configuration change
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 2 +-
drivers/scsi/hpsa.h | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0082baa..6a50a83 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -6425,7 +6425,7 @@ static void hpsa_ctlr_needs_rescan(struct ctlr_info *h)
return;
h->events = readl(&(h->cfgtable->event_notify));
- if (!h->events && !h->drv_req_rescan)
+ if (!(h->events & RESCAN_REQUIRED_EVENT_BITS) && !h->drv_req_rescan)
return;
/*
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index fe813e9..fe8d281 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -181,6 +181,22 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
u32 events;
+#define CTLR_STATE_CHANGE_EVENT (1 << 0)
+#define CTLR_ENCLOSURE_HOT_PLUG_EVENT (1 << 1)
+#define CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV (1 << 4)
+#define CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV (1 << 5)
+#define CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL (1 << 6)
+#define CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED (1 << 30)
+#define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE (1 << 31)
+
+#define RESCAN_REQUIRED_EVENT_BITS \
+ (CTLR_STATE_CHANGE_EVENT | \
+ CTLR_ENCLOSURE_HOT_PLUG_EVENT | \
+ CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \
+ CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \
+ CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE)
int acciopath_status;
int drv_req_rescan; /* flag for driver to request rescan event */
};
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 38/41] hpsa: improve error messages for driver initiated commands
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (36 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 37/41] hpsa: only do device rescan for certain events Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-16 8:42 ` Hannes Reinecke
2014-01-15 22:39 ` [PATCH 39/41] hpsa add sysfs debug switch for raid map debugging messages Stephen M. Cameron
` (2 subsequent siblings)
40 siblings, 1 reply; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
On encountering unexpected error conditions from driver initiated
commands, print something useful like CDB and sense data rather than
something useless like the kernel virtual address of the command buffer.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 71 ++++++++++++++++++++++++++++++++-------------------
1 files changed, 44 insertions(+), 27 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6a50a83..d469974 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1847,17 +1847,37 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
hpsa_pci_unmap(h->pdev, c, 1, data_direction);
}
-static void hpsa_scsi_interpret_error(struct CommandList *cp)
+static void hpsa_print_cmd(struct ctlr_info *h, char *txt,
+ struct CommandList *c)
{
- struct ErrorInfo *ei;
+ const u8 *cdb = c->Request.CDB;
+ const u8 *lun = c->Header.LUN.LunAddrBytes;
+
+ dev_warn(&h->pdev->dev, "%s: LUN:%02x%02x%02x%02x%02x%02x%02x%02x"
+ " CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ txt, lun[0], lun[1], lun[2], lun[3],
+ lun[4], lun[5], lun[6], lun[7],
+ cdb[0], cdb[1], cdb[2], cdb[3],
+ cdb[4], cdb[5], cdb[6], cdb[7],
+ cdb[8], cdb[9], cdb[10], cdb[11],
+ cdb[12], cdb[13], cdb[14], cdb[15]);
+}
+
+static void hpsa_scsi_interpret_error(struct ctlr_info *h,
+ struct CommandList *cp)
+{
+ const struct ErrorInfo *ei = cp->err_info;
struct device *d = &cp->h->pdev->dev;
+ const u8 *sd = ei->SenseInfo;
- ei = cp->err_info;
switch (ei->CommandStatus) {
case CMD_TARGET_STATUS:
- dev_warn(d, "cmd %p has completed with errors\n", cp);
- dev_warn(d, "cmd %p has SCSI Status = %x\n", cp,
- ei->ScsiStatus);
+ 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]);
+ else
+ dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus);
if (ei->ScsiStatus == 0)
dev_warn(d, "SCSI status is abnormally zero. "
"(probably indicates selection timeout "
@@ -1865,48 +1885,45 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
"firmware bug, circa July, 2001.)\n");
break;
case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
- dev_info(d, "UNDERRUN\n");
break;
case CMD_DATA_OVERRUN:
- dev_warn(d, "cp %p has completed with data overrun\n", cp);
+ hpsa_print_cmd(h, "overrun condition", cp);
break;
case CMD_INVALID: {
/* controller unfortunately reports SCSI passthru's
* to non-existent targets as invalid commands.
*/
- dev_warn(d, "cp %p is reported invalid (probably means "
- "target device no longer present)\n", cp);
- /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
- print_cmd(cp); */
+ hpsa_print_cmd(h, "invalid command", cp);
+ dev_warn(d, "probably means device no longer present\n");
}
break;
case CMD_PROTOCOL_ERR:
- dev_warn(d, "cp %p has protocol error \n", cp);
+ hpsa_print_cmd(h, "protocol error", cp);
break;
case CMD_HARDWARE_ERR:
- /* cmd->result = DID_ERROR << 16; */
- dev_warn(d, "cp %p had hardware error\n", cp);
+ hpsa_print_cmd(h, "hardware error", cp);
break;
case CMD_CONNECTION_LOST:
- dev_warn(d, "cp %p had connection lost\n", cp);
+ hpsa_print_cmd(h, "connection lost", cp);
break;
case CMD_ABORTED:
- dev_warn(d, "cp %p was aborted\n", cp);
+ hpsa_print_cmd(h, "aborted", cp);
break;
case CMD_ABORT_FAILED:
- dev_warn(d, "cp %p reports abort failed\n", cp);
+ hpsa_print_cmd(h, "abort failed", cp);
break;
case CMD_UNSOLICITED_ABORT:
- dev_warn(d, "cp %p aborted due to an unsolicited abort\n", cp);
+ hpsa_print_cmd(h, "unsolicited abort", cp);
break;
case CMD_TIMEOUT:
- dev_warn(d, "cp %p timed out\n", cp);
+ hpsa_print_cmd(h, "timed out", cp);
break;
case CMD_UNABORTABLE:
- dev_warn(d, "Command unabortable\n");
+ hpsa_print_cmd(h, "unabortable", cp);
break;
default:
- dev_warn(d, "cp %p returned unknown status %x\n", cp,
+ hpsa_print_cmd(h, "unknown status", cp);
+ dev_warn(d, "Unknown command status %x\n",
ei->CommandStatus);
}
}
@@ -1934,7 +1951,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
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(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
out:
@@ -1964,7 +1981,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
ei = c->err_info;
if (ei->CommandStatus != 0) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
cmd_special_free(h, c);
@@ -2088,7 +2105,7 @@ static int hpsa_get_raid_map(struct ctlr_info *h,
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(c);
+ hpsa_scsi_interpret_error(h, c);
cmd_special_free(h, c);
return -1;
}
@@ -2230,7 +2247,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
ei = c->err_info;
if (ei->CommandStatus != 0 &&
ei->CommandStatus != CMD_DATA_UNDERRUN) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
} else {
if (buf->extended_response_flag != extended_response) {
@@ -3981,7 +3998,7 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
default:
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
__func__, tagupper, taglower);
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
break;
}
^ permalink raw reply related [flat|nested] 46+ messages in thread* Re: [PATCH 38/41] hpsa: improve error messages for driver initiated commands
2014-01-15 22:39 ` [PATCH 38/41] hpsa: improve error messages for driver initiated commands Stephen M. Cameron
@ 2014-01-16 8:42 ` Hannes Reinecke
2014-01-16 16:14 ` scameron
0 siblings, 1 reply; 46+ messages in thread
From: Hannes Reinecke @ 2014-01-16 8:42 UTC (permalink / raw)
To: Stephen M. Cameron, jbottomley
Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
On 01/15/2014 11:39 PM, Stephen M. Cameron wrote:
> From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
>
> On encountering unexpected error conditions from driver initiated
> commands, print something useful like CDB and sense data rather than
> something useless like the kernel virtual address of the command buffer.
>
> Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
> ---
> drivers/scsi/hpsa.c | 71 ++++++++++++++++++++++++++++++++-------------------
> 1 files changed, 44 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> index 6a50a83..d469974 100644
> --- a/drivers/scsi/hpsa.c
> +++ b/drivers/scsi/hpsa.c
> @@ -1847,17 +1847,37 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
> hpsa_pci_unmap(h->pdev, c, 1, data_direction);
> }
>
> -static void hpsa_scsi_interpret_error(struct CommandList *cp)
> +static void hpsa_print_cmd(struct ctlr_info *h, char *txt,
> + struct CommandList *c)
> {
> - struct ErrorInfo *ei;
> + const u8 *cdb = c->Request.CDB;
> + const u8 *lun = c->Header.LUN.LunAddrBytes;
> +
> + dev_warn(&h->pdev->dev, "%s: LUN:%02x%02x%02x%02x%02x%02x%02x%02x"
> + " CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> + txt, lun[0], lun[1], lun[2], lun[3],
> + lun[4], lun[5], lun[6], lun[7],
> + cdb[0], cdb[1], cdb[2], cdb[3],
> + cdb[4], cdb[5], cdb[6], cdb[7],
> + cdb[8], cdb[9], cdb[10], cdb[11],
> + cdb[12], cdb[13], cdb[14], cdb[15]);
> +}
Do you _really_ have to do this?
We do have scsi_logging_level, which would provide exactly this
information.
Can't you rely on the SCSI stack for logging here and drop all
the redundancy in the driver?
Thing is, the hpsa driver is already quite chatty:
hpsa 0000:4f:00.0: Direct-Access device c0b0t0l0 added.
hpsa 0000:4f:00.0: RAID device c0b3t0l0 added.
scsi 0:0:0:0: Direct-Access HP LOGICAL VOLUME 7.24 PQ
: 0 ANSI: 5
sd 0:0:0:0: [sda] 286677120 512-byte logical blocks: (146 GB/136
GiB)
scsi 0:3:0:0: RAID HP P400 7.24 PQ: 0
ANSI: 0
So where is the point of the first two messages?
The enumeration is internal anyway, so it has a very quesionable
value to the user. And the devices are listed afterwards anyway.
Hence it _might_ be an idea to remove some of those messages ...
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread* Re: [PATCH 38/41] hpsa: improve error messages for driver initiated commands
2014-01-16 8:42 ` Hannes Reinecke
@ 2014-01-16 16:14 ` scameron
0 siblings, 0 replies; 46+ messages in thread
From: scameron @ 2014-01-16 16:14 UTC (permalink / raw)
To: Hannes Reinecke
Cc: jbottomley, stephenmcameron, mikem, matthew.gates, linux-scsi,
scott.teel, scameron
On Thu, Jan 16, 2014 at 09:42:52AM +0100, Hannes Reinecke wrote:
> On 01/15/2014 11:39 PM, Stephen M. Cameron wrote:
> > From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
> >
> > On encountering unexpected error conditions from driver initiated
> > commands, print something useful like CDB and sense data rather than
> > something useless like the kernel virtual address of the command buffer.
> >
> > Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
> > ---
> > drivers/scsi/hpsa.c | 71 ++++++++++++++++++++++++++++++++-------------------
> > 1 files changed, 44 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> > index 6a50a83..d469974 100644
> > --- a/drivers/scsi/hpsa.c
> > +++ b/drivers/scsi/hpsa.c
> > @@ -1847,17 +1847,37 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
> > hpsa_pci_unmap(h->pdev, c, 1, data_direction);
> > }
> >
> > -static void hpsa_scsi_interpret_error(struct CommandList *cp)
> > +static void hpsa_print_cmd(struct ctlr_info *h, char *txt,
> > + struct CommandList *c)
> > {
> > - struct ErrorInfo *ei;
> > + const u8 *cdb = c->Request.CDB;
> > + const u8 *lun = c->Header.LUN.LunAddrBytes;
> > +
> > + dev_warn(&h->pdev->dev, "%s: LUN:%02x%02x%02x%02x%02x%02x%02x%02x"
> > + " CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> > + txt, lun[0], lun[1], lun[2], lun[3],
> > + lun[4], lun[5], lun[6], lun[7],
> > + cdb[0], cdb[1], cdb[2], cdb[3],
> > + cdb[4], cdb[5], cdb[6], cdb[7],
> > + cdb[8], cdb[9], cdb[10], cdb[11],
> > + cdb[12], cdb[13], cdb[14], cdb[15]);
> > +}
> Do you _really_ have to do this?
> We do have scsi_logging_level, which would provide exactly
> this information.
Not exactly, the mid layer could not print the 8-byte LUNID because
it does not and cannot know it ...
> Can't you rely on the SCSI stack for logging here and drop all
> the redundancy in the driver?
and furthermore, hpsa_print_cmd() is only called by
hpsa_scsi_interpret_error(), which is only called from:
hpsa_scsi_do_inquiry
hpsa_send_reset
hpsa_get_raid_map
hpsa_scsi_do_report_luns
hpsa_send_abort
none of which are called from a place where this information
could be passed back to the scsi mid layer because the scsi mid
layer did not build the commands for these cases, they are commands
initiated by the driver (as noted in the changelog entry).
>
> Thing is, the hpsa driver is already quite chatty:
>
> hpsa 0000:4f:00.0: Direct-Access device c0b0t0l0 added.
> hpsa 0000:4f:00.0: RAID device c0b3t0l0 added.
> scsi 0:0:0:0: Direct-Access HP LOGICAL VOLUME 7.24 PQ
> : 0 ANSI: 5
> sd 0:0:0:0: [sda] 286677120 512-byte logical blocks: (146 GB/136
> GiB)
> scsi 0:3:0:0: RAID HP P400 7.24 PQ: 0
> ANSI: 0
>
> So where is the point of the first two messages?
> The enumeration is internal anyway, so it has a very quesionable
> value to the user. And the devices are listed afterwards anyway.
>
> Hence it _might_ be an idea to remove some of those messages ...
FWIW, I'm usually the one in my group arguing for less messages rather
than more. I don't always win.
-- steve
^ permalink raw reply [flat|nested] 46+ messages in thread
* [PATCH 39/41] hpsa add sysfs debug switch for raid map debugging messages
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (37 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 38/41] hpsa: improve error messages for driver initiated commands Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 40/41] pci: add HP/3PAR vendor id to pci_ids.h Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 41/41] hpsa: Add support for a few HP Storage controllers Stephen M. Cameron
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/hpsa.h | 1 +
2 files changed, 66 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index d469974..eab21bb 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -312,6 +312,31 @@ static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
return count;
}
+static ssize_t host_store_raid_offload_debug(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int debug_level, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ 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", &debug_level) != 1)
+ return -EINVAL;
+ if (debug_level < 0)
+ debug_level = 0;
+ h = shost_to_hba(shost);
+ h->raid_offload_debug = debug_level;
+ dev_warn(&h->pdev->dev, "hpsa: Set raid_offload_debug level = %d\n",
+ h->raid_offload_debug);
+ return count;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -585,6 +610,8 @@ static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO,
static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH,
host_show_hp_ssd_smart_path_status,
host_store_hp_ssd_smart_path_status);
+static DEVICE_ATTR(raid_offload_debug, S_IWUSR, NULL,
+ host_store_raid_offload_debug);
static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
@@ -609,6 +636,7 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_transport_mode,
&dev_attr_resettable,
&dev_attr_hp_ssd_smart_path_status,
+ &dev_attr_raid_offload_debug,
NULL,
};
@@ -2019,6 +2047,10 @@ static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
if (rc != 0)
return;
+ /* Show details only if debugging has been activated. */
+ if (h->raid_offload_debug < 2)
+ return;
+
dev_info(&h->pdev->dev, "structure_size = %u\n",
le32_to_cpu(map_buff->structure_size));
dev_info(&h->pdev->dev, "volume_blk_size = %u\n",
@@ -2504,6 +2536,17 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
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 (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
@@ -2528,6 +2571,15 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
found = 1;
memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
physicals)->LUN[i][0], 8);
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __func__, find,
+ ((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20],
+ scsi3addr[0], scsi3addr[1], scsi3addr[2],
+ scsi3addr[3], scsi3addr[4], scsi3addr[5],
+ scsi3addr[6], scsi3addr[7]);
break; /* found it */
}
@@ -4083,6 +4135,13 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
return -1; /* not abortable */
}
+ 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",
+ 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]);
+
if (!dev->offload_enabled) {
dev_warn(&h->pdev->dev,
"Can't abort: device is not operating in HP SSD Smart Path mode.\n");
@@ -4096,6 +4155,12 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
}
/* send the reset */
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "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);
if (rc != 0) {
dev_warn(&h->pdev->dev,
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index fe8d281..c4a81f0 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -199,6 +199,7 @@ struct ctlr_info {
CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE)
int acciopath_status;
int drv_req_rescan; /* flag for driver to request rescan event */
+ int raid_offload_debug;
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 40/41] pci: add HP/3PAR vendor id to pci_ids.h
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (38 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 39/41] hpsa add sysfs debug switch for raid map debugging messages Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 41/41] hpsa: Add support for a few HP Storage controllers Stephen M. Cameron
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
include/linux/pci_ids.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 97fbecd..0154d9b 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -726,6 +726,7 @@
#define PCI_DEVICE_ID_SI_7018 0x7018
#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_VENDOR_ID_HP_3PAR 0x1590
#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005
#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006
#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 41/41] hpsa: Add support for a few HP Storage controllers
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
` (39 preceding siblings ...)
2014-01-15 22:39 ` [PATCH 40/41] pci: add HP/3PAR vendor id to pci_ids.h Stephen M. Cameron
@ 2014-01-15 22:39 ` Stephen M. Cameron
40 siblings, 0 replies; 46+ messages in thread
From: Stephen M. Cameron @ 2014-01-15 22:39 UTC (permalink / raw)
To: jbottomley; +Cc: stephenmcameron, mikem, matthew.gates, linux-scsi, scott.teel
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
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 eab21bb..fb0950c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -119,6 +119,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C7},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C8},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C9},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0088},
+ {PCI_VENDOR_ID_HP, 0x333f, 0x103c, 0x333f},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -164,6 +169,11 @@ static struct board_type products[] = {
{0x21C7103C, "Smart Array", &SA5_access},
{0x21C8103C, "Smart Array", &SA5_access},
{0x21C9103C, "Smart Array", &SA5_access},
+ {0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
+ {0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
+ {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
+ {0x00881590, "HP Storage P1228e Array Controller", &SA5_access},
+ {0x333f103c, "HP StorageWorks 1210m Array Controller", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
^ permalink raw reply related [flat|nested] 46+ messages in thread