diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2006-08-24 09:18:41 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2006-08-24 09:18:41 +0000 |
commit | be81f15a237c10f83421422c67e62a6d3cbe1d80 (patch) | |
tree | 6fad26cacc0f036160bf260d6d81fd1de4c74ecf /sys/dev | |
parent | 511c20de05df25f20a3437cf1a65d29e9552dcc5 (diff) |
a start at the BIOC INQ, VOL, and DISK ioctls for fetching information
about the disks that are configured on the controller. so far this fetches
the right volumes and disks in each volume, but doesnt properly fill in the
status, the size of both the volumes and disks, the type of raid, or the
firmware version of the physical disks.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/arc.c | 245 |
1 files changed, 244 insertions, 1 deletions
diff --git a/sys/dev/pci/arc.c b/sys/dev/pci/arc.c index 1ea92840948..7b1c91f595c 100644 --- a/sys/dev/pci/arc.c +++ b/sys/dev/pci/arc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arc.c,v 1.34 2006/08/20 13:56:09 dlg Exp $ */ +/* $OpenBSD: arc.c,v 1.35 2006/08/24 09:18:40 dlg Exp $ */ /* * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> @@ -455,9 +455,15 @@ int arc_msgbuf(struct arc_softc *, void *, size_t, /* bioctl */ #if NBIO > 0 int arc_bioctl(struct device *, u_long, caddr_t); +int arc_bio_inq(struct arc_softc *, struct bioc_inq *); +int arc_bio_vol(struct arc_softc *, struct bioc_vol *); +int arc_bio_disk(struct arc_softc *, struct bioc_disk *); int arc_bio_alarm(struct arc_softc *, struct bioc_alarm *); int arc_bio_alarm_state(struct arc_softc *, struct bioc_alarm *); + +int arc_bio_getvol(struct arc_softc *, int, + struct arc_fw_volinfo *); #endif int @@ -908,6 +914,18 @@ arc_bioctl(struct device *self, u_long cmd, caddr_t addr) int error = 0; switch (cmd) { + case BIOCINQ: + error = arc_bio_inq(sc, (struct bioc_inq *)addr); + break; + + case BIOCVOL: + error = arc_bio_vol(sc, (struct bioc_vol *)addr); + break; + + case BIOCDISK: + error = arc_bio_disk(sc, (struct bioc_disk *)addr); + break; + case BIOCALARM: error = arc_bio_alarm(sc, (struct bioc_alarm *)addr); break; @@ -992,6 +1010,231 @@ out: free(sysinfo, M_TEMP); return (error); } + + +int +arc_bio_inq(struct arc_softc *sc, struct bioc_inq *bi) +{ + u_int8_t request[2]; + struct arc_fw_sysinfo *sysinfo; + struct arc_fw_volinfo *volinfo; + int maxvols, nvols = 0, i; + int error = 0; + + sysinfo = malloc(sizeof(struct arc_fw_sysinfo), M_TEMP, M_WAITOK); + if (sysinfo == NULL) + return (ENOMEM); + + volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK); + if (volinfo == NULL) { + free(sysinfo, M_TEMP); + return (ENOMEM); + } + + arc_lock(sc); + + request[0] = ARC_FW_SYSINFO; + error = arc_msgbuf(sc, request, 1, sysinfo, + sizeof(struct arc_fw_sysinfo)); + if (error != 0) + goto out; + + maxvols = sysinfo->max_volume_set; + + request[0] = ARC_FW_VOLINFO; + for (i = 0; i < maxvols; i++) { + request[1] = i; + error = arc_msgbuf(sc, request, sizeof(request), volinfo, + sizeof(struct arc_fw_volinfo)); + if (error != 0) + goto out; + + /* + * i cant find an easy way to see if the volume exists or not + * except to say that if it has no capacity then it isnt there + */ + if (volinfo->capacity != 0) + nvols++; + } + + bi->bi_novol = nvols; +out: + arc_unlock(sc); + free(volinfo, M_TEMP); + free(sysinfo, M_TEMP); + return (error); +} + +int +arc_bio_getvol(struct arc_softc *sc, int vol, struct arc_fw_volinfo *volinfo) +{ + u_int8_t request[2]; + struct arc_fw_sysinfo *sysinfo; + int error = 0; + int maxvols, nvols = 0, i; + + sysinfo = malloc(sizeof(struct arc_fw_sysinfo), M_TEMP, M_WAITOK); + if (sysinfo == NULL) + return (ENOMEM); + + request[0] = ARC_FW_SYSINFO; + error = arc_msgbuf(sc, request, 1, sysinfo, + sizeof(struct arc_fw_sysinfo)); + if (error != 0) + goto out; + + maxvols = sysinfo->max_volume_set; + + request[0] = ARC_FW_VOLINFO; + for (i = 0; i < maxvols; i++) { + request[1] = i; + error = arc_msgbuf(sc, request, sizeof(request), volinfo, + sizeof(struct arc_fw_volinfo)); + if (error != 0) + goto out; + + if (volinfo->capacity == 0) + continue; + + if (nvols == vol) + break; + + nvols++; + } + + if (nvols != vol || volinfo->capacity == 0) { + error = ENODEV; + goto out; + } + +out: + free(sysinfo, M_TEMP); + return (error); +} + +int +arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv) +{ + struct arc_fw_volinfo *volinfo; + struct scsi_link *sc_link; + struct device *dev; + int error = 0; + + volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK); + if (volinfo == NULL) + return (ENOMEM); + + arc_lock(sc); + error = arc_bio_getvol(sc, bv->bv_volid, volinfo); + arc_unlock(sc); + + if (error != 0) + goto out; + + sc_link = sc->sc_scsibus->sc_link[volinfo->scsi_attr.target] + [volinfo->scsi_attr.lun]; + if (sc_link == NULL) { + error = ENODEV; + goto out; + } + dev = sc_link->device_softc; + arc_unlock(sc); + + bv->bv_percent = -1; + bv->bv_seconds = 0; + + bv->bv_status = BIOC_SVONLINE; + bv->bv_size = letoh32(volinfo->capacity) * + letoh32(volinfo->stripe_size) * 512; + bv->bv_level = 0; + bv->bv_nodisk = volinfo->member_disks; + strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev)); + +out: + free(volinfo, M_TEMP); + return (error); +} + +int +arc_bio_disk(struct arc_softc *sc, struct bioc_disk *bd) +{ + u_int8_t request[2]; + struct arc_fw_volinfo *volinfo; + struct arc_fw_raidinfo *raidinfo; + struct arc_fw_diskinfo *diskinfo; + int error = 0; + char string[128]; + + volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK); + if (volinfo == NULL) + return (ENOMEM); + + raidinfo = malloc(sizeof(struct arc_fw_raidinfo), M_TEMP, M_WAITOK); + if (raidinfo == NULL) { + free(volinfo, M_TEMP); + return (ENOMEM); + } + + diskinfo = malloc(sizeof(struct arc_fw_diskinfo), M_TEMP, M_WAITOK); + if (diskinfo == NULL) { + free(raidinfo, M_TEMP); + free(volinfo, M_TEMP); + return (ENOMEM); + } + + arc_lock(sc); + + error = arc_bio_getvol(sc, bd->bd_volid, volinfo); + if (error != 0) + goto out; + + request[0] = ARC_FW_RAIDINFO; + request[1] = volinfo->raid_set_number; + error = arc_msgbuf(sc, request, sizeof(request), raidinfo, + sizeof(struct arc_fw_raidinfo)); + if (error != 0) + goto out; + + if (bd->bd_diskid > raidinfo->member_devices) { + error = ENODEV; + goto out; + } + + request[0] = ARC_FW_DISKINFO; + request[1] = raidinfo->device_array[bd->bd_diskid]; + error = arc_msgbuf(sc, request, sizeof(request), diskinfo, + sizeof(struct arc_fw_diskinfo)); + if (error != 0) + goto out; + +#if 0 + bd->bd_channel = diskinfo->scsi_attr.channel; + bd->bd_target = diskinfo->scsi_attr.target; + bd->bd_lun = diskinfo->scsi_attr.lun; +#endif + /* + * the firwmare doesnt seem to fill scsi_attr in, so fake it with + * the diskid. + */ + bd->bd_channel = 0; + bd->bd_target = raidinfo->device_array[bd->bd_diskid]; + bd->bd_lun = 0; + + bd->bd_status = BIOC_SDONLINE; + bd->bd_size = letoh32(diskinfo->capacity) * 512; + + scsi_strvis(string, diskinfo->model, sizeof(diskinfo->model)); + strlcpy(bd->bd_vendor, string, sizeof(bd->bd_vendor)); + scsi_strvis(string, diskinfo->serial, sizeof(diskinfo->serial)); + strlcpy(bd->bd_serial, string, sizeof(bd->bd_serial)); + +out: + arc_unlock(sc); + free(diskinfo, M_TEMP); + free(raidinfo, M_TEMP); + free(volinfo, M_TEMP); + return (error); +} #endif /* NBIO > 0 */ u_int8_t |