The diff below adds support for "physical disks" to mfii(4). Just like with mfi(4) you can configure this hardware (or at least some models) to expose disks that have not been assigned to a logical volume to the host. This diff makes those disks accesable from OpenBSD.
I would appreciate some tests, especially from people who have configured some logical volumes on their hardware. Index: mfii.c =================================================================== RCS file: /cvs/src/sys/dev/pci/mfii.c,v retrieving revision 1.17 diff -u -p -r1.17 mfii.c --- mfii.c 13 Jul 2014 23:10:23 -0000 1.17 +++ mfii.c 20 Sep 2014 18:20:30 -0000 @@ -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, struc 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; @@ -1260,6 +1405,120 @@ mfii_scsi_cmd_cdb(struct mfii_softc *sc, ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI; ccb->ccb_req.smid = letoh16(ccb->ccb_smid); + + 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); }