Hi, > most parts are taken from mfi(4), plus fix for rebuilding (bioctl -R).
Do I understand the rebuilding problem correctly? - mfii_makegood() and mfii_makespare() are added before sending the rebuild command to fix the problem - The problem doesn't happen with mfi(4) On Mon, 05 Mar 2018 21:49:16 +0900 (JST) Naoki Fukaumi <[email protected]> wrote: > Hi tech@, > > This patch adds bio(4) support for mfii(4). > # with "mfii(4): use MFII_FUNCTION_PASSTHRU_IO for MFI commands" > > most parts are taken from mfi(4), plus fix for rebuilding (bioctl -R). > > --- sys/dev/ic/mfireg.h > +++ sys/dev/ic/mfireg.h > @@ -139,6 +139,9 @@ > #define MR_DCMD_CONF_GET 0x04010000 > #define MR_DCMD_CFG_ADD 0x04020000 > #define MR_DCMD_CFG_CLEAR 0x04030000 > +#define MR_DCMD_CFG_MAKE_SPARE 0x04040000 > +#define MR_DCMD_CFG_FOREIGN_SCAN 0x04060100 > +#define MR_DCMD_CFG_FOREIGN_CLEAR 0x04060500 > #define MR_DCMD_BBU_GET_STATUS 0x05010000 > #define MR_DCMD_BBU_GET_CAPACITY_INFO 0x05020000 > #define MR_DCMD_BBU_GET_DESIGN_INFO 0x05030000 > @@ -1228,3 +1231,13 @@ struct mfi_pr_properties { > uint32_t exec_freq; > uint32_t clear_freq; > } __packed; > + > +/* We currently don't know the full details of the following struct */ > +struct mfii_foreign_scan_cfg { > + char data[24]; > +}; > + > +struct mfii_foreign_scan_info { > + uint32_t count; /* Number of foreign configs found */ > + struct mfii_foreign_scan_cfg cfgs[8]; > +}; > --- sys/dev/pci/mfii.c > +++ sys/dev/pci/mfii.c > @@ -22,10 +22,14 @@ > #include <sys/systm.h> > #include <sys/malloc.h> > #include <sys/device.h> > +#include <sys/dkio.h> > #include <sys/pool.h> > #include <sys/task.h> > #include <sys/atomic.h> > +#include <sys/sensors.h> > +#include <sys/rwlock.h> > > +#include <dev/biovar.h> > #include <dev/pci/pcidevs.h> > #include <dev/pci/pcivar.h> > > @@ -307,7 +311,35 @@ struct mfii_softc { > struct mfii_pd_softc *sc_pd; > struct scsi_iopool sc_iopool; > > + /* save some useful information for logical drives that is missing > + * in sc_ld_list > + */ > + struct { > + uint32_t ld_present; > + char ld_dev[16]; /* device name sd? */ > + } sc_ld[MFI_MAX_LD]; > + > + /* scsi ioctl from sd device */ > + int (*sc_ioctl)(struct device *, u_long, caddr_t); > + > + uint32_t sc_ld_cnt; > + > + /* bio */ > + struct mfi_conf *sc_cfg; > struct mfi_ctrl_info sc_info; > + struct mfi_ld_list sc_ld_list; > + struct mfi_ld_details *sc_ld_details; /* array to all logical disks */ > + int sc_no_pd; /* used physical disks */ > + int sc_ld_sz; /* sizeof sc_ld_details */ > + > + /* mgmt lock */ > + struct rwlock sc_lock; > + > + /* sensors */ > + struct ksensordev sc_sensordev; > + struct ksensor *sc_bbu; > + struct ksensor *sc_bbu_status; > + struct ksensor *sc_sensors; > }; > > #ifdef MFII_DEBUG > @@ -355,13 +387,15 @@ struct cfdriver mfii_cd = { > > void mfii_scsi_cmd(struct scsi_xfer *); > void mfii_scsi_cmd_done(struct mfii_softc *, struct mfii_ccb *); > +int mfii_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int); > +int mfii_ioctl_cache(struct scsi_link *, u_long, struct dk_cache *); > > struct scsi_adapter mfii_switch = { > mfii_scsi_cmd, > scsi_minphys, > NULL, /* probe */ > NULL, /* unprobe */ > - NULL /* ioctl */ > + mfii_scsi_ioctl > }; > > void mfii_pd_scsi_cmd(struct scsi_xfer *); > @@ -409,9 +443,11 @@ int mfii_load_mfa(struct mfii_softc > *, struct mfii_ccb *, > > int mfii_mfa_poll(struct mfii_softc *, struct mfii_ccb *); > > -int mfii_mgmt(struct mfii_softc *, struct mfii_ccb *, > - u_int32_t, const union mfi_mbox *, > - void *, size_t, int); > +int mfii_mgmt(struct mfii_softc *, uint32_t, uint32_t, > + size_t, void *, const union mfi_mbox *); > +int mfii_do_mgmt(struct mfii_softc *, struct mfii_ccb *, > + uint32_t, uint32_t, size_t, void *, > + const union mfi_mbox *); > void mfii_empty_done(struct mfii_softc *, struct mfii_ccb *); > > int mfii_scsi_cmd_io(struct mfii_softc *, > @@ -445,6 +481,42 @@ void mfii_aen_pd_remove(struct > mfii_softc *, > void mfii_aen_pd_state_change(struct mfii_softc *, > const struct mfi_evtarg_pd_state *); > > +#if NBIO > 0 > +int mfii_ioctl(struct device *, u_long, caddr_t); > +int mfii_bio_getitall(struct mfii_softc *); > +int mfii_ioctl_inq(struct mfii_softc *, struct bioc_inq *); > +int mfii_ioctl_vol(struct mfii_softc *, struct bioc_vol *); > +int mfii_ioctl_disk(struct mfii_softc *, struct bioc_disk *); > +int mfii_ioctl_alarm(struct mfii_softc *, struct bioc_alarm *); > +int mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *); > +int mfii_ioctl_setstate(struct mfii_softc *, > + struct bioc_setstate *); > +int mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *); > +int mfii_bio_hs(struct mfii_softc *, int, int, void *); > + > +#ifndef SMALL_KERNEL > +static const char *mfi_bbu_indicators[] = { > + "pack missing", > + "voltage low", > + "temp high", > + "charge active", > + "discharge active", > + "learn cycle req'd", > + "learn cycle active", > + "learn cycle failed", > + "learn cycle timeout", > + "I2C errors", > + "replace pack", > + "low capacity", > + "periodic learn req'd" > +}; > + > +int mfii_create_sensors(struct mfii_softc *); > +void mfii_refresh_sensors(void *); > +int mfii_bbu(struct mfii_softc *); > +#endif /* SMALL_KERNEL */ > +#endif /* NBIO > 0 */ > + > /* > * mfii boards support asynchronous (and non-polled) completion of > * dcmds by proxying them through a passthru mpii command that points > @@ -575,7 +647,7 @@ mfii_attach(struct device *parent, struct device *self, > void *aux) > pci_intr_handle_t ih; > struct scsibus_attach_args saa; > u_int32_t status, scpad2, scpad3; > - int chain_frame_sz, nsge_in_io, nsge_in_chain; > + int chain_frame_sz, nsge_in_io, nsge_in_chain, i; > > /* init sc */ > sc->sc_iop = mfii_find_iop(aux); > @@ -586,6 +658,8 @@ mfii_attach(struct device *parent, struct device *self, > void *aux) > mtx_init(&sc->sc_reply_postq_mtx, IPL_BIO); > scsi_iopool_init(&sc->sc_iopool, sc, mfii_get_ccb, mfii_put_ccb); > > + rw_init(&sc->sc_lock, "mfii_lock"); > + > sc->sc_aen_ccb = NULL; > task_set(&sc->sc_aen_task, mfii_aen, sc); > > @@ -716,6 +790,10 @@ mfii_attach(struct device *parent, struct device *self, > void *aux) > if (sc->sc_ih == NULL) > goto free_sgl; > > + sc->sc_ld_cnt = sc->sc_info.mci_lds_present; > + for (i = 0; i < sc->sc_ld_cnt; i++) > + sc->sc_ld[i].ld_present = 1; > + > sc->sc_link.openings = sc->sc_max_cmds; > sc->sc_link.adapter_softc = sc; > sc->sc_link.adapter = &mfii_switch; > @@ -726,7 +804,8 @@ mfii_attach(struct device *parent, struct device *self, > void *aux) > memset(&saa, 0, sizeof(saa)); > saa.saa_sc_link = &sc->sc_link; > > - config_found(&sc->sc_dev, &saa, scsiprint); > + sc->sc_scsibus = (struct scsibus_softc *) > + config_found(&sc->sc_dev, &saa, scsiprint); > > mfii_syspd(sc); > > @@ -739,6 +818,18 @@ mfii_attach(struct device *parent, struct device *self, > void *aux) > mfii_write(sc, MFI_OSTS, 0xffffffff); > mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID); > > +#if NBIO > 0 > + if (bio_register(&sc->sc_dev, mfii_ioctl) != 0) > + panic("%s: controller registration failed", DEVNAME(sc)); > + else > + sc->sc_ioctl = mfii_ioctl; > + > +#ifndef SMALL_KERNEL > + if (mfii_create_sensors(sc) != 0) > + printf("%s: unable to create sensors\n", DEVNAME(sc)); > +#endif > +#endif /* NBIO > 0 */ > + > return; > intr_disestablish: > pci_intr_disestablish(sc->sc_pc, sc->sc_ih); > @@ -777,17 +868,14 @@ mfii_dev_handles_update(struct mfii_softc *sc) > { > struct mfii_ld_map *lm; > uint16_t *dev_handles = NULL; > - struct mfii_ccb *ccb; > int i; > int rv = 0; > > lm = malloc(sizeof(*lm), M_TEMP, M_WAITOK|M_ZERO); > - 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); > + rv = mfii_mgmt(sc, MR_DCMD_LD_MAP_GET_INFO, MFII_DATA_IN, sizeof(*lm), > + lm, NULL); > > - scsi_io_put(&sc->sc_iopool, ccb); > if (rv != 0) { > rv = EIO; > goto free_lm; > @@ -861,6 +949,23 @@ mfii_detach(struct device *self, int flags) > if (sc->sc_ih == NULL) > return (0); > > +#ifndef SMALL_KERNEL > + if (sc->sc_sensors) { > + sensordev_deinstall(&sc->sc_sensordev); > + free(sc->sc_sensors, M_DEVBUF, > + sc->sc_ld_cnt * sizeof(struct ksensor)); > + } > + > + if (sc->sc_bbu) { > + free(sc->sc_bbu, M_DEVBUF, 4 * sizeof(*sc->sc_bbu)); > + } > + > + if (sc->sc_bbu_status) { > + free(sc->sc_bbu_status, M_DEVBUF, > + sizeof(*sc->sc_bbu_status) * sizeof(mfi_bbu_indicators)); > + } > +#endif /* SMALL_KERNEL */ > + > mfii_aen_unregister(sc); > pci_intr_disestablish(sc->sc_pc, sc->sc_ih); > mfii_dmamem_free(sc, sc->sc_sgl); > @@ -977,9 +1082,10 @@ mfii_aen_register(struct mfii_softc *sc) > } > > memset(&mel, 0, sizeof(mel)); > + mfii_scrub_ccb(ccb); > > - rv = mfii_mgmt(sc, ccb, MR_DCMD_CTRL_EVENT_GET_INFO, NULL, > - &mel, sizeof(mel), SCSI_DATA_IN|SCSI_NOSLEEP); > + rv = mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_EVENT_GET_INFO, MFII_DATA_IN, > + sizeof(mel), &mel, NULL); > if (rv != 0) { > scsi_io_put(&sc->sc_iopool, ccb); > printf("%s: unable to get event info\n", DEVNAME(sc)); > @@ -1222,13 +1328,10 @@ mfii_transition_firmware(struct mfii_softc *sc) > int > mfii_get_info(struct mfii_softc *sc) > { > - struct mfii_ccb *ccb; > int rv; > > - ccb = scsi_io_get(&sc->sc_iopool, 0); > - rv = mfii_mgmt(sc, ccb, MR_DCMD_CTRL_GET_INFO, NULL, > - &sc->sc_info, sizeof(sc->sc_info), SCSI_DATA_IN|SCSI_NOSLEEP); > - scsi_io_put(&sc->sc_iopool, ccb); > + rv = mfii_mgmt(sc, MR_DCMD_CTRL_GET_INFO, MFII_DATA_IN, > + sizeof(sc->sc_info), &sc->sc_info, NULL); > > if (rv != 0) > return (rv); > @@ -1511,39 +1614,53 @@ mfii_exec_done(struct mfii_softc *sc, struct mfii_ccb > *ccb) > } > > int > -mfii_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, > - u_int32_t opc, const union mfi_mbox *mbox, void *buf, size_t len, > - int flags) > +mfii_mgmt(struct mfii_softc *sc, uint32_t opc, uint32_t dir, size_t len, > + void *buf, const union mfi_mbox *mbox) > +{ > + struct mfii_ccb *ccb; > + int rv; > + > + ccb = scsi_io_get(&sc->sc_iopool, 0); > + mfii_scrub_ccb(ccb); > + rv = mfii_do_mgmt(sc, ccb, opc, dir, len, buf, mbox); > + scsi_io_put(&sc->sc_iopool, ccb); > + > + return (rv); > +} > + > +int > +mfii_do_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, uint32_t opc, > + uint32_t dir, size_t len, void *buf, const union mfi_mbox *mbox) > { > struct mpii_msg_scsi_io *io = ccb->ccb_request; > struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1); > struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1); > struct mfi_dcmd_frame *dcmd = ccb->ccb_mfi; > struct mfi_frame_header *hdr = &dcmd->mdf_header; > - u_int8_t *dma_buf; > + uint8_t *dma_buf; > int rv = 0; > > dma_buf = dma_alloc(len, PR_WAITOK); > if (dma_buf == NULL) > return (ENOMEM); > > - mfii_scrub_ccb(ccb); > ccb->ccb_data = dma_buf; > ccb->ccb_len = len; > - switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { > - case SCSI_DATA_IN: > - ccb->ccb_direction = MFII_DATA_IN; > + ccb->ccb_direction = dir; > + switch (dir) { > + case MFII_DATA_IN: > hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ); > break; > - case SCSI_DATA_OUT: > - ccb->ccb_direction = MFII_DATA_OUT; > + case MFII_DATA_OUT: > hdr->mfh_flags = htole16(MFI_FRAME_DIR_WRITE); > memcpy(dma_buf, buf, len); > break; > + case MFII_DATA_NONE: > + hdr->mfh_flags = htole16(MFI_FRAME_DIR_NONE); > + break; > } > > - if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl, > - ISSET(flags, SCSI_NOSLEEP)) != 0) { > + if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl, 1/*cold*/) != 0) { > rv = ENOMEM; > goto done; > } > @@ -1569,7 +1686,7 @@ mfii_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, > ccb->ccb_req.scsi.flags = MFII_REQ_TYPE_SCSI; > ccb->ccb_req.scsi.smid = letoh16(ccb->ccb_smid); > > - if (ISSET(flags, SCSI_NOSLEEP)) { > + if (1/*cold*/) { > /* busy-loop polling with done handler */ > ccb->ccb_cookie = NULL; > ccb->ccb_done = mfii_empty_done; > @@ -1583,8 +1700,7 @@ mfii_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, > > if (ccb->ccb_len > 0) { > bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, > - 0, ccb->ccb_dmamap->dm_mapsize, > - (ccb->ccb_direction == MFII_DATA_IN) ? > + 0, ccb->ccb_dmamap->dm_mapsize, (dir == MFII_DATA_IN) ? > BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); > > bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); > @@ -1592,7 +1708,7 @@ mfii_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, > > rv = hdr->mfh_cmd_status == MFI_STAT_OK ? 0 : 1; > > - if (rv == 0 && ccb->ccb_direction == MFII_DATA_IN) > + if (rv == 0 && dir == MFII_DATA_IN) > memcpy(buf, dma_buf, len); > > done: > @@ -1930,6 +2046,109 @@ mfii_scsi_cmd_done(struct mfii_softc *sc, struct > mfii_ccb *ccb) > } > > int > +mfii_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag) > +{ > + struct mfii_softc *sc = (struct mfii_softc *)link->adapter_softc; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_scsi_ioctl\n", DEVNAME(sc)); > + > + switch (cmd) { > + case DIOCGCACHE: > + case DIOCSCACHE: > + return (mfii_ioctl_cache(link, cmd, (struct dk_cache *)addr)); > + break; > + > + default: > + if (sc->sc_ioctl) > + return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); > + break; > + } > + > + return (ENOTTY); > +} > + > +int > +mfii_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc) > +{ > + struct mfii_softc *sc = (struct mfii_softc *)link->adapter_softc; > + int rv, wrenable, rdenable; > + struct mfi_ld_prop ldp; > + union mfi_mbox mbox; > + > + if (mfii_get_info(sc)) { > + rv = EIO; > + goto done; > + } > + > + if (!sc->sc_ld[link->target].ld_present) { > + rv = EIO; > + goto done; > + } > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.b[0] = link->target; > + rv = mfii_mgmt(sc, MR_DCMD_LD_GET_PROPERTIES, MFII_DATA_IN, sizeof(ldp), > + &ldp, &mbox); > + if (rv != 0) > + goto done; > + > + if (sc->sc_info.mci_memory_size > 0) { > + wrenable = ISSET(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_WRITE_CACHE)? 1 : 0; > + rdenable = ISSET(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_READ_CACHE)? 1 : 0; > + } else { > + wrenable = ISSET(ldp.mlp_diskcache_policy, > + MR_LD_DISK_CACHE_ENABLE)? 1 : 0; > + rdenable = 0; > + } > + > + if (cmd == DIOCGCACHE) { > + dc->wrcache = wrenable; > + dc->rdcache = rdenable; > + goto done; > + } /* else DIOCSCACHE */ > + > + if (((dc->wrcache) ? 1 : 0) == wrenable && > + ((dc->rdcache) ? 1 : 0) == rdenable) > + goto done; > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.b[0] = ldp.mlp_ld.mld_target; > + mbox.b[1] = ldp.mlp_ld.mld_res; > + mbox.s[1] = ldp.mlp_ld.mld_seq; > + > + if (sc->sc_info.mci_memory_size > 0) { > + if (dc->rdcache) > + SET(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_READ_CACHE); > + else > + CLR(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_READ_CACHE); > + if (dc->wrcache) > + SET(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_WRITE_CACHE); > + else > + CLR(ldp.mlp_cur_cache_policy, > + MR_LD_CACHE_ALLOW_WRITE_CACHE); > + } else { > + if (dc->rdcache) { > + rv = EOPNOTSUPP; > + goto done; > + } > + if (dc->wrcache) > + ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_ENABLE; > + else > + ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_DISABLE; > + } > + > + rv = mfii_mgmt(sc, MR_DCMD_LD_SET_PROPERTIES, MFII_DATA_OUT, > + sizeof(ldp), &ldp, &mbox); > +done: > + return (rv); > +} > + > +int > mfii_scsi_cmd_io(struct mfii_softc *sc, struct scsi_xfer *xs) > { > struct scsi_link *link = xs->sc_link; > @@ -2078,7 +2297,6 @@ int > mfii_pd_scsi_probe(struct scsi_link *link) > { > struct mfii_softc *sc = link->adapter_softc; > - struct mfii_ccb *ccb; > struct mfi_pd_details mpd; > union mfi_mbox mbox; > int rv; > @@ -2089,10 +2307,8 @@ mfii_pd_scsi_probe(struct scsi_link *link) > memset(&mbox, 0, sizeof(mbox)); > mbox.s[0] = htole16(link->target); > > - ccb = scsi_io_get(&sc->sc_iopool, 0); > - rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_INFO, &mbox, &mpd, sizeof(mpd), > - SCSI_DATA_IN|SCSI_NOSLEEP); > - scsi_io_put(&sc->sc_iopool, ccb); > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, sizeof(mpd), &mpd, > + &mbox); > if (rv != 0) > return (EIO); > > @@ -2427,3 +2643,1162 @@ destroy: > return (1); > } > > +#if NBIO > 0 > +int > +mfii_ioctl(struct device *dev, u_long cmd, caddr_t addr) > +{ > + struct mfii_softc *sc = (struct mfii_softc *)dev; > + int error = 0; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl ", DEVNAME(sc)); > + > + rw_enter_write(&sc->sc_lock); > + > + switch (cmd) { > + case BIOCINQ: > + DNPRINTF(MFII_D_IOCTL, "inq\n"); > + error = mfii_ioctl_inq(sc, (struct bioc_inq *)addr); > + break; > + > + case BIOCVOL: > + DNPRINTF(MFII_D_IOCTL, "vol\n"); > + error = mfii_ioctl_vol(sc, (struct bioc_vol *)addr); > + break; > + > + case BIOCDISK: > + DNPRINTF(MFII_D_IOCTL, "disk\n"); > + error = mfii_ioctl_disk(sc, (struct bioc_disk *)addr); > + break; > + > + case BIOCALARM: > + DNPRINTF(MFII_D_IOCTL, "alarm\n"); > + error = mfii_ioctl_alarm(sc, (struct bioc_alarm *)addr); > + break; > + > + case BIOCBLINK: > + DNPRINTF(MFII_D_IOCTL, "blink\n"); > + error = mfii_ioctl_blink(sc, (struct bioc_blink *)addr); > + break; > + > + case BIOCSETSTATE: > + DNPRINTF(MFII_D_IOCTL, "setstate\n"); > + error = mfii_ioctl_setstate(sc, (struct bioc_setstate *)addr); > + break; > + > + case BIOCPATROL: > + DNPRINTF(MFII_D_IOCTL, "patrol\n"); > + error = mfii_ioctl_patrol(sc, (struct bioc_patrol *)addr); > + break; > + > + default: > + DNPRINTF(MFII_D_IOCTL, " invalid ioctl\n"); > + error = EINVAL; > + } > + > + rw_exit_write(&sc->sc_lock); > + > + return (error); > +} > + > +int > +mfii_bio_getitall(struct mfii_softc *sc) > +{ > + int i, d, rv = EINVAL; > + size_t size; > + union mfi_mbox mbox; > + struct mfi_conf *cfg = NULL; > + struct mfi_ld_details *ld_det = NULL; > + > + /* get info */ > + if (mfii_get_info(sc)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_get_info failed\n", > + DEVNAME(sc)); > + goto done; > + } > + > + /* send single element command to retrieve size for full structure */ > + cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO); > + if (cfg == NULL) > + goto done; > + if (mfii_mgmt(sc, MR_DCMD_CONF_GET, MFII_DATA_IN, sizeof *cfg, cfg, > + NULL)) { > + free(cfg, M_DEVBUF, sizeof *cfg); > + goto done; > + } > + > + size = cfg->mfc_size; > + free(cfg, M_DEVBUF, sizeof *cfg); > + > + /* memory for read config */ > + cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); > + if (cfg == NULL) > + goto done; > + if (mfii_mgmt(sc, MR_DCMD_CONF_GET, MFII_DATA_IN, size, cfg, NULL)) { > + free(cfg, M_DEVBUF, size); > + goto done; > + } > + > + /* replace current pointer with new one */ > + if (sc->sc_cfg) > + free(sc->sc_cfg, M_DEVBUF, 0); > + sc->sc_cfg = cfg; > + > + /* get all ld info */ > + if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, MFII_DATA_IN, > + sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL)) > + goto done; > + > + /* get memory for all ld structures */ > + size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details); > + if (sc->sc_ld_sz != size) { > + if (sc->sc_ld_details) > + free(sc->sc_ld_details, M_DEVBUF, 0); > + > + ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); > + if (ld_det == NULL) > + goto done; > + sc->sc_ld_sz = size; > + sc->sc_ld_details = ld_det; > + } > + > + /* find used physical disks */ > + size = sizeof(struct mfi_ld_details); > + for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) { > + memset(&mbox, 0, sizeof(mbox)); > + mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target; > + if (mfii_mgmt(sc, MR_DCMD_LD_GET_INFO, MFII_DATA_IN, size, > + &sc->sc_ld_details[i], &mbox)) > + goto done; > + > + d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span * > + sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth; > + } > + sc->sc_no_pd = d; > + > + rv = 0; > +done: > + return (rv); > +} > + > +int > +mfii_ioctl_inq(struct mfii_softc *sc, struct bioc_inq *bi) > +{ > + int rv = EINVAL; > + struct mfi_conf *cfg = NULL; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_inq\n", DEVNAME(sc)); > + > + if (mfii_bio_getitall(sc)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n", > + DEVNAME(sc)); > + goto done; > + } > + > + /* count unused disks as volumes */ > + if (sc->sc_cfg == NULL) > + goto done; > + cfg = sc->sc_cfg; > + > + bi->bi_nodisk = sc->sc_info.mci_pd_disks_present; > + bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs; > +#if notyet > + bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs + > + (bi->bi_nodisk - sc->sc_no_pd); > +#endif > + /* tell bio who we are */ > + strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); > + > + rv = 0; > +done: > + return (rv); > +} > + > +int > +mfii_ioctl_vol(struct mfii_softc *sc, struct bioc_vol *bv) > +{ > + int i, per, rv = EINVAL; > + struct scsi_link *link; > + struct device *dev; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_vol %#x\n", > + DEVNAME(sc), bv->bv_volid); > + > + /* we really could skip and expect that inq took care of it */ > + if (mfii_bio_getitall(sc)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n", > + DEVNAME(sc)); > + goto done; > + } > + > + if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) { > + /* go do hotspares & unused disks */ > + rv = mfii_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv); > + goto done; > + } > + > + i = bv->bv_volid; > + link = scsi_get_link(sc->sc_scsibus, i, 0); > + if (link != NULL && link->device_softc != NULL) { > + dev = link->device_softc; > + strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev)); > + } > + > + switch(sc->sc_ld_list.mll_list[i].mll_state) { > + case MFI_LD_OFFLINE: > + bv->bv_status = BIOC_SVOFFLINE; > + break; > + > + case MFI_LD_PART_DEGRADED: > + case MFI_LD_DEGRADED: > + bv->bv_status = BIOC_SVDEGRADED; > + break; > + > + case MFI_LD_ONLINE: > + bv->bv_status = BIOC_SVONLINE; > + break; > + > + default: > + bv->bv_status = BIOC_SVINVALID; > + DNPRINTF(MFII_D_IOCTL, "%s: invalid logical disk state %#x\n", > + DEVNAME(sc), > + sc->sc_ld_list.mll_list[i].mll_state); > + } > + > + /* additional status can modify MFI status */ > + switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) { > + case MFI_LD_PROG_CC: > + case MFI_LD_PROG_BGI: > + bv->bv_status = BIOC_SVSCRUB; > + per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress; > + bv->bv_percent = (per * 100) / 0xffff; > + bv->bv_seconds = > + sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds; > + break; > + > + case MFI_LD_PROG_FGI: > + case MFI_LD_PROG_RECONSTRUCT: > + /* nothing yet */ > + break; > + } > + > + if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01) > + bv->bv_cache = BIOC_CVWRITEBACK; > + else > + bv->bv_cache = BIOC_CVWRITETHROUGH; > + > + /* > + * The RAID levels are determined per the SNIA DDF spec, this is only > + * a subset that is valid for the MFI controller. > + */ > + bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid; > + if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_sec_raid == > + MFI_DDF_SRL_SPANNED) > + bv->bv_level *= 10; > + > + bv->bv_nodisk = > sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span * > + sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth; > + > + bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */ > + > + rv = 0; > +done: > + return (rv); > +} > + > +int > +mfii_ioctl_disk(struct mfii_softc *sc, struct bioc_disk *bd) > +{ > + struct mfi_conf *cfg; > + struct mfi_array *ar; > + struct mfi_ld_cfg *ld; > + struct mfi_pd_details *pd; > + struct mfi_pd_list *pl; > + struct mfi_pd_progress *mfp; > + struct mfi_progress *mp; > + struct scsi_inquiry_data *inqbuf; > + char vend[8+16+4+1], *vendp; > + int i, rv = EINVAL; > + int arr, vol, disk, span; > + union mfi_mbox mbox; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_disk %#x\n", > + DEVNAME(sc), bd->bd_diskid); > + > + /* we really could skip and expect that inq took care of it */ > + if (mfii_bio_getitall(sc)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n", > + DEVNAME(sc)); > + return (rv); > + } > + cfg = sc->sc_cfg; > + > + pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK); > + pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK); > + > + ar = cfg->mfc_array; > + vol = bd->bd_volid; > + if (vol >= cfg->mfc_no_ld) { > + /* do hotspares */ > + rv = mfii_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd); > + goto freeme; > + } > + > + /* calculate offset to ld structure */ > + ld = (struct mfi_ld_cfg *)( > + ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) + > + cfg->mfc_array_size * cfg->mfc_no_array); > + > + /* use span 0 only when raid group is not spanned */ > + if (ld[vol].mlc_parm.mpa_span_depth > 1) > + span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span; > + else > + span = 0; > + arr = ld[vol].mlc_span[span].mls_index; > + > + /* offset disk into pd list */ > + disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span; > + > + if (ar[arr].pd[disk].mar_pd.mfp_id == 0xffffU) { > + /* disk is missing but succeed command */ > + bd->bd_status = BIOC_SDFAILED; > + rv = 0; > + > + /* try to find an unused disk for the target to rebuild */ > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, MFII_DATA_IN, > + sizeof *pl, pl, NULL)) > + goto freeme; > + > + for (i = 0; i < pl->mpl_no_pd; i++) { > + if (pl->mpl_address[i].mpa_scsi_type != 0) > + continue; > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = pl->mpl_address[i].mpa_pd_id; > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, > + sizeof *pd, pd, &mbox)) > + continue; > + > + if (pd->mpd_fw_state == MFI_PD_UNCONFIG_GOOD || > + pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD) > + break; > + } > + > + if (i == pl->mpl_no_pd) > + goto freeme; > + } else { > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id; > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, > + sizeof *pd, pd, &mbox)) { > + bd->bd_status = BIOC_SDINVALID; > + goto freeme; > + } > + } > + > + /* get the remaining fields */ > + bd->bd_channel = pd->mpd_enc_idx; > + bd->bd_target = pd->mpd_enc_slot; > + > + /* get status */ > + switch (pd->mpd_fw_state){ > + case MFI_PD_UNCONFIG_GOOD: > + case MFI_PD_UNCONFIG_BAD: > + bd->bd_status = BIOC_SDUNUSED; > + break; > + > + case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */ > + bd->bd_status = BIOC_SDHOTSPARE; > + break; > + > + case MFI_PD_OFFLINE: > + bd->bd_status = BIOC_SDOFFLINE; > + break; > + > + case MFI_PD_FAILED: > + bd->bd_status = BIOC_SDFAILED; > + break; > + > + case MFI_PD_REBUILD: > + bd->bd_status = BIOC_SDREBUILD; > + break; > + > + case MFI_PD_ONLINE: > + bd->bd_status = BIOC_SDONLINE; > + break; > + > + case MFI_PD_COPYBACK: > + case MFI_PD_SYSTEM: > + default: > + bd->bd_status = BIOC_SDINVALID; > + break; > + } > + > + bd->bd_size = pd->mpd_size * 512; /* bytes per block */ > + > + inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data; > + vendp = inqbuf->vendor; > + memcpy(vend, vendp, sizeof vend - 1); > + vend[sizeof vend - 1] = '\0'; > + strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor)); > + > + /* XXX find a way to retrieve serial nr from drive */ > + /* XXX find a way to get bd_procdev */ > + > + mfp = &pd->mpd_progress; > + if (mfp->mfp_in_prog & MFI_PD_PROG_PR) { > + mp = &mfp->mfp_patrol_read; > + bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff; > + bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds; > + } > + > + rv = 0; > +freeme: > + free(pd, M_DEVBUF, sizeof *pd); > + free(pl, M_DEVBUF, sizeof *pl); > + > + return (rv); > +} > + > +int > +mfii_ioctl_alarm(struct mfii_softc *sc, struct bioc_alarm *ba) > +{ > + uint32_t opc, dir = MFII_DATA_NONE; > + int rv = 0; > + int8_t ret; > + > + switch(ba->ba_opcode) { > + case BIOC_SADISABLE: > + opc = MR_DCMD_SPEAKER_DISABLE; > + break; > + > + case BIOC_SAENABLE: > + opc = MR_DCMD_SPEAKER_ENABLE; > + break; > + > + case BIOC_SASILENCE: > + opc = MR_DCMD_SPEAKER_SILENCE; > + break; > + > + case BIOC_GASTATUS: > + opc = MR_DCMD_SPEAKER_GET; > + dir = MFII_DATA_IN; > + break; > + > + case BIOC_SATEST: > + opc = MR_DCMD_SPEAKER_TEST; > + break; > + > + default: > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_alarm biocalarm invalid " > + "opcode %x\n", DEVNAME(sc), ba->ba_opcode); > + return (EINVAL); > + } > + > + if (mfii_mgmt(sc, opc, dir, sizeof(ret), &ret, NULL)) > + rv = EINVAL; > + else > + if (ba->ba_opcode == BIOC_GASTATUS) > + ba->ba_status = ret; > + else > + ba->ba_status = 0; > + > + return (rv); > +} > + > +int > +mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb) > +{ > + int i, found, rv = EINVAL; > + union mfi_mbox mbox; > + uint32_t cmd; > + struct mfi_pd_list *pd; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink %x\n", DEVNAME(sc), > + bb->bb_status); > + > + /* channel 0 means not in an enclosure so can't be blinked */ > + if (bb->bb_channel == 0) > + return (EINVAL); > + > + pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK); > + > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, MFII_DATA_IN, > + sizeof(*pd), pd, NULL)) > + goto done; > + > + for (i = 0, found = 0; i < pd->mpl_no_pd; i++) > + if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index && > + bb->bb_target == pd->mpl_address[i].mpa_enc_slot) { > + found = 1; > + break; > + } > + > + if (!found) > + goto done; > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = pd->mpl_address[i].mpa_pd_id; > + > + switch (bb->bb_status) { > + case BIOC_SBUNBLINK: > + cmd = MR_DCMD_PD_UNBLINK; > + break; > + > + case BIOC_SBBLINK: > + cmd = MR_DCMD_PD_BLINK; > + break; > + > + case BIOC_SBALARM: > + default: > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink biocblink invalid " > + "opcode %x\n", DEVNAME(sc), bb->bb_status); > + goto done; > + } > + > + > + if (mfii_mgmt(sc, cmd, MFII_DATA_NONE, 0, NULL, &mbox)) > + goto done; > + > + rv = 0; > +done: > + free(pd, M_DEVBUF, sizeof *pd); > + return (rv); > +} > + > +static int > +mfii_makegood(struct mfii_softc *sc, uint16_t pd_id) > +{ > + struct mfii_foreign_scan_info *fsi; > + struct mfi_pd_details *pd; > + union mfi_mbox mbox; > + int rv; > + > + fsi = malloc(sizeof *fsi, M_DEVBUF, M_WAITOK); > + pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK); > + > + memset(&mbox, 0, sizeof mbox); > + mbox.s[0] = pd_id; > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, sizeof(*pd), pd, > + &mbox); > + if (rv != 0) > + goto done; > + > + if (pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD) { > + mbox.s[0] = pd_id; > + mbox.s[1] = pd->mpd_pd.mfp_seq; > + mbox.b[4] = MFI_PD_UNCONFIG_GOOD; > + rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, MFII_DATA_NONE, 0, > + NULL, &mbox); > + if (rv != 0) > + goto done; > + } > + > + memset(&mbox, 0, sizeof mbox); > + mbox.s[0] = pd_id; > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, sizeof(*pd), pd, > + &mbox); > + if (rv != 0) > + goto done; > + > + if (pd->mpd_ddf_state & MFI_DDF_FOREIGN) { > + rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_SCAN, MFII_DATA_IN, > + sizeof(*fsi), fsi, NULL); > + if (rv != 0) > + goto done; > + > + if (fsi->count > 0) { > + rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_CLEAR, > + MFII_DATA_NONE, 0, NULL, NULL); > + if (rv != 0) > + goto done; > + } > + } > + > + memset(&mbox, 0, sizeof mbox); > + mbox.s[0] = pd_id; > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, sizeof *pd, pd, > + &mbox); > + if (rv != 0) > + goto done; > + > + if (pd->mpd_fw_state != MFI_PD_UNCONFIG_GOOD || > + pd->mpd_ddf_state & MFI_DDF_FOREIGN) > + rv = ENXIO; > + > +done: > + free(fsi, M_DEVBUF, sizeof *fsi); > + free(pd, M_DEVBUF, sizeof *pd); > + > + return (rv); > +} > + > +static int > +mfii_makespare(struct mfii_softc *sc, uint16_t pd_id) > +{ > + struct mfi_hotspare *hs; > + struct mfi_pd_details *pd; > + union mfi_mbox mbox; > + size_t size; > + int rv = EINVAL; > + > + /* we really could skip and expect that inq took care of it */ > + if (mfii_bio_getitall(sc)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n", > + DEVNAME(sc)); > + return (rv); > + } > + size = sizeof *hs + sizeof(uint16_t) * sc->sc_cfg->mfc_no_array; > + > + hs = malloc(size, M_DEVBUF, M_WAITOK); > + pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK); > + > + memset(&mbox, 0, sizeof mbox); > + mbox.s[0] = pd_id; > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, sizeof *pd, pd, > + &mbox); > + if (rv != 0) > + goto done; > + > + memset(hs, 0, size); > + hs->mhs_pd.mfp_id = pd->mpd_pd.mfp_id; > + hs->mhs_pd.mfp_seq = pd->mpd_pd.mfp_seq; > + rv = mfii_mgmt(sc, MR_DCMD_CFG_MAKE_SPARE, MFII_DATA_OUT, size, hs, > + NULL); > + > +done: > + free(hs, M_DEVBUF, size); > + free(pd, M_DEVBUF, sizeof *pd); > + > + return (rv); > +} > + > +int > +mfii_ioctl_setstate(struct mfii_softc *sc, struct bioc_setstate *bs) > +{ > + struct mfi_pd_details *pd; > + struct mfi_pd_list *pl; > + int i, found, rv = EINVAL; > + union mfi_mbox mbox; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate %x\n", DEVNAME(sc), > + bs->bs_status); > + > + pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK); > + pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK); > + > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, MFII_DATA_IN, > + sizeof *pl, pl, NULL)) > + goto done; > + > + for (i = 0, found = 0; i < pl->mpl_no_pd; i++) > + if (bs->bs_channel == pl->mpl_address[i].mpa_enc_index && > + bs->bs_target == pl->mpl_address[i].mpa_enc_slot) { > + found = 1; > + break; > + } > + > + if (!found) > + goto done; > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = pl->mpl_address[i].mpa_pd_id; > + > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, > + sizeof *pd, pd, &mbox)) > + goto done; > + > + mbox.s[0] = pl->mpl_address[i].mpa_pd_id; > + mbox.s[1] = pd->mpd_pd.mfp_seq; > + > + switch (bs->bs_status) { > + case BIOC_SSONLINE: > + mbox.b[4] = MFI_PD_ONLINE; > + break; > + > + case BIOC_SSOFFLINE: > + mbox.b[4] = MFI_PD_OFFLINE; > + break; > + > + case BIOC_SSHOTSPARE: > + mbox.b[4] = MFI_PD_HOTSPARE; > + break; > + > + case BIOC_SSREBUILD: > + if (pd->mpd_fw_state != MFI_PD_OFFLINE) { > + if ((rv = mfii_makegood(sc, > + pl->mpl_address[i].mpa_pd_id))) > + goto done; > + > + if ((rv = mfii_makespare(sc, > + pl->mpl_address[i].mpa_pd_id))) > + goto done; > + > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = pl->mpl_address[i].mpa_pd_id; > + rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, > + sizeof *pd, pd, &mbox); > + if (rv != 0) > + goto done; > + > + /* rebuilding might be started by mfii_makespare() */ > + if (pd->mpd_fw_state == MFI_PD_REBUILD) { > + rv = 0; > + goto done; > + } > + > + mbox.s[0] = pl->mpl_address[i].mpa_pd_id; > + mbox.s[1] = pd->mpd_pd.mfp_seq; > + } > + mbox.b[4] = MFI_PD_REBUILD; > + break; > + > + default: > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate invalid " > + "opcode %x\n", DEVNAME(sc), bs->bs_status); > + goto done; > + } > + > + > + rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, MFII_DATA_NONE, 0, NULL, > + &mbox); > +done: > + free(pd, M_DEVBUF, sizeof *pd); > + free(pl, M_DEVBUF, sizeof *pl); > + return (rv); > +} > + > +int > +mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *bp) > +{ > + uint32_t opc, dir = MFII_DATA_NONE; > + int rv = 0; > + struct mfi_pr_properties prop; > + struct mfi_pr_status status; > + uint32_t time, exec_freq; > + > + switch (bp->bp_opcode) { > + case BIOC_SPSTOP: > + case BIOC_SPSTART: > + if (bp->bp_opcode == BIOC_SPSTART) > + opc = MR_DCMD_PR_START; > + else > + opc = MR_DCMD_PR_STOP; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, 0, NULL, NULL)) > + return (EINVAL); > + break; > + > + case BIOC_SPMANUAL: > + case BIOC_SPDISABLE: > + case BIOC_SPAUTO: > + /* Get device's time. */ > + opc = MR_DCMD_TIME_SECS_GET; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, sizeof(time), &time, NULL)) > + return (EINVAL); > + > + opc = MR_DCMD_PR_GET_PROPERTIES; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL)) > + return (EINVAL); > + > + switch (bp->bp_opcode) { > + case BIOC_SPMANUAL: > + prop.op_mode = MFI_PR_OPMODE_MANUAL; > + break; > + case BIOC_SPDISABLE: > + prop.op_mode = MFI_PR_OPMODE_DISABLED; > + break; > + case BIOC_SPAUTO: > + if (bp->bp_autoival != 0) { > + if (bp->bp_autoival == -1) > + /* continuously */ > + exec_freq = 0xffffffffU; > + else if (bp->bp_autoival > 0) > + exec_freq = bp->bp_autoival; > + else > + return (EINVAL); > + prop.exec_freq = exec_freq; > + } > + if (bp->bp_autonext != 0) { > + if (bp->bp_autonext < 0) > + return (EINVAL); > + else > + prop.next_exec = time + bp->bp_autonext; > + } > + prop.op_mode = MFI_PR_OPMODE_AUTO; > + break; > + } > + > + opc = MR_DCMD_PR_SET_PROPERTIES; > + dir = MFII_DATA_OUT; > + if (mfii_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL)) > + return (EINVAL); > + > + break; > + > + case BIOC_GPSTATUS: > + opc = MR_DCMD_PR_GET_PROPERTIES; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL)) > + return (EINVAL); > + > + opc = MR_DCMD_PR_GET_STATUS; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, sizeof(status), &status, NULL)) > + return (EINVAL); > + > + /* Get device's time. */ > + opc = MR_DCMD_TIME_SECS_GET; > + dir = MFII_DATA_IN; > + if (mfii_mgmt(sc, opc, dir, sizeof(time), &time, NULL)) > + return (EINVAL); > + > + switch (prop.op_mode) { > + case MFI_PR_OPMODE_AUTO: > + bp->bp_mode = BIOC_SPMAUTO; > + bp->bp_autoival = prop.exec_freq; > + bp->bp_autonext = prop.next_exec; > + bp->bp_autonow = time; > + break; > + case MFI_PR_OPMODE_MANUAL: > + bp->bp_mode = BIOC_SPMMANUAL; > + break; > + case MFI_PR_OPMODE_DISABLED: > + bp->bp_mode = BIOC_SPMDISABLED; > + break; > + default: > + printf("%s: unknown patrol mode %d\n", > + DEVNAME(sc), prop.op_mode); > + break; > + } > + > + switch (status.state) { > + case MFI_PR_STATE_STOPPED: > + bp->bp_status = BIOC_SPSSTOPPED; > + break; > + case MFI_PR_STATE_READY: > + bp->bp_status = BIOC_SPSREADY; > + break; > + case MFI_PR_STATE_ACTIVE: > + bp->bp_status = BIOC_SPSACTIVE; > + break; > + case MFI_PR_STATE_ABORTED: > + bp->bp_status = BIOC_SPSABORTED; > + break; > + default: > + printf("%s: unknown patrol state %d\n", > + DEVNAME(sc), status.state); > + break; > + } > + > + break; > + > + default: > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_patrol biocpatrol > invalid " > + "opcode %x\n", DEVNAME(sc), bp->bp_opcode); > + return (EINVAL); > + } > + > + return (rv); > +} > + > +int > +mfii_bio_hs(struct mfii_softc *sc, int volid, int type, void *bio_hs) > +{ > + struct mfi_conf *cfg; > + struct mfi_hotspare *hs; > + struct mfi_pd_details *pd; > + struct bioc_disk *sdhs; > + struct bioc_vol *vdhs; > + struct scsi_inquiry_data *inqbuf; > + char vend[8+16+4+1], *vendp; > + int i, rv = EINVAL; > + uint32_t size; > + union mfi_mbox mbox; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs %d\n", DEVNAME(sc), volid); > + > + if (!bio_hs) > + return (EINVAL); > + > + pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK); > + > + /* send single element command to retrieve size for full structure */ > + cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK); > + if (mfii_mgmt(sc, MR_DCMD_CONF_GET, MFII_DATA_IN, sizeof *cfg, cfg, > NULL)) > + goto freeme; > + > + size = cfg->mfc_size; > + free(cfg, M_DEVBUF, sizeof *cfg); > + > + /* memory for read config */ > + cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO); > + if (mfii_mgmt(sc, MR_DCMD_CONF_GET, MFII_DATA_IN, size, cfg, NULL)) > + goto freeme; > + > + /* calculate offset to hs structure */ > + hs = (struct mfi_hotspare *)( > + ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) + > + cfg->mfc_array_size * cfg->mfc_no_array + > + cfg->mfc_ld_size * cfg->mfc_no_ld); > + > + if (volid < cfg->mfc_no_ld) > + goto freeme; /* not a hotspare */ > + > + if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs)) > + goto freeme; /* not a hotspare */ > + > + /* offset into hotspare structure */ > + i = volid - cfg->mfc_no_ld; > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs i %d volid %d no_ld %d no_hs %d > " > + "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld, > + cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id); > + > + /* get pd fields */ > + memset(&mbox, 0, sizeof(mbox)); > + mbox.s[0] = hs[i].mhs_pd.mfp_id; > + if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, MFII_DATA_IN, > + sizeof *pd, pd, &mbox)) { > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs illegal PD\n", > + DEVNAME(sc)); > + goto freeme; > + } > + > + switch (type) { > + case MFI_MGMT_VD: > + vdhs = bio_hs; > + vdhs->bv_status = BIOC_SVONLINE; > + vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */ > + vdhs->bv_level = -1; /* hotspare */ > + vdhs->bv_nodisk = 1; > + break; > + > + case MFI_MGMT_SD: > + sdhs = bio_hs; > + sdhs->bd_status = BIOC_SDHOTSPARE; > + sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */ > + sdhs->bd_channel = pd->mpd_enc_idx; > + sdhs->bd_target = pd->mpd_enc_slot; > + inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data; > + vendp = inqbuf->vendor; > + memcpy(vend, vendp, sizeof vend - 1); > + vend[sizeof vend - 1] = '\0'; > + strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor)); > + break; > + > + default: > + goto freeme; > + } > + > + DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs 6\n", DEVNAME(sc)); > + rv = 0; > +freeme: > + free(pd, M_DEVBUF, sizeof *pd); > + free(cfg, M_DEVBUF, 0); > + > + return (rv); > +} > + > +#ifndef SMALL_KERNEL > + > +#define MFI_BBU_SENSORS 4 > + > +int > +mfii_bbu(struct mfii_softc *sc) > +{ > + struct mfi_bbu_status bbu; > + u_int32_t status; > + u_int32_t mask; > + u_int32_t soh_bad; > + int i; > + > + if (mfii_mgmt(sc, MR_DCMD_BBU_GET_STATUS, MFII_DATA_IN, > + sizeof(bbu), &bbu, NULL) != 0) { > + for (i = 0; i < MFI_BBU_SENSORS; i++) { > + sc->sc_bbu[i].value = 0; > + sc->sc_bbu[i].status = SENSOR_S_UNKNOWN; > + } > + for (i = 0; i < nitems(mfi_bbu_indicators); i++) { > + sc->sc_bbu_status[i].value = 0; > + sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN; > + } > + return (-1); > + } > + > + switch (bbu.battery_type) { > + case MFI_BBU_TYPE_IBBU: > + mask = MFI_BBU_STATE_BAD_IBBU; > + soh_bad = 0; > + break; > + case MFI_BBU_TYPE_BBU: > + mask = MFI_BBU_STATE_BAD_BBU; > + soh_bad = (bbu.detail.bbu.is_SOH_good == 0); > + break; > + > + case MFI_BBU_TYPE_NONE: > + default: > + sc->sc_bbu[0].value = 0; > + sc->sc_bbu[0].status = SENSOR_S_CRIT; > + for (i = 1; i < MFI_BBU_SENSORS; i++) { > + sc->sc_bbu[i].value = 0; > + sc->sc_bbu[i].status = SENSOR_S_UNKNOWN; > + } > + for (i = 0; i < nitems(mfi_bbu_indicators); i++) { > + sc->sc_bbu_status[i].value = 0; > + sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN; > + } > + return (0); > + } > + > + status = letoh32(bbu.fw_status); > + > + sc->sc_bbu[0].value = ((status & mask) || soh_bad) ? 0 : 1; > + sc->sc_bbu[0].status = ((status & mask) || soh_bad) ? SENSOR_S_CRIT : > + SENSOR_S_OK; > + > + sc->sc_bbu[1].value = letoh16(bbu.voltage) * 1000; > + sc->sc_bbu[2].value = (int16_t)letoh16(bbu.current) * 1000; > + sc->sc_bbu[3].value = letoh16(bbu.temperature) * 1000000 + 273150000; > + for (i = 1; i < MFI_BBU_SENSORS; i++) > + sc->sc_bbu[i].status = SENSOR_S_UNSPEC; > + > + for (i = 0; i < nitems(mfi_bbu_indicators); i++) { > + sc->sc_bbu_status[i].value = (status & (1 << i)) ? 1 : 0; > + sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC; > + } > + > + return (0); > +} > + > +int > +mfii_create_sensors(struct mfii_softc *sc) > +{ > + struct device *dev; > + struct scsi_link *link; > + int i; > + > + strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), > + sizeof(sc->sc_sensordev.xname)); > + > + if (ISSET(letoh32(sc->sc_info.mci_adapter_ops ), MFI_INFO_AOPS_BBU)) { > + sc->sc_bbu = mallocarray(4, sizeof(*sc->sc_bbu), > + M_DEVBUF, M_WAITOK | M_ZERO); > + > + sc->sc_bbu[0].type = SENSOR_INDICATOR; > + sc->sc_bbu[0].status = SENSOR_S_UNKNOWN; > + strlcpy(sc->sc_bbu[0].desc, "bbu ok", > + sizeof(sc->sc_bbu[0].desc)); > + sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[0]); > + > + sc->sc_bbu[1].type = SENSOR_VOLTS_DC; > + sc->sc_bbu[1].status = SENSOR_S_UNSPEC; > + sc->sc_bbu[2].type = SENSOR_AMPS; > + sc->sc_bbu[2].status = SENSOR_S_UNSPEC; > + sc->sc_bbu[3].type = SENSOR_TEMP; > + sc->sc_bbu[3].status = SENSOR_S_UNSPEC; > + for (i = 1; i < MFI_BBU_SENSORS; i++) { > + strlcpy(sc->sc_bbu[i].desc, "bbu", > + sizeof(sc->sc_bbu[i].desc)); > + sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[i]); > + } > + > + sc->sc_bbu_status = malloc(sizeof(*sc->sc_bbu_status) * > + sizeof(mfi_bbu_indicators), M_DEVBUF, M_WAITOK | M_ZERO); > + > + for (i = 0; i < nitems(mfi_bbu_indicators); i++) { > + sc->sc_bbu_status[i].type = SENSOR_INDICATOR; > + sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC; > + strlcpy(sc->sc_bbu_status[i].desc, > + mfi_bbu_indicators[i], > + sizeof(sc->sc_bbu_status[i].desc)); > + > + sensor_attach(&sc->sc_sensordev, &sc->sc_bbu_status[i]); > + } > + } > + > + sc->sc_sensors = mallocarray(sc->sc_ld_cnt, sizeof(struct ksensor), > + M_DEVBUF, M_NOWAIT | M_ZERO); > + if (sc->sc_sensors == NULL) > + return (1); > + > + for (i = 0; i < sc->sc_ld_cnt; i++) { > + link = scsi_get_link(sc->sc_scsibus, i, 0); > + if (link == NULL) > + goto bad; > + > + dev = link->device_softc; > + > + sc->sc_sensors[i].type = SENSOR_DRIVE; > + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; > + > + strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, > + sizeof(sc->sc_sensors[i].desc)); > + > + sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); > + } > + > + if (sensor_task_register(sc, mfii_refresh_sensors, 10) == NULL) > + goto bad; > + > + sensordev_install(&sc->sc_sensordev); > + > + return (0); > + > +bad: > + free(sc->sc_sensors, M_DEVBUF, > + sc->sc_ld_cnt * sizeof(struct ksensor)); > + > + return (1); > +} > + > +void > +mfii_refresh_sensors(void *arg) > +{ > + struct mfii_softc *sc = arg; > + int i, rv; > + struct bioc_vol bv; > + > + if (sc->sc_bbu != NULL && mfii_bbu(sc) != 0) > + return; > + > + for (i = 0; i < sc->sc_ld_cnt; i++) { > + bzero(&bv, sizeof(bv)); > + bv.bv_volid = i; > + > + rw_enter_write(&sc->sc_lock); > + rv = mfii_ioctl_vol(sc, &bv); > + rw_exit_write(&sc->sc_lock); > + > + if (rv != 0) > + return; > + > + switch(bv.bv_status) { > + case BIOC_SVOFFLINE: > + sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; > + sc->sc_sensors[i].status = SENSOR_S_CRIT; > + break; > + > + case BIOC_SVDEGRADED: > + sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; > + sc->sc_sensors[i].status = SENSOR_S_WARN; > + break; > + > + case BIOC_SVSCRUB: > + case BIOC_SVONLINE: > + sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; > + sc->sc_sensors[i].status = SENSOR_S_OK; > + break; > + > + case BIOC_SVINVALID: > + /* FALLTRHOUGH */ > + default: > + sc->sc_sensors[i].value = 0; /* unknown */ > + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; > + break; > + } > + } > +} > +#endif /* SMALL_KERNEL */ > +#endif /* NBIO > 0 */ > > -- > FUKAUMI Naoki
