Commit 34592254 authored by Scott Teel's avatar Scott Teel Committed by Martin K. Petersen

hpsa: add discovery polling for PT RAID devices.

There are problems with getting configuration change notification
in pass-through RAID environments.  So, activate flag
h->discovery_polling when one of these devices is detected in
update_scsi_devices.

After discovery_polling is set, execute a report luns from
rescan_controller_worker (every 30 seconds).

If the data from report_luns is different than last
time (binary compare), execute a full rescan via update_scsi_devices.
Reviewed-by: default avatarScott Teel <scott.teel@pmcs.com>
Reviewed-by: default avatarJustin Lindley <justin.lindley@pmcs.com>
Reviewed-by: default avatarKevin Barnett <kevin.barnett@pmcs.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarMatthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: default avatarDon Brace <don.brace@pmcs.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2d62a33e
......@@ -275,6 +275,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
static void hpsa_command_resubmit_worker(struct work_struct *work);
static u32 lockup_detected(struct ctlr_info *h);
static int detect_controller_lockup(struct ctlr_info *h);
static int hpsa_luns_changed(struct ctlr_info *h);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
......@@ -3898,6 +3899,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
/* Turn on discovery_polling if there are ext target devices.
* Event-based change notification is unreliable for those.
*/
if (!h->discovery_polling) {
if (tmpdevice->external) {
h->discovery_polling = 1;
dev_info(&h->pdev->dev,
"External target, activate discovery polling.\n");
}
}
*this_device = *tmpdevice;
this_device->physical_device = physical_device;
......@@ -8016,6 +8029,41 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h)
return 0;
}
static int hpsa_luns_changed(struct ctlr_info *h)
{
int rc = 1; /* assume there are changes */
struct ReportLUNdata *logdev = NULL;
/* if we can't find out if lun data has changed,
* assume that it has.
*/
if (!h->lastlogicals)
goto out;
logdev = kzalloc(sizeof(*logdev), GFP_KERNEL);
if (!logdev) {
dev_warn(&h->pdev->dev,
"Out of memory, can't track lun changes.\n");
goto out;
}
if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) {
dev_warn(&h->pdev->dev,
"report luns failed, can't track lun changes.\n");
goto out;
}
if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) {
dev_info(&h->pdev->dev,
"Lun changes detected.\n");
memcpy(h->lastlogicals, logdev, sizeof(*logdev));
goto out;
} else
rc = 0; /* no changes detected. */
out:
kfree(logdev);
return rc;
}
static void hpsa_rescan_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
......@@ -8031,6 +8079,18 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work)
hpsa_ack_ctlr_events(h);
hpsa_scan_start(h->scsi_host);
scsi_host_put(h->scsi_host);
} else if (h->discovery_polling) {
if (hpsa_luns_changed(h)) {
struct Scsi_Host *sh = NULL;
dev_info(&h->pdev->dev,
"driver discovery polling rescan.\n");
sh = scsi_host_get(h->scsi_host);
if (sh != NULL) {
hpsa_scan_start(sh);
scsi_host_put(sh);
}
}
}
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
......@@ -8271,6 +8331,8 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
/* Disable discovery polling.*/
h->discovery_polling = 0;
/* Turn the interrupts on so we can service requests */
......@@ -8278,6 +8340,11 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
hpsa_hba_inquiry(h);
h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL);
if (!h->lastlogicals)
dev_info(&h->pdev->dev,
"Can't track change to report lun data\n");
/* Monitor the controller for firmware lockups */
h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
......@@ -8415,6 +8482,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
hpsa_free_performant_mode(h); /* init_one 7 */
hpsa_free_sg_chain_blocks(h); /* init_one 6 */
hpsa_free_cmd_pool(h); /* init_one 5 */
kfree(h->lastlogicals);
/* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */
......
......@@ -262,6 +262,8 @@ struct ctlr_info {
int acciopath_status;
int drv_req_rescan;
int raid_offload_debug;
int discovery_polling;
struct ReportLUNdata *lastlogicals;
int needs_abort_tags_swizzled;
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment