diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2014-09-30 18:02:34 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2014-09-30 18:02:34 +0000 |
commit | b80c0aaef252aa7807089d91ed82f7db25d68bc9 (patch) | |
tree | 604137926505bdbdf6d290e7da22fdec44a1f172 /sys/dev | |
parent | 8bd665503f6e8639d1606239c24cdb65615866b9 (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.c | 263 |
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) |