lkml.org 
[lkml]   [2018]   [Dec]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 2/6] scsi: hpsa: Support HBA mode on HP Smart Array P410i controllers
Date
This patch is based on code from the 316b221, most of which was removed by
the b9092b7.

Originally, HBA mode on these controllers was supported only on
Itanium-based HP Integrity servers running HP-UX. Tool for switching
between RAID and HBA modes existed only in form of EFI binary for
ia64 architecture: saupdate.efi[1]. However, I guessed how to overwrite the
corresponding flags field in controller's NVRAM, and was able to
reimplement RAID/HBA mode switching tool for Linux[2].

This change was successfully tested using blktests[3] and xfstests[4] on
my hardware, with embedded P410i controller (PCI ID: 103c:3245, board
ID: 0x3245103c) with firmware version 6.64.

This may work with some other controllers, but it is not tested
(because I do not have the hardware) and it may be very dangerous. That is
why this functionality is disabled by default and may be enabled only
manually using the new module parameter.

[1] https://support.hpe.com/hpsc/swd/public/detail?swItemId=MTX_0b76aec489764aea9802a6d27b
[2] https://github.com/im-0/hpsahba
[3] https://github.com/osandov/blktests
[4] https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git

Signed-off-by: Ivan Mironov <mironov.ivan@gmail.com>
---
drivers/scsi/hpsa.c | 98 +++++++++++++++++++++++++++++++++++++++++++--
drivers/scsi/hpsa.h | 3 ++
2 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index fc06b790f16b..ee3d7c722a63 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -88,6 +88,11 @@ module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(hpsa_simple_mode,
"Use 'simple mode' rather than 'performant mode'");

+static bool hpsa_use_nvram_hba_flag;
+module_param(hpsa_use_nvram_hba_flag, bool, 0444);
+MODULE_PARM_DESC(hpsa_use_nvram_hba_flag,
+ "Use flag from NVRAM to enable HBA mode");
+
/* define the PCI info for the cards we can control */
static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
@@ -3039,6 +3044,37 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
return rc;
}

+static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
+ struct bmic_controller_parameters *buf)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, sizeof(*buf),
+ 0, RAID_CTLR_LUNID, TYPE_CMD)) {
+ rc = -1;
+ 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_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
u8 reset_type, int reply_queue)
{
@@ -4296,6 +4332,50 @@ static bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes,
return false;
}

+static int hpsa_nvram_hba_flag_enabled(struct ctlr_info *h, bool *flag_enabled)
+{
+ int rc;
+ struct bmic_controller_parameters *ctlr_params;
+
+ ctlr_params = kzalloc(sizeof(*ctlr_params), GFP_KERNEL);
+ if (!ctlr_params) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = hpsa_bmic_ctrl_mode_sense(h, ctlr_params);
+ if (rc)
+ goto out;
+
+ *flag_enabled = ctlr_params->nvram_flags & HPSA_NVRAM_FLAG_HBA;
+
+out:
+ kfree(ctlr_params);
+ return rc;
+}
+
+static int hpsa_update_nvram_hba_mode(struct ctlr_info *h)
+{
+ int rc;
+ bool flag_enabled;
+
+ if (!hpsa_use_nvram_hba_flag)
+ return 0;
+
+ rc = hpsa_nvram_hba_flag_enabled(h, &flag_enabled);
+ if (rc == -ENOMEM)
+ dev_warn(&h->pdev->dev, "Out of memory.\n");
+ if (rc)
+ return rc;
+
+ dev_info(&h->pdev->dev, "NVRAM HBA flag: %s\n",
+ flag_enabled ? "enabled" : "disabled");
+
+ h->nvram_hba_mode_enabled = flag_enabled;
+
+ return 0;
+}
+
static void hpsa_update_scsi_devices(struct ctlr_info *h)
{
/* the idea here is we could get notified
@@ -4352,6 +4432,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
__func__);
}

+ if (hpsa_update_nvram_hba_mode(h)) {
+ h->drv_req_rescan = 1;
+ goto out;
+ }
+
/* 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.
@@ -4437,11 +4522,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
* Expose all devices except for physical devices that
* are masked.
*/
- if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device)
- this_device->expose_device = 0;
- else
+ if (MASKED_DEVICE(lunaddrbytes) &&
+ this_device->physical_device) {
+ if (is_disk_or_zbc(this_device) &&
+ h->nvram_hba_mode_enabled)
+ this_device->expose_device = 1;
+ else
+ this_device->expose_device = 0;
+ } else {
this_device->expose_device = 1;
-
+ }

/*
* Get the SAS address for physical devices that are exposed.
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 59e023696fff..5b508f270520 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -158,6 +158,8 @@ struct bmic_controller_parameters {
};
#pragma pack()

+#define HPSA_NVRAM_FLAG_HBA (1 << 3)
+
struct ctlr_info {
unsigned int *reply_map;
int ctlr;
@@ -182,6 +184,7 @@ struct ctlr_info {
unsigned int msix_vectors;
int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
struct access_method access;
+ bool nvram_hba_mode_enabled;

/* queue and queue Info */
unsigned int Qdepth;
--
2.19.2
\
 
 \ /
  Last update: 2018-12-14 14:24    [W:0.123 / U:0.168 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site