diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2006-06-19 19:05:46 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2006-06-19 19:05:46 +0000 |
commit | 88808ef2cad0e3f288cd285abc2a51d1986cae7d (patch) | |
tree | 5bc86f66c2de679dc447454d69dfe31300797a29 | |
parent | 1929450412dcfb9542cc3f6a9aae0ed7da7dca92 (diff) |
Add hot spare support.
-rw-r--r-- | sys/dev/ic/mfi.c | 211 | ||||
-rw-r--r-- | sys/dev/ic/mfireg.h | 10 | ||||
-rw-r--r-- | sys/dev/ic/mfivar.h | 3 |
3 files changed, 205 insertions, 19 deletions
diff --git a/sys/dev/ic/mfi.c b/sys/dev/ic/mfi.c index bd0b505ae42..0e88e61de3f 100644 --- a/sys/dev/ic/mfi.c +++ b/sys/dev/ic/mfi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mfi.c,v 1.58 2006/05/26 00:53:54 marco Exp $ */ +/* $OpenBSD: mfi.c,v 1.59 2006/06/19 19:05:45 marco Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us> * @@ -79,8 +79,8 @@ void mfi_freemem(struct mfi_softc *, struct mfi_mem *); int mfi_transition_firmware(struct mfi_softc *); int mfi_initialize_firmware(struct mfi_softc *); int mfi_get_info(struct mfi_softc *); -u_int32_t mfi_read(struct mfi_softc *, bus_size_t); -void mfi_write(struct mfi_softc *, bus_size_t, u_int32_t); +uint32_t mfi_read(struct mfi_softc *, bus_size_t); +void mfi_write(struct mfi_softc *, bus_size_t, uint32_t); int mfi_poll(struct mfi_ccb *); int mfi_despatch_cmd(struct mfi_ccb *); int mfi_create_sgl(struct mfi_ccb *, int); @@ -102,6 +102,7 @@ int mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *); int mfi_ioctl_alarm(struct mfi_softc *, struct bioc_alarm *); int mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *); int mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *); +int mfi_bio_hs(struct mfi_softc *, int, int, void *); #endif /* NBIO > 0 */ struct mfi_ccb * @@ -212,10 +213,10 @@ destroy: return (1); } -u_int32_t +uint32_t mfi_read(struct mfi_softc *sc, bus_size_t r) { - u_int32_t rv; + uint32_t rv; bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, BUS_SPACE_BARRIER_READ); @@ -226,7 +227,7 @@ mfi_read(struct mfi_softc *sc, bus_size_t r) } void -mfi_write(struct mfi_softc *sc, bus_size_t r, u_int32_t v) +mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v) { DNPRINTF(MFI_D_RW, "%s: mw 0x%x 0x%08x", DEVNAME(sc), r, v); @@ -1253,17 +1254,30 @@ mfi_ioctl(struct device *dev, u_long cmd, caddr_t addr) int mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi) { + struct mfi_conf *cfg; + int rv = EINVAL; + + DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc)); + if (mfi_get_info(sc)) { DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq failed\n", DEVNAME(sc)); return (EIO); } + /* get figures */ + cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK); + if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL)) + goto freeme; + strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); - bi->bi_novol = sc->sc_info.mci_lds_present; + bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs; bi->bi_nodisk = sc->sc_info.mci_pd_disks_present; - return (0); + rv = 0; +freeme: + free(cfg, M_DEVBUF); + return (rv); } int @@ -1288,8 +1302,9 @@ mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv) sizeof(sc->sc_ld_details), &sc->sc_ld_details, mbox)) goto done; - if (bv->bv_volid > sc->sc_ld_list.mll_no_ld) { - /* XXX go do hotspares */ + if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) { + /* go do hotspares */ + rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv); goto done; } @@ -1401,8 +1416,9 @@ mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd) vol = bd->bd_volid; - if (vol > cfg->mfc_no_ld) { - /* XXX do hotspares */ + if (vol >= cfg->mfc_no_ld) { + /* do hotspares */ + rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd); goto freeme; } @@ -1422,7 +1438,7 @@ mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd) bd->bd_status = BIOC_SDUNUSED; break; - case MFI_PD_HOTSPARE: + case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */ bd->bd_status = BIOC_SDHOTSPARE; break; @@ -1530,6 +1546,9 @@ mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb) uint32_t cmd; struct mfi_pd_list *pd; + DNPRINTF(MFI_D_IOCTL, "%s: mfi_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); @@ -1552,14 +1571,14 @@ mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb) memset(mbox, 0, sizeof mbox); + *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;; + switch (bb->bb_status) { case BIOC_SBUNBLINK: - *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;; cmd = MR_DCMD_PD_UNBLINK; break; case BIOC_SBBLINK: - *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;; cmd = MR_DCMD_PD_BLINK; break; @@ -1583,6 +1602,166 @@ done: int mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs) { - return (ENOTTY); /* XXX not yet */ + struct mfi_pd_list *pd; + int i, found, rv = EINVAL; + uint8_t mbox[MFI_MBOX_SIZE]; + uint32_t cmd; + + DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc), + bs->bs_status); + + pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK); + + if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN, + MFI_PD_LIST_SIZE, pd, NULL)) + goto done; + + for (i = 0, found = 0; i < pd->mpl_no_pd; i++) + if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index && + bs->bs_target == pd->mpl_address[i].mpa_enc_slot) { + found = 1; + break; + } + + if (!found) + goto done; + + memset(mbox, 0, sizeof mbox); + + *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;; + + switch (bs->bs_status) { + case BIOC_SSONLINE: + mbox[2] = MFI_PD_ONLINE; + cmd = MD_DCMD_PD_SET_STATE; + break; + + case BIOC_SSOFFLINE: + mbox[2] = MFI_PD_OFFLINE; + cmd = MD_DCMD_PD_SET_STATE; + break; + + case BIOC_SSHOTSPARE: + mbox[2] = MFI_PD_HOTSPARE; + cmd = MD_DCMD_PD_SET_STATE; + break; +/* + case BIOC_SSREBUILD: + cmd = MD_DCMD_PD_REBUILD; + break; +*/ + default: + DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid " + "opcode %x\n", DEVNAME(sc), bs->bs_status); + goto done; + } + + + if (mfi_mgmt(sc, MD_DCMD_PD_SET_STATE, MFI_DATA_NONE, 0, NULL, mbox)) + goto done; + + rv = 0; +done: + free(pd, M_DEVBUF); + return (rv); } + +int +mfi_bio_hs(struct mfi_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]; + int i, rv = EINVAL; + uint32_t size; + uint8_t mbox[MFI_MBOX_SIZE]; + + DNPRINTF(MFI_D_IOCTL, "%s: mfi_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 (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL)) + goto freeme; + + size = cfg->mfc_size; + free(cfg, M_DEVBUF); + + /* memory for read config */ + cfg = malloc(size, M_DEVBUF, M_WAITOK); + memset(cfg, 0, size); + if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_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(MFI_D_IOCTL, "%s: mfi_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); + *((uint16_t *)&mbox) = hs[i].mhs_pd.mfp_id; + if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN, + sizeof *pd, pd, mbox)) { + DNPRINTF(MFI_D_IOCTL, "%s: mfi_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; + 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; + sdhs->bd_channel = pd->mpd_enc_idx; + sdhs->bd_target = pd->mpd_enc_slot; + inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data; + memcpy(vend, inqbuf->vendor, sizeof vend - 1); + vend[sizeof vend - 1] = '\0'; + strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor)); + break; + + default: + goto freeme; + } + + DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc)); + rv = 0; +freeme: + free(pd, M_DEVBUF); + free(cfg, M_DEVBUF); + + return (rv); +} + #endif /* NBIO > 0 */ diff --git a/sys/dev/ic/mfireg.h b/sys/dev/ic/mfireg.h index 68a162aab48..d5654783263 100644 --- a/sys/dev/ic/mfireg.h +++ b/sys/dev/ic/mfireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mfireg.h,v 1.23 2006/05/26 00:53:54 marco Exp $ */ +/* $OpenBSD: mfireg.h,v 1.24 2006/06/19 19:05:45 marco Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us> * @@ -15,7 +15,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* management interface constants */ +#define MFI_MGMT_VD 0x01 +#define MFI_MGMT_SD 0x02 +/* generic constants */ #define MFI_FRAME_SIZE 64 #define MFI_SENSE_SIZE 128 #define MFI_OSTS_INTR_VALID 0x00000002 /* valid interrupt */ @@ -94,6 +98,8 @@ #define MR_DCMD_CTRL_EVENT_WAIT 0x01040500 #define MR_DCMD_PD_GET_LIST 0x02010000 #define MR_DCMD_PD_GET_INFO 0x02020000 +#define MD_DCMD_PD_SET_STATE 0x02030100 +#define MD_DCMD_PD_REBUILD 0x02040100 #define MR_DCMD_PD_BLINK 0x02070100 #define MR_DCMD_PD_UNBLINK 0x02070200 #define MR_DCMD_LD_GET_LIST 0x03010000 @@ -859,7 +865,7 @@ struct mfi_pd_details { u_quad_t mpd_coerce_size; uint16_t mpd_enc_id; uint8_t mpd_enc_idx; - uint8_t mpd_slot; + uint8_t mpd_enc_slot; struct mfi_pd_progress mpd_progress; uint8_t mpd_bblock_full; uint8_t mpd_unusable; diff --git a/sys/dev/ic/mfivar.h b/sys/dev/ic/mfivar.h index 0a1b7f9c310..9906ee49c4a 100644 --- a/sys/dev/ic/mfivar.h +++ b/sys/dev/ic/mfivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mfivar.h,v 1.25 2006/05/25 00:21:31 marco Exp $ */ +/* $OpenBSD: mfivar.h,v 1.26 2006/06/19 19:05:45 marco Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us> * @@ -122,6 +122,7 @@ struct mfi_softc { uint32_t sc_max_sgl; uint32_t sc_max_ld; uint32_t sc_ld_cnt; + /* XXX these struct should be local to mgmt function */ struct mfi_ctrl_info sc_info; struct mfi_ld_list sc_ld_list; struct mfi_ld_details sc_ld_details; |