diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2006-08-27 11:29:46 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2006-08-27 11:29:46 +0000 |
commit | bbf58ae93c16e99e757b90f5df94e4bbaa54278e (patch) | |
tree | 628d40d38eebe52512fd2f0f49a1d8d87ac0ed6b | |
parent | 3303f585d297012ea36ee41c57e5dc4364683642 (diff) |
sigh, this is annoying. it appears that the arc firmware doesnt care if a
volume is degraded, just if it is working or not. if a volume is degraded,
its still online, so we have to go look for missing disks. if a disk has
been replaced, but it is yet to be rebuilt, the firmware kindly tells us
that it needs rebuilding. we can figure out if a volume is degraded using
these two facts.
-rw-r--r-- | sys/dev/pci/arc.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/sys/dev/pci/arc.c b/sys/dev/pci/arc.c index 6e124091f6a..1cd03fdc494 100644 --- a/sys/dev/pci/arc.c +++ b/sys/dev/pci/arc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arc.c,v 1.45 2006/08/27 09:56:20 dlg Exp $ */ +/* $OpenBSD: arc.c,v 1.46 2006/08/27 11:29:45 dlg Exp $ */ /* * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> @@ -1139,18 +1139,27 @@ int arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv) { struct arc_fw_volinfo *volinfo; + struct arc_fw_raidinfo *raidinfo; struct scsi_link *sc_link; struct device *dev; + u_int8_t request[2]; u_int32_t status; + int i; int error = 0; 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); + } + arc_lock(sc); + error = arc_bio_getvol(sc, bv->bv_volid, volinfo); - arc_unlock(sc); if (error != 0) goto out; @@ -1158,8 +1167,29 @@ arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv) bv->bv_seconds = 0; status = letoh32(volinfo->volume_status); - if (status == 0x0) + if (status == 0x0) { bv->bv_status = BIOC_SVONLINE; + /* + * the stupid firmware doesnt care if a volume is degraded, + * just if it is working or not. go see if any disks are + * missing and figure out if it's degraded for ourselves. + */ + 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; + + for (i = 0; i < raidinfo->member_devices; i++) { + /* a missing disk shows up as 0xff */ + if (raidinfo->device_array[i] == 0xff) { + bv->bv_status = BIOC_SVDEGRADED; + break; + } + } + } else if (status & ARC_FW_VOL_STATUS_NEED_REGEN) + bv->bv_status = BIOC_SVDEGRADED; else if (status & ARC_FW_VOL_STATUS_FAILED) bv->bv_status = BIOC_SVOFFLINE; else if (status & ARC_FW_VOL_STATUS_INITTING) { @@ -1203,6 +1233,8 @@ arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv) } out: + arc_unlock(sc); + free(raidinfo, M_TEMP); free(volinfo, M_TEMP); return (error); } |