From: Stephen M. Cameron <scameron@xxxxxxxxxxxxxxxxxx> 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@xxxxxx> --- drivers/scsi/hpsa.c | 93 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/scsi/hpsa.h | 41 +++++++++++++++++++++ drivers/scsi/hpsa_cmd.h | 1 + 3 files changed, 131 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 23110a8..355ebf3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -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; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index ae8c592..44235a2 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -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; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 50388f1..b5cc705 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -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 { -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html