summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/hpsa.c139
-rw-r--r--drivers/scsi/hpsa.h1
-rw-r--r--drivers/scsi/hpsa_cmd.h11
3 files changed, 125 insertions, 26 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0af4c670c7cd..1a67d63d5585 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -275,7 +275,6 @@ 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 is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -776,7 +775,7 @@ static ssize_t path_info_show(struct device *dev,
hdev->bus, hdev->target, hdev->lun,
scsi_device_type(hdev->devtype));
- if (is_ext_target(h, hdev) ||
+ if (hdev->external ||
hdev->devtype == TYPE_RAID ||
is_logical_device(hdev)) {
output_len += snprintf(path[i] + output_len,
@@ -3034,6 +3033,35 @@ out:
return rc;
}
+static int hpsa_bmic_id_controller(struct ctlr_info *h,
+ struct bmic_identify_controller *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if (rc)
+ goto out;
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
+
static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
unsigned char scsi3addr[], u16 bmic_device_index,
struct bmic_identify_physical_device *buf, size_t bufsize)
@@ -3510,27 +3538,6 @@ static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
}
}
-static unsigned char *ext_target_model[] = {
- "MSA2012",
- "MSA2024",
- "MSA2312",
- "MSA2324",
- "P2000 G3 SAS",
- "MSA 2040 SAS",
- NULL,
-};
-
-static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
-{
- int i;
-
- for (i = 0; ext_target_model[i]; i++)
- if (strncmp(device->model, ext_target_model[i],
- strlen(ext_target_model[i])) == 0)
- return 1;
- return 0;
-}
-
/*
* Helper function to assign bus, target, lun mapping of devices.
* Logical drive target and lun are assigned at this time, but
@@ -3554,7 +3561,7 @@ static void figure_bus_target_lun(struct ctlr_info *h,
return;
}
/* It's a logical device */
- if (is_ext_target(h, device)) {
+ if (device->external) {
hpsa_set_bus_target_lun(device,
HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff,
lunid & 0x00ff);
@@ -3588,7 +3595,7 @@ static int add_ext_target_dev(struct ctlr_info *h,
if (!is_logical_dev_addr_mode(lunaddrbytes))
return 0; /* It's the logical targets that may lack lun 0. */
- if (!is_ext_target(h, tmpdevice))
+ if (!tmpdevice->external)
return 0; /* Only external target devices have this problem. */
if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */
@@ -3647,6 +3654,27 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
return 0;
}
+static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position,
+ int i, int nphysicals, int nlocal_logicals)
+{
+ /* In report logicals, local logicals are listed first,
+ * then any externals.
+ */
+ int logicals_start = nphysicals + (raid_ctlr_position == 0);
+
+ if (i == raid_ctlr_position)
+ return 0;
+
+ if (i < logicals_start)
+ return 0;
+
+ /* i is in logicals range, but still within local logicals */
+ if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals)
+ return 0;
+
+ return 1; /* it's an external lun */
+}
+
/*
* Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
* logdev. The number of luns in physdev and logdev are returned in
@@ -3770,6 +3798,32 @@ static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
sizeof(this_device->bay));
}
+/* get number of local logical disks. */
+static int hpsa_set_local_logical_count(struct ctlr_info *h,
+ struct bmic_identify_controller *id_ctlr,
+ u32 *nlocals)
+{
+ int rc;
+
+ if (!id_ctlr) {
+ dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n",
+ __func__);
+ return -ENOMEM;
+ }
+ memset(id_ctlr, 0, sizeof(*id_ctlr));
+ rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr));
+ if (!rc)
+ if (id_ctlr->configured_logical_drive_count < 256)
+ *nlocals = id_ctlr->configured_logical_drive_count;
+ else
+ *nlocals = le16_to_cpu(
+ id_ctlr->extended_logical_unit_count);
+ else
+ *nlocals = -1;
+ return rc;
+}
+
+
static void hpsa_update_scsi_devices(struct ctlr_info *h)
{
/* the idea here is we could get notified
@@ -3785,8 +3839,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
struct bmic_identify_physical_device *id_phys = NULL;
+ struct bmic_identify_controller *id_ctlr = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
+ u32 nlocal_logicals = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
@@ -3800,9 +3856,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL);
if (!currentsd || !physdev_list || !logdev_list ||
- !tmpdevice || !id_phys) {
+ !tmpdevice || !id_phys || !id_ctlr) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
@@ -3816,6 +3873,13 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
goto out;
}
+ /* Set number of local logicals (non PTRAID) */
+ if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) {
+ dev_warn(&h->pdev->dev,
+ "%s: Can't determine number of local logical devices.\n",
+ __func__);
+ }
+
/* We might see up to the maximum number of logical and physical disks
* plus external target devices, and a device for the local RAID
* controller.
@@ -3879,6 +3943,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
continue;
}
+ /* Determine if this is a lun from an external target array */
+ tmpdevice->external =
+ figure_external_status(h, raid_ctlr_position, i,
+ nphysicals, nlocal_logicals);
+
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
@@ -3962,6 +4031,7 @@ out:
kfree(currentsd);
kfree(physdev_list);
kfree(logdev_list);
+ kfree(id_ctlr);
kfree(id_phys);
}
@@ -6414,6 +6484,23 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0XFF;
break;
+ case BMIC_IDENTIFY_CONTROLLER:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = 0;
+ c->Request.CDB[3] = 0;
+ c->Request.CDB[4] = 0;
+ c->Request.CDB[5] = 0;
+ c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ c->Request.CDB[9] = 0;
+ break;
+
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index a4cab12fc3b4..ffcd4cbd5efc 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -77,6 +77,7 @@ struct hpsa_scsi_dev_t {
struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES];
int nphysical_disks;
int supports_aborts;
+ int external; /* 1-from external array 0-not <0-unknown */
};
struct reply_queue_buffer {
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index c2c07373dcd8..c83eaf1b03e1 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -286,6 +286,7 @@ struct SenseSubsystem_info {
#define BMIC_FLASH_FIRMWARE 0xF7
#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
+#define BMIC_IDENTIFY_CONTROLLER 0x11
/* Command List Structure */
union SCSI3Addr {
@@ -682,6 +683,16 @@ struct hpsa_pci_info {
u32 board_id;
};
+struct bmic_identify_controller {
+ u8 configured_logical_drive_count; /* offset 0 */
+ u8 pad1[153];
+ __le16 extended_logical_unit_count; /* offset 154 */
+ u8 pad2[136];
+ u8 controller_mode; /* offset 292 */
+ u8 pad3[32];
+};
+
+
struct bmic_identify_physical_device {
u8 scsi_bus; /* SCSI Bus number on controller */
u8 scsi_id; /* SCSI ID on this bus */