RE: [PATCH 08/37] smartpqi: add suspend and resume support

2017-05-03 Thread Don Brace
> -Original Message-
> On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
> > +static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
> > +   struct pqi_scsi_dev *device)
> > +{
> > +   while (atomic_read(>scsi_cmds_outstanding)) {
> > +   pqi_check_ctrl_health(ctrl_info);
> > +   if (pqi_ctrl_offline(ctrl_info))
> > +   return -ENXIO;
> > +   usleep_range(1000, 2000);
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info)
> > +{
> > +   bool io_pending;
> > +   unsigned long flags;
> > +   struct pqi_scsi_dev *device;
> > +
> > +   while (1) {
> > +   io_pending = false;
> > +
> > +   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
> > +   list_for_each_entry(device, _info->scsi_device_list,
> > +   scsi_device_list_entry) {
> > +   if (atomic_read(>scsi_cmds_outstanding)) {
> > +   io_pending = true;
> > +   break;
> > +   }
> > +   }
> > +   spin_unlock_irqrestore(_info->scsi_device_list_lock,
> > +   flags);
> > +
> > +   if (!io_pending)
> > +   break;
> > +
> > +   pqi_check_ctrl_health(ctrl_info);
> > +   if (pqi_ctrl_offline(ctrl_info))
> > +   return -ENXIO;
> > +
> > +   usleep_range(1000, 2000);
> > +   }
> > +
> > +   return 0;
> > +}
> 
> The same comment applies here that applies to the previous patch: please
> use
> scsi_target_block() / scsi_target_unblock() instead of reimplementing these
> functions.
> 
> Thanks,
> 
> Bart.

Our LUN reset functions have to do several PQI-specific things in order to work 
correctly,
which is why we did not use scsi_target_block()/scsi_target_unblock()

Hope this is acceptable

Thanks for your review
Don Brace
ESC - Smart Storage
Microsemi Corporation



Re: [PATCH 08/37] smartpqi: add suspend and resume support

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
> +static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
> +   struct pqi_scsi_dev *device)
> +{
> +   while (atomic_read(>scsi_cmds_outstanding)) {
> +   pqi_check_ctrl_health(ctrl_info);
> +   if (pqi_ctrl_offline(ctrl_info))
> +   return -ENXIO;
> +   usleep_range(1000, 2000);
> +   }
> +
> +   return 0;
> +}
> +
> +static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info)
> +{
> +   bool io_pending;
> +   unsigned long flags;
> +   struct pqi_scsi_dev *device;
> +
> +   while (1) {
> +   io_pending = false;
> +
> +   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
> +   list_for_each_entry(device, _info->scsi_device_list,
> +   scsi_device_list_entry) {
> +   if (atomic_read(>scsi_cmds_outstanding)) {
> +   io_pending = true;
> +   break;
> +   }
> +   }
> +   spin_unlock_irqrestore(_info->scsi_device_list_lock,
> +   flags);
> +
> +   if (!io_pending)
> +   break;
> +
> +   pqi_check_ctrl_health(ctrl_info);
> +   if (pqi_ctrl_offline(ctrl_info))
> +   return -ENXIO;
> +
> +   usleep_range(1000, 2000);
> +   }
> +
> +   return 0;
> +}

The same comment applies here that applies to the previous patch: please use
scsi_target_block() / scsi_target_unblock() instead of reimplementing these
functions.

Thanks,

Bart.

[PATCH 08/37] smartpqi: add suspend and resume support

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add support for ACPI S3 (suspend) and S4 (hibernate) system power states.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   12 +
 drivers/scsi/smartpqi/smartpqi_init.c |  424 +++--
 drivers/scsi/smartpqi/smartpqi_sis.c  |   75 ++
 drivers/scsi/smartpqi/smartpqi_sis.h  |3 
 4 files changed, 485 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 5b0c6fb..06e2b71 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -61,7 +61,7 @@ struct pqi_device_registers {
 /*
  * controller registers
  *
- * These are defined by the PMC implementation.
+ * These are defined by the Microsemi implementation.
  *
  * Some registers (those named sis_*) are only used when in
  * legacy SIS mode before we transition the controller into
@@ -102,6 +102,12 @@ enum pqi_io_path {
AIO_PATH = 1
 };
 
+enum pqi_irq_mode {
+   IRQ_MODE_NONE,
+   IRQ_MODE_INTX,
+   IRQ_MODE_MSIX
+};
+
 struct pqi_sg_descriptor {
__le64  address;
__le32  length;
@@ -908,7 +914,7 @@ struct pqi_ctrl_info {
dma_addr_t  error_buffer_dma_handle;
size_t  sg_chain_buffer_length;
unsigned intnum_queue_groups;
-   unsigned intnum_active_queue_groups;
+   u16 max_hw_queue_index;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
u16 max_inbound_iu_length_per_firmware;
@@ -923,6 +929,7 @@ struct pqi_ctrl_info {
struct pqi_admin_queues admin_queues;
struct pqi_queue_group queue_groups[PQI_MAX_QUEUE_GROUPS];
struct pqi_event_queue event_queue;
+   enum pqi_irq_mode irq_mode;
int max_msix_vectors;
int num_msix_vectors_enabled;
int num_msix_vectors_initialized;
@@ -937,6 +944,7 @@ struct pqi_ctrl_info {
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
u8  heartbeat_timer_started : 1;
+   u8  update_time_worker_scheduled : 1;
 
struct list_head scsi_device_list;
spinlock_t  scsi_device_list_lock;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 96bf318..ca9d010 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -262,6 +262,11 @@ static inline void pqi_schedule_rescan_worker(struct 
pqi_ctrl_info *ctrl_info)
PQI_RESCAN_WORK_INTERVAL);
 }
 
+static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info)
+{
+   cancel_delayed_work_sync(_info->rescan_work);
+}
+
 static int pqi_map_single(struct pci_dev *pci_dev,
struct pqi_sg_descriptor *sg_descriptor, void *buffer,
size_t buffer_length, int data_direction)
@@ -588,7 +593,7 @@ static int pqi_write_driver_version_to_host_wellness(
buffer->driver_version_tag[1] = 'V';
put_unaligned_le16(sizeof(buffer->driver_version),
>driver_version_length);
-   strncpy(buffer->driver_version, DRIVER_VERSION,
+   strncpy(buffer->driver_version, "Linux " DRIVER_VERSION,
sizeof(buffer->driver_version) - 1);
buffer->driver_version[sizeof(buffer->driver_version) - 1] = '\0';
buffer->end_tag[0] = 'Z';
@@ -686,7 +691,21 @@ static void pqi_update_time_worker(struct work_struct 
*work)
 static inline void pqi_schedule_update_time_worker(
struct pqi_ctrl_info *ctrl_info)
 {
+   if (ctrl_info->update_time_worker_scheduled)
+   return;
+
schedule_delayed_work(_info->update_time_work, 0);
+   ctrl_info->update_time_worker_scheduled = true;
+}
+
+static inline void pqi_cancel_update_time_worker(
+   struct pqi_ctrl_info *ctrl_info)
+{
+   if (!ctrl_info->update_time_worker_scheduled)
+   return;
+
+   cancel_delayed_work_sync(_info->update_time_work);
+   ctrl_info->update_time_worker_scheduled = false;
 }
 
 static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
@@ -1967,6 +1986,18 @@ static int pqi_scan_finished(struct Scsi_Host *shost,
return !mutex_is_locked(_info->scan_mutex);
 }
 
+static void pqi_wait_until_scan_finished(struct pqi_ctrl_info *ctrl_info)
+{
+   mutex_lock(_info->scan_mutex);
+   mutex_unlock(_info->scan_mutex);
+}
+
+static void pqi_wait_until_lun_reset_finished(struct pqi_ctrl_info *ctrl_info)
+{
+   mutex_lock(_info->lun_reset_mutex);
+   mutex_unlock(_info->lun_reset_mutex);
+}
+
 static inline void pqi_set_encryption_info(
struct pqi_encryption_info *encryption_info, struct raid_map *raid_map,
u64