Skip to contentSkip to conversation

hpsa: resend of November 2013 patches

PATCH New Stephen M. Cameron 1 participant 10 messages Dec 4, 2013

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover hpsa: resend of November 2013 patches

This updated series applies on top of the "misc" branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git

Note: the first two patches in this series revert previously applied patches which I had not previously realized were present in James's tree.

There's one extra patch in this set that wasn't present in the series I sent in November to allow the SCSI mid layer to handle unit attn's.

Patches from the November series that are already present in James's tree are not in this patch series.

And, finally if this is all too confusing and you want me to send something else, let me know.

---

Matt Gates (1):
hpsa: allow SCSI mid layer to handle unit attention

Stephen M. Cameron (8):
hpsa: revert bring logical drives online when format completes
hpsa: revert hide logical drives with format in progress from linux
hpsa: return 0 from driver probe function on success, not 1
hpsa: use workqueue instead of kernel thread for lockup detection
hpsa: rename scsi prefetch field
hpsa: enable unit attention reporting
hpsa: do not discard scsi status on aborted commands
hpsa: do not require board "not ready" status after hard reset

 drivers/scsi/hpsa.c     |  321 ++++++-----------------------------------------
 drivers/scsi/hpsa.h     |   17 --
 drivers/scsi/hpsa_cmd.h |    4 -
 3 files changed, 45 insertions(+), 297 deletions(-)
Signature · 1 line
-- steve
#1 lore raw

PATCH 1/9 hpsa: revert bring logical drives online when format completes

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

This relies on a kernel thread which I wish to remove and replace with a work queue based solution.

---
 drivers/scsi/hpsa.c |  128 ---------------------------------------------------
 drivers/scsi/hpsa.h |   13 -----
 2 files changed, 1 insertions(+), 140 deletions(-)
drivers/scsi/hpsa.c +1 -127
index 89f50c3..961332b 100644
@@ -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
 
@@ -945,112 +943,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)
 {
@@ -1123,10 +1015,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;
@@ -1150,17 +1039,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.
@@ -5065,10 +4943,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)
@@ -5077,7 +4953,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));
@@ -5256,7 +5131,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);
drivers/scsi/hpsa.h +0 -13
index bea2365..04074f5 100644
@@ -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
#2 lore raw

PATCH 2/9 hpsa: revert hide logical drives with format in progress from linux

In reply to Stephen M. Cameron

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

This relies on a kernel thread which I wish to replace with a work queue based solution.

---
 drivers/scsi/hpsa.c |   50 ++------------------------------------------------
 drivers/scsi/hpsa.h |    1 -
 2 files changed, 2 insertions(+), 49 deletions(-)
drivers/scsi/hpsa.c +2 -48
index 961332b..75800f7 100644
@@ -1007,20 +1007,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) {
@@ -1726,34 +1712,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)
@@ -1792,14 +1750,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
drivers/scsi/hpsa.h +0 -1
index 04074f5..5f3f72f 100644
@@ -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 {
#3 lore raw

PATCH 3/9 hpsa: return 0 from driver probe function on success, not 1

In reply to Stephen M. Cameron

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

A return value of 1 is interpreted as an error. See pci-driver.c in local_pci_probe(). If you're wondering how this ever could have worked, it's because it used to be the case that only return values less than zero were interpreted as failure. But even in the current kernel if the driver registers its various entry points with the kernel, and then returns a value which is interpreted as failure, those registrations aren't undone, so the driver still mostly works. However, the driver's remove function wouldn't be called on rmmod, and pci power management functions wouldn't work. In the case of Smart Array, since it has a battery backed cache (or else no cache) even if the driver is not shut down properly as long as there is no outstanding i/o, nothing too bad happens, which is why it took so long to
notice.

Requesting backport to stable because the change to pci-driver.c which requires driver probe functions to return 0 occurred between 2.6.35 and 2.6.36 (the pci power management breakage) and again between 3.7 and 3.8 (pci_dev->driver getting set to NULL in local_pci_probe() preventing driver remove function from being called on rmmod.)

---
 drivers/scsi/hpsa.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/hpsa.c +1 -1
index 75800f7..14f662d 100644
@@ -5004,7 +5004,7 @@ reinit_after_soft_reset:
 	hpsa_hba_inquiry(h);
 	hpsa_register_scsi(h);	/* hook ourselves into SCSI subsystem */
 	start_controller_lockup_detector(h);
-	return 1;
+	return 0;
 
 clean4:
 	hpsa_free_sg_chain_blocks(h);
#4 lore raw

PATCH 4/9 hpsa: use workqueue instead of kernel thread for lockup detection

In reply to Stephen M. Cameron

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

Much simpler and avoids races starting/stopping the thread.

---
 drivers/scsi/hpsa.c |  103 +++++++++++++--------------------------------------
 drivers/scsi/hpsa.h |    3 +
 2 files changed, 28 insertions(+), 78 deletions(-)
drivers/scsi/hpsa.c +26 -77
index 14f662d..a502718 100644
@@ -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);
@@ -4715,16 +4711,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)
 {
@@ -4743,8 +4729,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);
@@ -4764,7 +4748,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 +
@@ -4794,68 +4777,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)
@@ -5003,7 +4940,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:
@@ -5078,13 +5020,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);
drivers/scsi/hpsa.h +2 -1
index 5f3f72f..01c3283 100644
@@ -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];
#5 lore raw

PATCH 5/9 hpsa: rename scsi prefetch field

In reply to Stephen M. Cameron

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

The field contains more bits than just the one to indicate whether scsi prefetch should be turned on.

---
 drivers/scsi/hpsa.c     |   14 +++++++-------
 drivers/scsi/hpsa_cmd.h |    3 ++-
 2 files changed, 9 insertions(+), 8 deletions(-)
drivers/scsi/hpsa.c +7 -7
index a502718..2b0f578 100644
@@ -4381,15 +4381,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
 }
 
@@ -4500,7 +4500,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)
drivers/scsi/hpsa_cmd.h +2 -1
index a894f2e..5158709 100644
@@ -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;
#6 lore raw

PATCH 6/9 hpsa: enable unit attention reporting

In reply to Stephen M. Cameron

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

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.

---
 drivers/scsi/hpsa.c     |    7 ++++---
 drivers/scsi/hpsa_cmd.h |    1 +
 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/scsi/hpsa.c +4 -3
index 2b0f578..069640f 100644
@@ -4383,14 +4383,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;
 
+#ifdef CONFIG_X86
+	/* Need to enable prefetch in the SCSI core for 6400 in x86 */
 	driver_support = readl(&(h->cfgtable->driver_support));
 	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
drivers/scsi/hpsa_cmd.h +1 -0
index 5158709..bfc8c4e 100644
@@ -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;
#7 lore raw

PATCH 7/9 hpsa: do not discard scsi status on aborted commands

In reply to Stephen M. Cameron

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

We inadvertantly discarded the scsi status for aborted commands. For some commands (e.g. reads from tape drives) these can't be retried, and if we discarded the scsi status, the scsi mid layer couldn't notice anything was wrong and the error was not reported.

---
 drivers/scsi/hpsa.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/hpsa.c +1 -1
index 069640f..162405e 100644
@@ -1281,7 +1281,7 @@ static void complete_scsi_command(struct CommandList *cp)
 					"has check condition: aborted command: "
 					"ASC: 0x%x, ASCQ: 0x%x\n",
 					cp, asc, ascq);
-				cmd->result = DID_SOFT_ERROR << 16;
+				cmd->result |= DID_SOFT_ERROR << 16;
 				break;
 			}
 			/* Must be some other type of check condition */
#8 lore raw

PATCH 8/9 hpsa: do not require board "not ready" status after hard reset

In reply to Stephen M. Cameron

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

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.

---
 drivers/scsi/hpsa.c |   17 -----------------
 1 files changed, 0 insertions(+), 17 deletions(-)
drivers/scsi/hpsa.c +0 -17
index 162405e..693c801 100644
@@ -4047,23 +4047,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,
#9 lore raw

PATCH 9/9 hpsa: allow SCSI mid layer to handle unit attention

In reply to Stephen M. Cameron

From: Matt Gates <[email protected]>

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.

---
 drivers/scsi/hpsa.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)
drivers/scsi/hpsa.c +1 -3
index 693c801..107f3c4 100644
@@ -1240,10 +1240,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