summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2006-08-27 11:29:46 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2006-08-27 11:29:46 +0000
commitbbf58ae93c16e99e757b90f5df94e4bbaa54278e (patch)
tree628d40d38eebe52512fd2f0f49a1d8d87ac0ed6b
parent3303f585d297012ea36ee41c57e5dc4364683642 (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.c38
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);
}