[SCSI] mpt fusion: Queue full event handling
Kashyap, Desai [Fri, 29 May 2009 11:25:09 +0000 (16:25 +0530)]
FW will report Queue full event to Driver and driver will handle this queue
full event to SCSI Mid layer.

Signed-off-by: Kashyap Desai <kadesai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h

index 7215823..10a12d8 100644 (file)
@@ -121,6 +121,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc,
 static void mptsas_send_expander_event(struct fw_event_work *fw_event);
 static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
 static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
+static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
 static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
@@ -680,6 +681,18 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
                mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
                    phys_disk.PhysDiskID);
 
+               mutex_lock(&ioc->sas_device_info_mutex);
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (!sas_info->is_logical_volume &&
+                           (sas_info->fw.channel == phys_disk.PhysDiskBus &&
+                           sas_info->fw.id == phys_disk.PhysDiskID)) {
+                               sas_info->is_hidden_raid_component = 1;
+                               sas_info->volume_id = starget->id;
+                       }
+               }
+               mutex_unlock(&ioc->sas_device_info_mutex);
+
        }
 
        /*
@@ -747,6 +760,29 @@ mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
 }
 
 /**
+ *     mptsas_del_device_component_by_os - Once a device has been removed, we
+ *     mark the entry in the list as being cached
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: os mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct mptsas_device_info       *sas_info, *next;
+
+       /*
+        * Set is_cached flag
+        */
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+               list) {
+               if (sas_info->os.channel == channel && sas_info->os.id == id)
+                       sas_info->is_cached = 1;
+       }
+}
+
+/**
  *     mptsas_del_device_components - Cleaning the list
  *     @ioc: Pointer to MPT_ADAPTER structure
  *
@@ -1576,6 +1612,9 @@ mptsas_firmware_event_work(struct work_struct *work)
        case MPI_EVENT_SAS_PHY_LINK_STATUS:
                mptsas_send_link_status_event(fw_event);
                break;
+       case MPI_EVENT_QUEUE_FULL:
+               mptsas_handle_queue_full_event(fw_event);
+               break;
        }
 }
 
@@ -1705,6 +1744,9 @@ mptsas_target_destroy(struct scsi_target *starget)
 
        vtarget = starget->hostdata;
 
+       mptsas_del_device_component_by_os(ioc, starget->channel,
+           starget->id);
+
 
        if (starget->channel == MPTSAS_RAID_CHANNEL)
                goto out;
@@ -3398,6 +3440,8 @@ mptsas_not_responding_devices(MPT_ADAPTER *ioc)
        mutex_lock(&ioc->sas_device_info_mutex);
  redo_device_scan:
        list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+               if (sas_info->is_cached)
+                       continue;
                if (!sas_info->is_logical_volume) {
                        sas_device.handle = 0;
                        retry_count = 0;
@@ -3612,6 +3656,95 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
        }
 }
 
+
+static void
+mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
+{
+       MPT_ADAPTER *ioc;
+       EventDataQueueFull_t *qfull_data;
+       struct mptsas_device_info *sas_info;
+       struct scsi_device      *sdev;
+       int depth;
+       int id = -1;
+       int channel = -1;
+       int fw_id, fw_channel;
+       u16 current_depth;
+
+
+       ioc = fw_event->ioc;
+       qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
+       fw_id = qfull_data->TargetID;
+       fw_channel = qfull_data->Bus;
+       current_depth = le16_to_cpu(qfull_data->CurrentDepth);
+
+       /* if hidden raid component, look for the volume id */
+       mutex_lock(&ioc->sas_device_info_mutex);
+       if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (sas_info->is_cached ||
+                           sas_info->is_logical_volume)
+                               continue;
+                       if (sas_info->is_hidden_raid_component &&
+                           (sas_info->fw.channel == fw_channel &&
+                           sas_info->fw.id == fw_id)) {
+                               id = sas_info->volume_id;
+                               channel = MPTSAS_RAID_CHANNEL;
+                               goto out;
+                       }
+               }
+       } else {
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (sas_info->is_cached ||
+                           sas_info->is_hidden_raid_component ||
+                           sas_info->is_logical_volume)
+                               continue;
+                       if (sas_info->fw.channel == fw_channel &&
+                           sas_info->fw.id == fw_id) {
+                               id = sas_info->os.id;
+                               channel = sas_info->os.channel;
+                               goto out;
+                       }
+               }
+
+       }
+
+ out:
+       mutex_unlock(&ioc->sas_device_info_mutex);
+
+       if (id != -1) {
+               shost_for_each_device(sdev, ioc->sh) {
+                       if (sdev->id == id && sdev->channel == channel) {
+                               if (current_depth > sdev->queue_depth) {
+                                       sdev_printk(KERN_INFO, sdev,
+                                           "strange observation, the queue "
+                                           "depth is (%d) meanwhile fw queue "
+                                           "depth (%d)\n", sdev->queue_depth,
+                                           current_depth);
+                                       continue;
+                               }
+                               depth = scsi_track_queue_full(sdev,
+                                   current_depth - 1);
+                               if (depth > 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Queue depth reduced to (%d)\n",
+                                          depth);
+                               else if (depth < 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Tagged Command Queueing is being "
+                                       "disabled\n");
+                               else if (depth == 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Queue depth not changed yet\n");
+                       }
+               }
+       }
+
+       mptsas_free_fw_event(ioc, fw_event);
+}
+
+
 static struct mptsas_phyinfo *
 mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
 {
index 57258b6..953c2bf 100644 (file)
@@ -83,6 +83,12 @@ struct mptsas_device_info {
        u16                     slot;           /* enclosure slot id */
        u64                     enclosure_logical_id; /*enclosure address */
        u8                      is_logical_volume; /* is this logical volume */
+       /* this belongs to volume */
+       u8                      is_hidden_raid_component;
+       /* this valid when is_hidden_raid_component set */
+       u8                      volume_id;
+       /* cached data for a removed device */
+       u8                      is_cached;
 };
 
 struct mptsas_hotplug_event {