[SCSI] hpsa: Add hba mode to the hpsa driver
authorStephen M. Cameron <scameron@beardog.cce.hp.com>
Fri, 21 Feb 2014 22:25:15 +0000 (16:25 -0600)
committerJames Bottomley <JBottomley@Parallels.com>
Sat, 15 Mar 2014 17:19:23 +0000 (10:19 -0700)
This allows exposing physical disks behind Smart
Array controllers to the OS (if the controller
has the right firmware and is in "hba" mode)

Signed-off-by: Joe Handzik <joseph.t.handzik@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/hpsa_cmd.h

index 388e229..eb23eea 100644 (file)
@@ -2128,6 +2128,37 @@ out:
        return rc;
 }
 
+static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
+               unsigned char *scsi3addr, unsigned char page,
+               struct bmic_controller_parameters *buf, size_t bufsize)
+{
+       int rc = IO_OK;
+       struct CommandList *c;
+       struct ErrorInfo *ei;
+
+       c = cmd_special_alloc(h);
+
+       if (c == NULL) {                        /* trouble... */
+               dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+               return -ENOMEM;
+       }
+
+       if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize,
+                       page, scsi3addr, TYPE_CMD)) {
+               rc = -1;
+               goto out;
+       }
+       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(h, c);
+               rc = -1;
+       }
+out:
+       cmd_special_free(h, c);
+       return rc;
+       }
+
 static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
        u8 reset_type)
 {
@@ -2929,6 +2960,24 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
        return NULL;
 }
 
+static int hpsa_hba_mode_enabled(struct ctlr_info *h)
+{
+       int rc;
+       struct bmic_controller_parameters *ctlr_params;
+       ctlr_params = kzalloc(sizeof(struct bmic_controller_parameters),
+               GFP_KERNEL);
+
+       if (!ctlr_params)
+               return 0;
+       rc = hpsa_bmic_ctrl_mode_sense(h, RAID_CTLR_LUNID, 0, ctlr_params,
+               sizeof(struct bmic_controller_parameters));
+       if (rc != 0) {
+               kfree(ctlr_params);
+               return 0;
+       }
+       return ctlr_params->nvram_flags & (1 << 3) ? 1 : 0;
+}
+
 static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
 {
        /* the idea here is we could get notified
@@ -2952,6 +3001,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
        int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24;
        int i, n_ext_target_devs, ndevs_to_allocate;
        int raid_ctlr_position;
+       u8 rescan_hba_mode;
        DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
 
        currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -2965,6 +3015,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
        }
        memset(lunzerobits, 0, sizeof(lunzerobits));
 
+       rescan_hba_mode = hpsa_hba_mode_enabled(h);
+
+       if (!h->hba_mode_enabled && rescan_hba_mode)
+               dev_warn(&h->pdev->dev, "HBA mode enabled\n");
+       else if (h->hba_mode_enabled && !rescan_hba_mode)
+               dev_warn(&h->pdev->dev, "HBA mode disabled\n");
+
+       h->hba_mode_enabled = rescan_hba_mode;
+
        if (hpsa_gather_lun_info(h, reportlunsize,
                        (struct ReportLUNdata *) physdev_list, &nphysicals,
                        &physical_mode, logdev_list, &nlogicals))
@@ -3048,7 +3107,19 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
                                ncurrent++;
                        break;
                case TYPE_DISK:
-                       if (i >= nphysicals) {
+                       if (h->hba_mode_enabled) {
+                               /* never use raid mapper in HBA mode */
+                               this_device->offload_enabled = 0;
+                               ncurrent++;
+                               break;
+                       } else if (h->acciopath_status) {
+                               if (i >= nphysicals) {
+                                       ncurrent++;
+                                       break;
+                               }
+                       } else {
+                               if (i < nphysicals)
+                                       break;
                                ncurrent++;
                                break;
                        }
@@ -4116,7 +4187,10 @@ static int hpsa_register_scsi(struct ctlr_info *h)
        sh->max_lun = HPSA_MAX_LUN;
        sh->max_id = HPSA_MAX_LUN;
        sh->can_queue = h->nr_cmds;
-       sh->cmd_per_lun = h->nr_cmds;
+       if (h->hba_mode_enabled)
+               sh->cmd_per_lun = 7;
+       else
+               sh->cmd_per_lun = h->nr_cmds;
        sh->sg_tablesize = h->maxsgentries;
        h->scsi_host = sh;
        sh->hostdata[0] = (unsigned long) h;
@@ -5261,6 +5335,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
                        c->Request.CDB[8] = (size >> 8) & 0xFF;
                        c->Request.CDB[9] = size & 0xFF;
                        break;
+               case BMIC_SENSE_CONTROLLER_PARAMETERS:
+                       c->Request.CDBLen = 10;
+                       c->Request.Type.Attribute = ATTR_SIMPLE;
+                       c->Request.Type.Direction = XFER_READ;
+                       c->Request.Timeout = 0;
+                       c->Request.CDB[0] = BMIC_READ;
+                       c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS;
+                       c->Request.CDB[7] = (size >> 16) & 0xFF;
+                       c->Request.CDB[8] = (size >> 8) & 0xFF;
+                       break;
                default:
                        dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
                        BUG();
@@ -6885,6 +6969,7 @@ reinit_after_soft_reset:
 
        pci_set_drvdata(pdev, h);
        h->ndevices = 0;
+       h->hba_mode_enabled = 0;
        h->scsi_host = NULL;
        spin_lock_init(&h->devlock);
        hpsa_put_ctlr_into_performant_mode(h);
@@ -6944,8 +7029,8 @@ reinit_after_soft_reset:
                goto reinit_after_soft_reset;
        }
 
-       /* Enable Accelerated IO path at driver layer */
-       h->acciopath_status = 1;
+               /* Enable Accelerated IO path at driver layer */
+               h->acciopath_status = 1;
 
        h->drv_req_rescan = 0;
 
index ae8c592..44235a2 100644 (file)
@@ -64,6 +64,46 @@ struct reply_pool {
        u32 current_entry;
 };
 
+#pragma pack(1)
+struct bmic_controller_parameters {
+       u8   led_flags;
+       u8   enable_command_list_verification;
+       u8   backed_out_write_drives;
+       u16  stripes_for_parity;
+       u8   parity_distribution_mode_flags;
+       u16  max_driver_requests;
+       u16  elevator_trend_count;
+       u8   disable_elevator;
+       u8   force_scan_complete;
+       u8   scsi_transfer_mode;
+       u8   force_narrow;
+       u8   rebuild_priority;
+       u8   expand_priority;
+       u8   host_sdb_asic_fix;
+       u8   pdpi_burst_from_host_disabled;
+       char software_name[64];
+       char hardware_name[32];
+       u8   bridge_revision;
+       u8   snapshot_priority;
+       u32  os_specific;
+       u8   post_prompt_timeout;
+       u8   automatic_drive_slamming;
+       u8   reserved1;
+       u8   nvram_flags;
+       u8   cache_nvram_flags;
+       u8   drive_config_flags;
+       u16  reserved2;
+       u8   temp_warning_level;
+       u8   temp_shutdown_level;
+       u8   temp_condition_reset;
+       u8   max_coalesce_commands;
+       u32  max_coalesce_delay;
+       u8   orca_password[4];
+       u8   access_id[16];
+       u8   reserved[356];
+};
+#pragma pack()
+
 struct ctlr_info {
        int     ctlr;
        char    devname[8];
@@ -89,6 +129,7 @@ struct ctlr_info {
        unsigned int msi_vector;
        int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
        struct access_method access;
+       char hba_mode_enabled;
 
        /* queue and queue Info */
        struct list_head reqQ;
index 50388f1..b5cc705 100644 (file)
@@ -257,6 +257,7 @@ struct SenseSubsystem_info {
 #define BMIC_CACHE_FLUSH 0xc2
 #define HPSA_CACHE_FLUSH 0x01  /* C2 was already being used by HPSA */
 #define BMIC_FLASH_FIRMWARE 0xF7
+#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
 
 /* Command List Structure */
 union SCSI3Addr {