summaryrefslogtreecommitdiffstats
path: root/sys/dev/mfi
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2006-06-20 22:41:44 +0000
committerps <ps@FreeBSD.org>2006-06-20 22:41:44 +0000
commit2946fa1ebcb52cf7428a24a7a7cf12731482d083 (patch)
tree85bd810e73032f5b1beef03e495b84923a2c8414 /sys/dev/mfi
parentf51ea9f5e21844c7505b147fb0d3136d876562e4 (diff)
downloadFreeBSD-src-2946fa1ebcb52cf7428a24a7a7cf12731482d083.zip
FreeBSD-src-2946fa1ebcb52cf7428a24a7a7cf12731482d083.tar.gz
Instead of using scsi probes to do device discovery, use the firmware
commands to grab the device listing. This resolves issues using multiple volumes, where each volume was actually internally pointing to target 0.
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r--sys/dev/mfi/mfi.c279
-rw-r--r--sys/dev/mfi/mfi_disk.c12
-rw-r--r--sys/dev/mfi/mfi_pci.c1
-rw-r--r--sys/dev/mfi/mfireg.h96
-rw-r--r--sys/dev/mfi/mfivar.h4
5 files changed, 178 insertions, 214 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index ddddc59..e2dfacd9 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -56,6 +56,7 @@ static int mfi_alloc_commands(struct mfi_softc *);
static void mfi_release_command(struct mfi_command *cm);
static int mfi_comms_init(struct mfi_softc *);
static int mfi_polled_command(struct mfi_softc *, struct mfi_command *);
+static int mfi_wait_command(struct mfi_softc *, struct mfi_command *);
static int mfi_get_controller_info(struct mfi_softc *);
static int mfi_get_log_state(struct mfi_softc *,
struct mfi_evt_log_state **);
@@ -68,16 +69,12 @@ static void mfi_data_cb(void *, bus_dma_segment_t *, int, int);
static void mfi_startup(void *arg);
static void mfi_intr(void *arg);
static void mfi_enable_intr(struct mfi_softc *sc);
-static void mfi_ldprobe_inq(struct mfi_softc *sc);
-static void mfi_ldprobe_inq_complete(struct mfi_command *);
-static int mfi_ldprobe_capacity(struct mfi_softc *sc, int id);
-static void mfi_ldprobe_capacity_complete(struct mfi_command *);
-static int mfi_ldprobe_tur(struct mfi_softc *sc, int id);
-static void mfi_ldprobe_tur_complete(struct mfi_command *);
+static void mfi_ldprobe(struct mfi_softc *sc);
static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
static void mfi_aen_complete(struct mfi_command *);
static int mfi_aen_setup(struct mfi_softc *, uint32_t);
-static int mfi_add_ld(struct mfi_softc *sc, int id, uint64_t, uint32_t);
+static int mfi_add_ld(struct mfi_softc *sc, int);
+static void mfi_add_ld_complete(struct mfi_command *);
static struct mfi_command * mfi_bio_command(struct mfi_softc *);
static void mfi_bio_complete(struct mfi_command *);
static int mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
@@ -679,6 +676,18 @@ mfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
return (0);
}
+static int
+mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
+{
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ cm->cm_complete = NULL;
+
+ mfi_enqueue_ready(cm);
+ mfi_startio(sc);
+ return (msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0));
+}
+
void
mfi_free(struct mfi_softc *sc)
{
@@ -747,7 +756,7 @@ mfi_startup(void *arg)
config_intrhook_disestablish(&sc->mfi_ich);
mfi_enable_intr(sc);
- mfi_ldprobe_inq(sc);
+ mfi_ldprobe(sc);
}
static void
@@ -824,136 +833,41 @@ mfi_enable_intr(struct mfi_softc *sc)
}
static void
-mfi_ldprobe_inq(struct mfi_softc *sc)
-{
- struct mfi_command *cm;
- struct mfi_pass_frame *pass;
- char *inq;
- int i;
-
- /* Probe all possible targets with a SCSI INQ command */
- mtx_lock(&sc->mfi_io_lock);
- sc->mfi_probe_count = 0;
- for (i = 0; i < MFI_MAX_CHANNEL_DEVS; i++) {
- inq = malloc(MFI_INQ_LENGTH, M_MFIBUF, M_NOWAIT|M_ZERO);
- if (inq == NULL)
- break;
- cm = mfi_dequeue_free(sc);
- if (cm == NULL) {
- free(inq, M_MFIBUF);
- msleep(mfi_startup, &sc->mfi_io_lock, 0, "mfistart",
- 5 * hz);
- i--;
- continue;
- }
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = i;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = MFI_INQ_LENGTH;
- bzero(pass->cdb, 16);
- pass->cdb[0] = INQUIRY;
- pass->cdb[4] = MFI_INQ_LENGTH;
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_inq_complete;
- cm->cm_private = inq;
- cm->cm_sg = &pass->sgl;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags |= MFI_CMD_DATAIN;
- cm->cm_data = inq;
- cm->cm_len = MFI_INQ_LENGTH;
- sc->mfi_probe_count++;
- mfi_enqueue_ready(cm);
- mfi_startio(sc);
- }
-
- /* Sleep while the arrays are attaching */
- msleep(mfi_startup, &sc->mfi_io_lock, 0, "mfistart", 60 * hz);
- mtx_unlock(&sc->mfi_io_lock);
-
- return;
-}
-
-static void
-mfi_ldprobe_inq_complete(struct mfi_command *cm)
+mfi_ldprobe(struct mfi_softc *sc)
{
struct mfi_frame_header *hdr;
- struct mfi_softc *sc;
- struct scsi_inquiry_data *inq;
+ struct mfi_command *cm = NULL;
+ struct mfi_ld_list *list = NULL;
+ int error, i;
- sc = cm->cm_sc;
- inq = cm->cm_private;
- hdr = &cm->cm_frame->header;
+ mtx_lock(&sc->mfi_io_lock);
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
+ (void **)&list, sizeof(*list));
+ if (error)
+ goto out;
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00) ||
- (SID_TYPE(inq) != T_DIRECT)) {
- free(inq, M_MFIBUF);
- mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
- return;
+ cm->cm_flags = MFI_CMD_DATAIN;
+ if (mfi_wait_command(sc, cm) != 0) {
+ device_printf(sc->mfi_dev, "Failed to get device listing\n");
+ goto out;
}
- free(inq, M_MFIBUF);
- mfi_release_command(cm);
- mfi_ldprobe_tur(sc, hdr->target_id);
-}
-
-static int
-mfi_ldprobe_tur(struct mfi_softc *sc, int id)
-{
- struct mfi_command *cm;
- struct mfi_pass_frame *pass;
-
- cm = mfi_dequeue_free(sc);
- if (cm == NULL)
- return (EBUSY);
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = id;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = 0;
- bzero(pass->cdb, 16);
- pass->cdb[0] = TEST_UNIT_READY;
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_tur_complete;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags = 0;
- mfi_enqueue_ready(cm);
- mfi_startio(sc);
-
- return (0);
-}
-
-static void
-mfi_ldprobe_tur_complete(struct mfi_command *cm)
-{
- struct mfi_frame_header *hdr;
- struct mfi_softc *sc;
-
- sc = cm->cm_sc;
hdr = &cm->cm_frame->header;
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
+ hdr->cmd_status);
+ goto out;
+ }
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
- device_printf(sc->mfi_dev, "Logical disk %d is not ready, "
- "cmd_status= %d scsi_status= %d\n", hdr->target_id,
- hdr->cmd_status, hdr->scsi_status);
- mfi_print_sense(sc, cm->cm_sense);
+ for (i = 0; i < list->ld_count; i++)
+ mfi_add_ld(sc, list->ld_list[i].ld.target_id);
+out:
+ if (list)
+ free(list, M_MFIBUF);
+ if (cm)
mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
- return;
- }
- mfi_release_command(cm);
- mfi_ldprobe_capacity(sc, hdr->target_id);
+ mtx_unlock(&sc->mfi_io_lock);
+ return;
}
#ifdef NOTYET
@@ -1361,40 +1275,29 @@ mfi_get_entry(struct mfi_softc *sc, int seq)
#endif
static int
-mfi_ldprobe_capacity(struct mfi_softc *sc, int id)
+mfi_add_ld(struct mfi_softc *sc, int id)
{
struct mfi_command *cm;
- struct mfi_pass_frame *pass;
- struct scsi_read_capacity_data_long *cap;
+ struct mfi_dcmd_frame *dcmd = NULL;
+ struct mfi_ld_info *ld_info = NULL;
+ int error;
- cap = malloc(sizeof(*cap), M_MFIBUF, M_NOWAIT|M_ZERO);
- if (cap == NULL)
- return (ENOMEM);
- cm = mfi_dequeue_free(sc);
- if (cm == NULL) {
- free(cap, M_MFIBUF);
- return (EBUSY);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
+ (void **)&ld_info, sizeof(*ld_info));
+ if (error) {
+ device_printf(sc->mfi_dev,
+ "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
+ if (ld_info)
+ free(ld_info, M_MFIBUF);
+ return (error);
}
- pass = &cm->cm_frame->pass;
- pass->header.cmd = MFI_CMD_LD_SCSI_IO;
- pass->header.target_id = id;
- pass->header.lun_id = 0;
- pass->header.cdb_len = 6;
- pass->header.timeout = 0;
- pass->header.data_len = sizeof(*cap);
- bzero(pass->cdb, 16);
- pass->cdb[0] = 0x9e; /* READ CAPACITY 16 */
- pass->cdb[13] = sizeof(*cap);
- pass->header.sense_len = MFI_SENSE_LEN;
- pass->sense_addr_lo = cm->cm_sense_busaddr;
- pass->sense_addr_hi = 0;
- cm->cm_complete = mfi_ldprobe_capacity_complete;
- cm->cm_private = cap;
- cm->cm_sg = &pass->sgl;
- cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
- cm->cm_flags |= MFI_CMD_DATAIN;
- cm->cm_data = cap;
- cm->cm_len = sizeof(*cap);
+ cm->cm_flags = MFI_CMD_DATAIN;
+ cm->cm_complete = mfi_add_ld_complete;
+ dcmd = &cm->cm_frame->dcmd;
+ dcmd->mbox[0] = id;
+
mfi_enqueue_ready(cm);
mfi_startio(sc);
@@ -1402,70 +1305,42 @@ mfi_ldprobe_capacity(struct mfi_softc *sc, int id)
}
static void
-mfi_ldprobe_capacity_complete(struct mfi_command *cm)
+mfi_add_ld_complete(struct mfi_command *cm)
{
struct mfi_frame_header *hdr;
+ struct mfi_ld_info *ld_info;
struct mfi_softc *sc;
- struct scsi_read_capacity_data_long *cap;
- uint64_t sectors;
- uint32_t secsize;
- int target;
+ struct mfi_ld *ld;
+ device_t child;
sc = cm->cm_sc;
- cap = cm->cm_private;
hdr = &cm->cm_frame->header;
+ ld_info = cm->cm_private;
- if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0x00)) {
- device_printf(sc->mfi_dev, "Failed to read capacity for "
- "logical disk\n");
- device_printf(sc->mfi_dev, "cmd_status= %d scsi_status= %d\n",
- hdr->cmd_status, hdr->scsi_status);
- free(cap, M_MFIBUF);
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ free(ld_info, M_MFIBUF);
mfi_release_command(cm);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
return;
}
- target = hdr->target_id;
- sectors = scsi_8btou64(cap->addr);
- secsize = scsi_4btoul(cap->length);
- free(cap, M_MFIBUF);
mfi_release_command(cm);
- mfi_add_ld(sc, target, sectors, secsize);
- if (--sc->mfi_probe_count <= 0)
- wakeup(mfi_startup);
-
- return;
-}
-
-static int
-mfi_add_ld(struct mfi_softc *sc, int id, uint64_t sectors, uint32_t secsize)
-{
- struct mfi_ld *ld;
- device_t child;
-
- if ((secsize == 0) || (sectors == 0)) {
- device_printf(sc->mfi_dev, "Invalid capacity parameters for "
- "logical disk %d\n", id);
- return (EINVAL);
- }
ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
if (ld == NULL) {
device_printf(sc->mfi_dev, "Cannot allocate ld\n");
- return (ENOMEM);
+ free(ld_info, M_MFIBUF);
+ return;
}
if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
device_printf(sc->mfi_dev, "Failed to add logical disk\n");
free(ld, M_MFIBUF);
- return (EINVAL);
+ free(ld_info, M_MFIBUF);
+ return;
}
- ld->ld_id = id;
+ ld->ld_id = ld_info->ld_config.properties.ld.target_id;
ld->ld_disk = child;
- ld->ld_secsize = secsize;
- ld->ld_sectors = sectors;
+ ld->ld_info = ld_info;
device_set_ivars(child, ld);
device_set_desc(child, "MFI Logical Disk");
@@ -1474,8 +1349,6 @@ mfi_add_ld(struct mfi_softc *sc, int id, uint64_t sectors, uint32_t secsize)
bus_generic_attach(sc->mfi_dev);
mtx_unlock(&Giant);
mtx_lock(&sc->mfi_io_lock);
-
- return (0);
}
static struct mfi_command *
@@ -1705,6 +1578,8 @@ mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
if (cm->cm_complete != NULL)
cm->cm_complete(cm);
+ else
+ wakeup(cm);
sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
mfi_startio(sc);
diff --git a/sys/dev/mfi/mfi_disk.c b/sys/dev/mfi/mfi_disk.c
index dc40e3b..909adcf 100644
--- a/sys/dev/mfi/mfi_disk.c
+++ b/sys/dev/mfi/mfi_disk.c
@@ -113,14 +113,8 @@ mfi_disk_attach(device_t dev)
sc->ld_ld = device_get_ivars(dev);
sc->ld_controller = device_get_softc(device_get_parent(dev));
- sectors = sc->ld_ld->ld_sectors;
- secsize = sc->ld_ld->ld_secsize;
- if (secsize != MFI_SECTOR_LEN) {
- device_printf(sc->ld_dev, "Reported sector length %d is not "
- "512, aborting\n", secsize);
- free(sc->ld_ld, M_MFIBUF);
- return (EINVAL);
- }
+ sectors = ld->ld_info->size;
+ secsize = MFI_SECTOR_LEN;
TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, ld, ld_link);
device_printf(dev, "%juMB (%ju sectors) RAID\n",
@@ -235,7 +229,7 @@ mfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
if (len > 0) {
if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
- sc->ld_ld->ld_secsize, virt, len)) != 0)
+ MFI_SECTOR_LEN, virt, len)) != 0)
return (error);
} else {
/* mfi_sync_cache(parent_sc, sc->ld_id); */
diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c
index f4e946d..e34e857 100644
--- a/sys/dev/mfi/mfi_pci.c
+++ b/sys/dev/mfi/mfi_pci.c
@@ -207,6 +207,7 @@ mfi_pci_detach(device_t dev)
if (error)
return (error);
TAILQ_REMOVE(&sc->mfi_ld_tqh, ld, ld_link);
+ free(ld->ld_info, M_MFIBUF);
free(ld, M_MFIBUF);
}
diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h
index 597a0a7..9fdd375 100644
--- a/sys/dev/mfi/mfireg.h
+++ b/sys/dev/mfi/mfireg.h
@@ -106,7 +106,10 @@ typedef enum {
MFI_DCMD_CTRL_EVENT_GETINFO = 0x01040100,
MFI_DCMD_CTRL_EVENT_GET = 0x01040300,
MFI_DCMD_CTRL_EVENT_WAIT = 0x01040500,
+ MFI_DCMD_LD_GET_LIST = 0x03010000,
+ MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000,
+ MFI_DCMD_LD_SET_PROP = 0x03040000,
MFI_DCMD_CLUSTER = 0x08000000,
MFI_DCMD_CLUSTER_RESET_ALL = 0x08010100,
MFI_DCMD_CLUSTER_RESET_LD = 0x08010200
@@ -727,4 +730,97 @@ struct mfi_log_detail {
char description[128];
} __packed;
+struct mfi_ldref {
+ uint8_t target_id;
+ uint8_t reserved;
+ uint16_t seq;
+} __packed;
+
+struct mfi_ld_list {
+ uint32_t ld_count;
+ uint32_t reserved1;
+ struct {
+ struct mfi_ldref ld;
+ uint8_t state;
+ uint8_t reserved2[3];
+ uint64_t size;
+ } ld_list[MFI_MAX_LD];
+} __packed;
+
+enum mfi_ld_access {
+ MFI_LD_ACCESS_RW = 0,
+ MFI_LD_ACCSSS_RO = 2,
+ MFI_LD_ACCESS_BLOCKED = 3,
+};
+#define MFI_LD_ACCESS_MASK 3
+
+enum mfi_ld_state {
+ MFI_LD_STATE_OFFLINE = 0,
+ MFI_LD_STATE_PARTIALLY_DEGRADED = 1,
+ MFI_LD_STATE_DEGRADED = 2,
+ MFI_LD_STATE_OPTIMAL = 3
+};
+
+struct mfi_ld_props {
+ struct mfi_ldref ld;
+ char name[16];
+ uint8_t default_cache_policy;
+ uint8_t access_policy;
+ uint8_t disk_cache_policy;
+ uint8_t current_cache_policy;
+ uint8_t no_bgi;
+ uint8_t reserved[7];
+} __packed;
+
+struct mfi_ld_params {
+ uint8_t primary_raid_level;
+ uint8_t raid_level_qualifier;
+ uint8_t secondary_raid_level;
+ uint8_t stripe_size;
+ uint8_t num_drives;
+ uint8_t span_depth;
+ uint8_t state;
+ uint8_t init_state;
+ uint8_t is_consistent;
+ uint8_t reserved[23];
+} __packed;
+
+struct mfi_ld_progress {
+ uint32_t active;
+#define MFI_LD_PROGRESS_CC (1<<0)
+#define MFI_LD_PROGRESS_BGI (1<<1)
+#define MFI_LD_PROGRESS_FGI (1<<2)
+#define MFI_LD_PORGRESS_RECON (1<<3)
+ struct mfi_progress cc;
+ struct mfi_progress bgi;
+ struct mfi_progress fgi;
+ struct mfi_progress recon;
+ struct mfi_progress reserved[4];
+} __packed;
+
+struct mfi_span {
+ uint64_t start_block;
+ uint64_t num_blocks;
+ uint16_t array_ref;
+ uint8_t reserved[6];
+} __packed;
+
+#define MFI_MAX_SPAN_DEPTH 8
+struct mfi_ld_config {
+ struct mfi_ld_props properties;
+ struct mfi_ld_params params;
+ struct mfi_span span[MFI_MAX_SPAN_DEPTH];
+} __packed;
+
+struct mfi_ld_info {
+ struct mfi_ld_config ld_config;
+ uint64_t size;
+ struct mfi_ld_progress progress;
+ uint16_t cluster_owner;
+ uint8_t reconstruct_active;
+ uint8_t reserved1[1];
+ uint8_t vpd_page83[64];
+ uint8_t reserved2[16];
+} __packed;
+
#endif /* _MFIREG_H */
diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h
index b558365..7b27491 100644
--- a/sys/dev/mfi/mfivar.h
+++ b/sys/dev/mfi/mfivar.h
@@ -75,8 +75,7 @@ struct mfi_command {
struct mfi_ld {
TAILQ_ENTRY(mfi_ld) ld_link;
device_t ld_disk;
- uint64_t ld_sectors;
- uint32_t ld_secsize;
+ struct mfi_ld_info *ld_info;
int ld_id;
};
@@ -133,7 +132,6 @@ struct mfi_softc {
struct intr_config_hook mfi_ich;
eventhandler_tag eh;
- int mfi_probe_count;
/*
* Allocation for the command array. Used as an indexable array to
OpenPOWER on IntegriCloud