summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2014-09-30 18:02:34 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2014-09-30 18:02:34 +0000
commitb80c0aaef252aa7807089d91ed82f7db25d68bc9 (patch)
tree604137926505bdbdf6d290e7da22fdec44a1f172 /sys/dev
parent8bd665503f6e8639d1606239c24cdb65615866b9 (diff)
Add support for "physical devices". Tested on:
mfii0 at pci1 dev 0 function 0 "Symbios Logic MegaRAID SAS2208" rev 0x05: msi mfii0: "LSI MegaRAID ROMB", firmware 23.22.0-0012, 1024MB cache ok dlg@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/mfii.c263
1 files changed, 261 insertions, 2 deletions
diff --git a/sys/dev/pci/mfii.c b/sys/dev/pci/mfii.c
index 604c123eb93..08ea68c3456 100644
--- a/sys/dev/pci/mfii.c
+++ b/sys/dev/pci/mfii.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfii.c,v 1.17 2014/07/13 23:10:23 deraadt Exp $ */
+/* $OpenBSD: mfii.c,v 1.18 2014/09/30 18:02:33 kettenis Exp $ */
/*
* Copyright (c) 2012 David Gwynne <dlg@openbsd.org>
@@ -48,6 +48,7 @@
#define MFII_REQ_TYPE_LDIO (0x7 << 1)
#define MFII_REQ_TYPE_MFA (0x1 << 1)
#define MFII_REQ_TYPE_NO_LOCK (0x2 << 1)
+#define MFII_REQ_TYPE_HI_PRI (0x6 << 1)
#define MFII_REQ_MFA(_a) htole64((_a) | MFII_REQ_TYPE_MFA)
@@ -59,9 +60,11 @@ struct mfii_request_descr {
u_int16_t smid;
u_int16_t lmid;
- u_int16_t field;
+ u_int16_t dev_handle;
} __packed;
+#define MFII_RAID_CTX_IO_TYPE_SYSPD (0x1 << 4)
+
struct mfii_raid_context {
u_int8_t type_nseg;
u_int8_t _reserved1;
@@ -105,6 +108,34 @@ struct mfii_sge {
#define MFII_REQUEST_SIZE 256
+#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+
+#define MFII_MAX_ROW 32
+#define MFII_MAX_ARRAY 128
+
+struct mfii_array_map {
+ uint16_t mam_pd[MFII_MAX_ROW];
+} __packed;
+
+struct mfii_dev_handle {
+ uint16_t mdh_cur_handle;
+ uint8_t mdh_valid;
+ uint8_t mdh_reserved;
+ uint16_t mdh_handle[2];
+} __packed;
+
+struct mfii_ld_map {
+ uint32_t mlm_total_size;
+ uint32_t mlm_reserved1[5];
+ uint32_t mlm_num_lds;
+ uint32_t mlm_reserved2;
+ uint8_t mlm_tgtid_to_ld[2 * MFI_MAX_LD];
+ uint8_t mlm_pd_timeout;
+ uint8_t mlm_reserved3[7];
+ struct mfii_array_map mlm_am[MFII_MAX_ARRAY];
+ struct mfii_dev_handle mlm_dev_handle[MFI_MAX_PD];
+} __packed;
+
struct mfii_dmamem {
bus_dmamap_t mdm_map;
bus_dma_segment_t mdm_seg;
@@ -156,6 +187,19 @@ struct mfii_ccb {
};
SIMPLEQ_HEAD(mfii_ccb_list, mfii_ccb);
+struct mfii_pd_link {
+ u_int16_t pd_id;
+ struct mfi_pd_details pd_info;
+ u_int16_t pd_handle;
+};
+
+struct mfii_pd_softc {
+ struct scsi_link pd_link;
+ struct scsibus_softc *pd_scsibus;
+ struct mfii_pd_link *pd_links[MFI_MAX_PD];
+ uint8_t pd_timeout;
+};
+
struct mfii_softc {
struct device sc_dev;
@@ -189,6 +233,7 @@ struct mfii_softc {
struct scsi_link sc_link;
struct scsibus_softc *sc_scsibus;
+ struct mfii_pd_softc *sc_pd;
struct scsi_iopool sc_iopool;
struct mfi_ctrl_info sc_info;
@@ -222,6 +267,15 @@ struct scsi_adapter mfii_switch = {
NULL /* ioctl */
};
+void mfii_pd_scsi_cmd(struct scsi_xfer *);
+int mfii_pd_scsi_probe(struct scsi_link *);
+
+struct scsi_adapter mfii_pd_switch = {
+ mfii_pd_scsi_cmd,
+ scsi_minphys,
+ mfii_pd_scsi_probe
+};
+
#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
u_int32_t mfii_read(struct mfii_softc *, bus_size_t);
@@ -239,6 +293,7 @@ void mfii_scrub_ccb(struct mfii_ccb *);
int mfii_transition_firmware(struct mfii_softc *);
int mfii_initialise_firmware(struct mfii_softc *);
int mfii_get_info(struct mfii_softc *);
+int mfii_syspd(struct mfii_softc *);
void mfii_start(struct mfii_softc *, struct mfii_ccb *);
void mfii_done(struct mfii_softc *, struct mfii_ccb *);
@@ -264,6 +319,8 @@ int mfii_scsi_cmd_io(struct mfii_softc *,
struct scsi_xfer *);
int mfii_scsi_cmd_cdb(struct mfii_softc *,
struct scsi_xfer *);
+int mfii_pd_scsi_cmd_cdb(struct mfii_softc *,
+ struct scsi_xfer *);
#define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
@@ -388,6 +445,8 @@ mfii_attach(struct device *parent, struct device *self, void *aux)
config_found(&sc->sc_dev, &saa, scsiprint);
+ mfii_syspd(sc);
+
/* enable interrupts */
mfii_write(sc, MFI_OSTS, 0xffffffff);
mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID);
@@ -406,6 +465,92 @@ pci_unmap:
}
int
+mfii_syspd(struct mfii_softc *sc)
+{
+ struct scsibus_attach_args saa;
+ struct scsi_link *link;
+ struct mfii_ld_map *lm;
+ struct mfii_pd_link *pl;
+ struct mfi_pd_list *pd;
+ struct mfii_ccb *ccb;
+ u_int npds, i;
+ int rv;
+
+ sc->sc_pd = malloc(sizeof(*sc->sc_pd), M_DEVBUF, M_WAITOK|M_ZERO);
+ if (sc->sc_pd == NULL)
+ return (1);
+
+ lm = malloc(sizeof(*lm), M_TEMP, M_WAITOK|M_ZERO);
+ if (lm == NULL)
+ goto free_pdsc;
+
+ ccb = scsi_io_get(&sc->sc_iopool, 0);
+ rv = mfii_mgmt(sc, ccb, MR_DCMD_LD_MAP_GET_INFO, NULL,
+ lm, sizeof(*lm), SCSI_DATA_IN|SCSI_NOSLEEP);
+ scsi_io_put(&sc->sc_iopool, ccb);
+ if (rv != 0)
+ goto free_lm;
+
+ sc->sc_pd->pd_timeout = lm->mlm_pd_timeout;
+
+ pd = malloc(sizeof(*pd), M_TEMP, M_WAITOK|M_ZERO);
+ if (pd == NULL)
+ goto free_lm;
+
+ ccb = scsi_io_get(&sc->sc_iopool, 0);
+ rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_LIST, NULL,
+ pd, sizeof(*pd), SCSI_DATA_IN|SCSI_NOSLEEP);
+ scsi_io_put(&sc->sc_iopool, ccb);
+ if (rv != 0)
+ goto free_pd;
+
+ npds = letoh32(pd->mpl_no_pd);
+ for (i = 0; i < npds; i++) {
+ pl = malloc(sizeof(*pl), M_DEVBUF, M_WAITOK|M_ZERO);
+ if (pl == NULL)
+ goto free_pl;
+
+ pl->pd_id = pd->mpl_address[i].mpa_pd_id;
+ pl->pd_handle = lm->mlm_dev_handle[i].mdh_cur_handle;
+ sc->sc_pd->pd_links[i] = pl;
+ }
+
+ free(pd, M_TEMP, 0);
+ free(lm, M_TEMP, 0);
+
+ link = &sc->sc_pd->pd_link;
+ link->adapter = &mfii_pd_switch;
+ link->adapter_softc = sc;
+ link->adapter_buswidth = MFI_MAX_PD;
+ link->adapter_target = -1;
+ link->openings = sc->sc_max_cmds - 1;
+ link->pool = &sc->sc_iopool;
+
+ bzero(&saa, sizeof(saa));
+ saa.saa_sc_link = link;
+
+ sc->sc_pd->pd_scsibus = (struct scsibus_softc *)
+ config_found(&sc->sc_dev, &saa, scsiprint);
+
+ return (0);
+free_pl:
+ for (i = 0; i < npds; i++) {
+ pl = sc->sc_pd->pd_links[i];
+ if (pl == NULL)
+ break;
+
+ free(pl, M_DEVBUF, 0);
+ }
+free_pd:
+ free(pd, M_TEMP, 0);
+free_lm:
+ free(lm, M_TEMP, 0);
+free_pdsc:
+ free(sc->sc_pd, M_DEVBUF, 0);
+ return (1);
+}
+
+int
mfii_detach(struct device *self, int flags)
{
struct mfii_softc *sc = (struct mfii_softc *)self;
@@ -1264,6 +1409,120 @@ mfii_scsi_cmd_cdb(struct mfii_softc *sc, struct scsi_xfer *xs)
return (0);
}
+void
+mfii_pd_scsi_cmd(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct mfii_softc *sc = link->adapter_softc;
+ struct mfii_ccb *ccb = xs->io;
+
+ mfii_scrub_ccb(ccb);
+ ccb->ccb_cookie = xs;
+ ccb->ccb_done = mfii_scsi_cmd_done;
+ ccb->ccb_data = xs->data;
+ ccb->ccb_len = xs->datalen;
+
+ if (mfii_pd_scsi_cmd_cdb(sc, xs) != 0)
+ goto stuffup;
+
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+
+ if (ISSET(xs->flags, SCSI_POLL)) {
+ if (mfii_poll(sc, ccb) != 0)
+ goto stuffup;
+ return;
+ }
+
+ mfii_start(sc, ccb);
+ return;
+
+stuffup:
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+}
+
+int
+mfii_pd_scsi_probe(struct scsi_link *link)
+{
+ struct mfii_ccb *ccb;
+ uint8_t mbox[MFI_MBOX_SIZE];
+ struct mfii_softc *sc = link->adapter_softc;
+ struct mfii_pd_link *pl = sc->sc_pd->pd_links[link->target];
+ int rv;
+
+ if (link->lun > 0)
+ return (0);
+
+ if (pl == NULL)
+ return (ENXIO);
+
+ memset(mbox, 0, sizeof(mbox));
+ memcpy(&mbox[0], &pl->pd_id, sizeof(pl->pd_id));
+
+ ccb = scsi_io_get(&sc->sc_iopool, 0);
+ rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_INFO, mbox, &pl->pd_info,
+ sizeof(pl->pd_info), SCSI_DATA_IN|SCSI_NOSLEEP);
+ scsi_io_put(&sc->sc_iopool, ccb);
+ if (rv != 0)
+ return (EIO);
+
+ if (letoh16(pl->pd_info.mpd_fw_state) != MFI_PD_SYSTEM)
+ return (ENXIO);
+
+ return (0);
+}
+
+int
+mfii_pd_scsi_cmd_cdb(struct mfii_softc *sc, struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct mfii_ccb *ccb = xs->io;
+ struct mpii_msg_scsi_io *io = ccb->ccb_request;
+ struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
+
+ io->dev_handle = sc->sc_pd->pd_links[link->target]->pd_handle;
+ io->function = 0;
+ io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
+ io->sgl_flags = htole16(0x02); /* XXX */
+ io->sense_buffer_length = sizeof(xs->sense);
+ io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
+ io->data_length = htole32(xs->datalen);
+ io->io_flags = htole16(xs->cmdlen);
+ io->lun[0] = htobe16(link->lun);
+ switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case SCSI_DATA_IN:
+ ccb->ccb_direction = MFII_DATA_IN;
+ io->direction = MPII_SCSIIO_DIR_READ;
+ break;
+ case SCSI_DATA_OUT:
+ ccb->ccb_direction = MFII_DATA_OUT;
+ io->direction = MPII_SCSIIO_DIR_WRITE;
+ break;
+ default:
+ ccb->ccb_direction = MFII_DATA_NONE;
+ io->direction = MPII_SCSIIO_DIR_NONE;
+ break;
+ }
+ bcopy(xs->cmd, io->cdb, xs->cmdlen);
+
+ ctx->virtual_disk_target_id = htole16(link->target);
+ ctx->raid_flags = MFII_RAID_CTX_IO_TYPE_SYSPD;
+ ctx->timeout_value = sc->sc_pd->pd_timeout;
+
+ if (mfii_load_ccb(sc, ccb, ctx + 1,
+ ISSET(xs->flags, SCSI_NOSLEEP)) != 0)
+ return (1);
+
+ ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap->dm_nsegs;
+
+ ccb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
+ ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
+ ccb->ccb_req.dev_handle = sc->sc_pd->pd_links[link->target]->pd_handle;
+
+ return (0);
+}
+
int
mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
int nosleep)