diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2009-02-17 20:22:08 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2009-02-17 20:22:08 +0000 |
commit | 7e4427953ac5c996b79e732aedfe45c97bfafdfe (patch) | |
tree | 334303210a1e8c0583a531059ae17a9d190fe577 | |
parent | 0118182c4b69719263e3856e0420f2629b73135b (diff) |
- add more bioctl support, now physical drives info available
- shrink dmesg strings
-rw-r--r-- | sys/dev/pci/ips.c | 218 |
1 files changed, 164 insertions, 54 deletions
diff --git a/sys/dev/pci/ips.c b/sys/dev/pci/ips.c index 15c9c942d4d..0f2ee1f3858 100644 --- a/sys/dev/pci/ips.c +++ b/sys/dev/pci/ips.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ips.c,v 1.46 2009/02/16 21:19:07 miod Exp $ */ +/* $OpenBSD: ips.c,v 1.47 2009/02/17 20:22:07 grange Exp $ */ /* * Copyright (c) 2006, 2007, 2009 Alexander Yurchenko <grange@openbsd.org> @@ -61,6 +61,7 @@ int ips_debug = IPS_D_ERR; #define IPS_MAXDRIVES 8 #define IPS_MAXCHANS 4 #define IPS_MAXTARGETS 15 +#define IPS_MAXCHUNKS 16 #define IPS_MAXCMDS 128 #define IPS_MAXFER (64 * 1024) @@ -81,6 +82,7 @@ int ips_debug = IPS_D_ERR; #define IPS_CMD_DCDB 0x04 #define IPS_CMD_GETADAPTERINFO 0x05 #define IPS_CMD_FLUSH 0x0a +#define IPS_CMD_REBUILDSTATUS 0x0c #define IPS_CMD_ERRORTABLE 0x17 #define IPS_CMD_GETDRIVEINFO 0x19 #define IPS_CMD_RESETCHAN 0x1a @@ -206,6 +208,65 @@ struct ips_pg5 { u_int8_t __reserved4[100]; }; +struct ips_conf { + u_int8_t ldcnt; + u_int8_t day; + u_int8_t month; + u_int8_t year; + u_int8_t initid[4]; + u_int8_t hostid[12]; + u_int8_t time[8]; + u_int32_t useropt; + u_int16_t userfield; + u_int8_t rebuildrate; + u_int8_t __reserved1; + + struct ips_hw { + u_int8_t board[8]; + u_int8_t cpu[8]; + u_int8_t nchantype; + u_int8_t nhostinttype; + u_int8_t compression; + u_int8_t nvramtype; + u_int32_t nvramsize; + } hw; + + struct ips_ld { + u_int16_t userfield; + u_int8_t state; + u_int8_t raidcacheparam; + u_int8_t chunkcnt; + u_int8_t stripesize; + u_int8_t params; + u_int8_t __reserved; + u_int32_t size; + + struct ips_chunk { + u_int8_t channel; + u_int8_t target; + u_int16_t __reserved; + u_int32_t startsec; + u_int32_t seccnt; + } chunk[IPS_MAXCHUNKS]; + } ld[IPS_MAXDRIVES]; + + struct ips_dev { + u_int8_t initiator; + u_int8_t params; + u_int8_t miscflag; + u_int8_t state; +#define IPS_DVS_PRESENT 0x81 +#define IPS_DVS_REBUILD 0x02 +#define IPS_DVS_SPARE 0x04 +#define IPS_DVS_MEMBER 0x08 + + u_int32_t seccnt; + u_int8_t devid[28]; + } dev[IPS_MAXCHANS][IPS_MAXTARGETS + 1]; + + u_int8_t reserved[512]; +}; + /* Command control block */ struct ips_ccb { int c_id; /* command id */ @@ -250,6 +311,7 @@ struct ips_softc { const struct ips_chipset *sc_chip; + struct ips_conf sc_conf; struct ips_driveinfo sc_di; int sc_nunits; @@ -270,10 +332,13 @@ int ips_match(struct device *, void *, void *); void ips_attach(struct device *, struct device *, void *); int ips_scsi_cmd(struct scsi_xfer *); +int ips_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, + struct proc *); int ips_ioctl(struct device *, u_long, caddr_t); int ips_ioctl_inq(struct ips_softc *, struct bioc_inq *); int ips_ioctl_vol(struct ips_softc *, struct bioc_vol *); +int ips_ioctl_disk(struct ips_softc *, struct bioc_disk *); int ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int, struct scsi_xfer *); @@ -283,6 +348,7 @@ int ips_intr(void *); void ips_timeout(void *); int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *); +int ips_getconf(struct ips_softc *, struct ips_conf *); int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *); int ips_flush(struct ips_softc *); int ips_readnvram(struct ips_softc *, void *, int); @@ -324,7 +390,7 @@ static struct scsi_adapter ips_scsi_adapter = { scsi_minphys, NULL, NULL, - NULL + ips_scsi_ioctl }; static struct scsi_device ips_scsi_device = { @@ -385,6 +451,8 @@ static const struct ips_chipset { #define ips_status(s) (s)->sc_chip->ic_status((s)) static const char *ips_names[] = { + NULL, + NULL, "II", "onboard", "onboard", @@ -429,24 +497,16 @@ ips_attach(struct device *parent, struct device *self, void *aux) sc->sc_dmat = pa->pa_dmat; /* Identify chipset */ - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_IBM_SERVERAID: + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_IBM_SERVERAID) sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD]; - break; - case PCI_PRODUCT_IBM_SERVERAID2: - case PCI_PRODUCT_ADP2_SERVERAID: + else sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS]; - break; - default: - printf(": unsupported chipset\n"); - return; - } /* Map registers */ maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar); if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) { - printf(": can't map registers\n"); + printf(": can't map regs\n"); return; } @@ -456,14 +516,14 @@ ips_attach(struct device *parent, struct device *self, void *aux) /* Allocate command buffer */ if (ips_dmamem_alloc(&sc->sc_cmdm, sc->sc_dmat, IPS_MAXCMDS * IPS_MAXCMDSZ)) { - printf(": can't allocate command buffer\n"); + printf(": can't alloc cmd buffer\n"); goto fail1; } /* Allocate status queue for the Copperhead chipset */ if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD) { if (ips_dmamem_alloc(&sc->sc_sqm, sc->sc_dmat, IPS_SQSZ)) { - printf(": can't allocate status queue\n"); + printf(": can't alloc status queue\n"); goto fail2; } sc->sc_sqtail = sc->sc_sqm.dm_paddr; @@ -488,7 +548,7 @@ ips_attach(struct device *parent, struct device *self, void *aux) if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS, IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb0.c_dmam)) { - printf(": can't bootstrap CCB queue\n"); + printf(": can't bootstrap ccb queue\n"); goto fail3; } TAILQ_INIT(&sc->sc_ccbq_free); @@ -502,9 +562,16 @@ ips_attach(struct device *parent, struct device *self, void *aux) goto fail3; } + /* Get configuration */ + if (ips_getconf(sc, &sc->sc_conf)) { + printf(": can't get config\n"); + bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam); + goto fail3; + } + /* Get logical drives info */ if (ips_getdriveinfo(sc, &sc->sc_di)) { - printf(": can't get logical drives info\n"); + printf(": can't get ld info\n"); bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam); goto fail3; } @@ -519,7 +586,7 @@ ips_attach(struct device *parent, struct device *self, void *aux) /* Initialize CCB queue */ sc->sc_nccbs = ai.cmdcnt; if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) { - printf(": can't allocate CCB queue\n"); + printf(": can't alloc ccb queue\n"); goto fail3; } TAILQ_INIT(&sc->sc_ccbq_free); @@ -547,16 +614,15 @@ ips_attach(struct device *parent, struct device *self, void *aux) /* Display adapter info */ printf("%s: ServeRAID", sc->sc_dev.dv_xname); type = letoh16(pg5.type); - if (type > 1 && type - 2 < sizeof(ips_names) / sizeof(ips_names[0])) - printf(" %s", ips_names[type - 2]); - printf(", firmware %c%c%c%c%c%c%c", - ai.firmware[0], ai.firmware[1], ai.firmware[2], - ai.firmware[3], ai.firmware[4], ai.firmware[5], + if (type < sizeof(ips_names) / sizeof(ips_names[0]) && ips_names[type]) + printf(" %s", ips_names[type]); + printf(", FW %c%c%c%c%c%c%c", ai.firmware[0], ai.firmware[1], + ai.firmware[2], ai.firmware[3], ai.firmware[4], ai.firmware[5], ai.firmware[6]); - printf(", bios %c%c%c%c%c%c%c", - ai.bios[0], ai.bios[1], ai.bios[2], ai.bios[3], ai.bios[4], - ai.bios[5], ai.bios[6]); - printf(", %d CCBs, %d units", sc->sc_nccbs, sc->sc_nunits); + printf(", BIOS %c%c%c%c%c%c%c", ai.bios[0], ai.bios[1], ai.bios[2], + ai.bios[3], ai.bios[4], ai.bios[5], ai.bios[6]); + printf(", %d cmds, %d LD%s", sc->sc_nccbs, sc->sc_nunits, + (sc->sc_nunits == 1 ? "" : "s")); printf("\n"); /* Attach SCSI bus */ @@ -724,6 +790,13 @@ ips_scsi_cmd(struct scsi_xfer *xs) return (COMPLETE); } +int +ips_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag, + struct proc *p) +{ + return (ips_ioctl(link->adapter_softc, cmd, addr)); +} + #if NBIO > 0 int ips_ioctl(struct device *dev, u_long cmd, caddr_t addr) @@ -737,6 +810,8 @@ ips_ioctl(struct device *dev, u_long cmd, caddr_t addr) return (ips_ioctl_inq(sc, (struct bioc_inq *)addr)); case BIOCVOL: return (ips_ioctl_vol(sc, (struct bioc_vol *)addr)); + case BIOCDISK: + return (ips_ioctl_disk(sc, (struct bioc_disk *)addr)); default: return (ENOTTY); } @@ -748,7 +823,7 @@ ips_ioctl_inq(struct ips_softc *sc, struct bioc_inq *bi) struct ips_adapterinfo ai; if (ips_getadapterinfo(sc, &ai)) - return (EIO); + return (ENOTTY); strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev)); bi->bi_novol = sc->sc_nunits; @@ -762,16 +837,15 @@ ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv) { struct ips_driveinfo di; struct ips_drive *drive; + int vid = bv->bv_volid; struct device *dev; - struct scsi_link *link; - int id = bv->bv_volid, vol, i; - if (id >= sc->sc_nunits) + if (vid >= sc->sc_nunits) return (EINVAL); if (ips_getdriveinfo(sc, &di)) - return (EIO); - drive = &di.drive[id]; + return (ENOTTY); + drive = &di.drive[vid]; switch (drive->state) { case IPS_DS_ONLINE: @@ -789,27 +863,56 @@ ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv) bv->bv_size = (u_quad_t)letoh32(drive->seccnt) * IPS_SECSZ; bv->bv_level = drive->raid; - bv->bv_nodisk = 0; /* XXX */ + bv->bv_nodisk = sc->sc_conf.ld[vid].chunkcnt; - for (i = 0, vol = -1; i < sc->sc_nunits; i++) { - link = sc->sc_scsibus->sc_link[i][0]; - if (link == NULL) - continue; + dev = sc->sc_scsibus->sc_link[vid][0]->device_softc; + strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev)); + strlcpy(bv->bv_vendor, "IBM", sizeof(bv->bv_vendor)); - /* skip if not a virtual disk */ - if (!(link->flags & SDEV_VIRTUAL)) - continue; + return (0); +} - vol++; - /* are we it? */ - if (vol == id) { - dev = link->device_softc; - memcpy(bv->bv_vendor, link->inqdata.vendor, - sizeof bv->bv_vendor); - bv->bv_vendor[sizeof(bv->bv_vendor) - 1] = '\0'; - strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev)); - break; - } +int +ips_ioctl_disk(struct ips_softc *sc, struct bioc_disk *bd) +{ + int vid = bd->bd_volid, did = bd->bd_diskid; + struct ips_ld *ld; + struct ips_chunk *chunk; + struct ips_dev *dev; + + if (vid >= sc->sc_nunits) + return (EINVAL); + ld = &sc->sc_conf.ld[vid]; + + if (did >= ld->chunkcnt) + return (EINVAL); + chunk = &ld->chunk[did]; + + if (chunk->channel >= IPS_MAXCHANS || chunk->target >= IPS_MAXTARGETS) + return (ENOTTY); + dev = &sc->sc_conf.dev[chunk->channel][chunk->target]; + + if (ips_getconf(sc, &sc->sc_conf)) + return (ENOTTY); + + bd->bd_channel = chunk->channel; + bd->bd_target = chunk->target; + bd->bd_lun = 0; + bd->bd_size = (u_quad_t)letoh32(chunk->seccnt) * IPS_SECSZ; + + bzero(bd->bd_vendor, sizeof(bd->bd_vendor)); + memcpy(bd->bd_vendor, dev->devid, MIN(sizeof(bd->bd_vendor), + sizeof(dev->devid))); + + if (dev->state & IPS_DVS_PRESENT) { + if (dev->state & IPS_DVS_REBUILD) + bd->bd_status = BIOC_SDREBUILD; + if (dev->state & IPS_DVS_SPARE) + bd->bd_status = BIOC_SDHOTSPARE; + if (dev->state & IPS_DVS_MEMBER) + bd->bd_status = BIOC_SDONLINE; + } else { + bd->bd_status = BIOC_SDOFFLINE; } return (0); @@ -851,7 +954,7 @@ ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data, /* Map data buffer into DMA segments */ if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, data, size, NULL, BUS_DMA_NOWAIT)) { - printf("%s: can't load DMA map\n", + printf("%s: can't load dma map\n", sc->sc_dev.dv_xname); return (1); /* XXX: return code */ } @@ -861,7 +964,7 @@ ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data, BUS_DMASYNC_PREWRITE); if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS) { - printf("%s: too many DMA segments\n", + printf("%s: too many dma segs\n", sc->sc_dev.dv_xname); return (1); /* XXX: return code */ } @@ -946,7 +1049,7 @@ ips_done(struct ips_softc *sc, struct ips_ccb *ccb) int error = 0; if ((flags & IPS_CCB_RUN) == 0) { - printf("%s: command 0x%02x not run\n", sc->sc_dev.dv_xname, + printf("%s: cmd 0x%02x not run\n", sc->sc_dev.dv_xname, ccb->c_id); if (xs != NULL) { xs->error = XS_DRIVER_STUFFUP; @@ -1056,6 +1159,13 @@ ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai) } int +ips_getconf(struct ips_softc *sc, struct ips_conf *conf) +{ + return (ips_cmd(sc, IPS_CMD_READCONF, 0, 0, conf, sizeof(*conf), + IPS_CCB_READ | IPS_CCB_POLL, NULL)); +} + +int ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di) { return (ips_cmd(sc, IPS_CMD_GETDRIVEINFO, 0, 0, di, sizeof(*di), |