Increase the size of the diskinfo struct, which has grown
authorjsg <jsg@openbsd.org>
Thu, 17 Jul 2008 13:16:29 +0000 (13:16 +0000)
committerjsg <jsg@openbsd.org>
Thu, 17 Jul 2008 13:16:29 +0000 (13:16 +0000)
4 bytes in the new firmware.

To allow this to work on older firmwares add a "short read allowed"
flag to arc_msgbuf(), which will allow short reads by getting
the read length from the header of the response the firmware sends.

Only set the flag on the arc_msgbuf() call that deals with the diskinfo
struct for now.

Discussed with and ok dlg@

sys/dev/pci/arc.c

index eb6bb0f..4ab3d70 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: arc.c,v 1.76 2008/06/27 12:04:29 jsg Exp $ */
+/*     $OpenBSD: arc.c,v 1.77 2008/07/17 13:16:29 jsg Exp $ */
 
 /*
  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -301,7 +301,7 @@ struct arc_fw_diskinfo {
        u_int8_t                drive_select;
        u_int8_t                raid_number; // 0xff unowned
        struct arc_fw_scsiattr  scsi_attr;
-       u_int8_t                reserved[40];
+       u_int8_t                reserved[44];
 } __packed;
 
 struct arc_fw_sysinfo {
@@ -483,7 +483,7 @@ void                        arc_unlock(struct arc_softc *);
 void                   arc_wait(struct arc_softc *);
 u_int8_t               arc_msg_cksum(void *, u_int16_t);
 int                    arc_msgbuf(struct arc_softc *, void *, size_t,
-                           void *, size_t);
+                           void *, size_t, int);
 
 /* bioctl */
 int                    arc_bioctl(struct device *, u_long, caddr_t);
@@ -1120,7 +1120,7 @@ arc_bio_alarm(struct arc_softc *sc, struct bioc_alarm *ba)
        }
 
        arc_lock(sc);
-       error = arc_msgbuf(sc, request, len, reply, sizeof(reply));
+       error = arc_msgbuf(sc, request, len, reply, sizeof(reply), 0);
        arc_unlock(sc);
 
        if (error != 0)
@@ -1149,7 +1149,7 @@ arc_bio_alarm_state(struct arc_softc *sc, struct bioc_alarm *ba)
 
        arc_lock(sc);
        error = arc_msgbuf(sc, &request, sizeof(request),
-           sysinfo, sizeof(struct arc_fw_sysinfo));
+           sysinfo, sizeof(struct arc_fw_sysinfo), 0);
        arc_unlock(sc);
 
        if (error != 0)
@@ -1179,7 +1179,7 @@ arc_bio_inq(struct arc_softc *sc, struct bioc_inq *bi)
 
        request[0] = ARC_FW_SYSINFO;
        error = arc_msgbuf(sc, request, 1, sysinfo,
-           sizeof(struct arc_fw_sysinfo));
+           sizeof(struct arc_fw_sysinfo), 0);
        if (error != 0)
                goto out;
 
@@ -1189,7 +1189,7 @@ arc_bio_inq(struct arc_softc *sc, struct bioc_inq *bi)
        for (i = 0; i < maxvols; i++) {
                request[1] = i;
                error = arc_msgbuf(sc, request, sizeof(request), volinfo,
-                   sizeof(struct arc_fw_volinfo));
+                   sizeof(struct arc_fw_volinfo), 0);
                if (error != 0)
                        goto out;
 
@@ -1236,7 +1236,7 @@ arc_bio_blink(struct arc_softc *sc, struct bioc_blink *blink)
        mask = htole32(sc->sc_ledmask);
        bcopy(&mask, &request[2], 3);
 
-       error = arc_msgbuf(sc, request, sizeof(request), NULL, 0);
+       error = arc_msgbuf(sc, request, sizeof(request), NULL, 0, 0);
        if (error)
                return (EIO);
 
@@ -1255,7 +1255,7 @@ arc_bio_getvol(struct arc_softc *sc, int vol, struct arc_fw_volinfo *volinfo)
 
        request[0] = ARC_FW_SYSINFO;
        error = arc_msgbuf(sc, request, 1, sysinfo,
-           sizeof(struct arc_fw_sysinfo));
+           sizeof(struct arc_fw_sysinfo), 0);
        if (error != 0)
                goto out;
 
@@ -1265,7 +1265,7 @@ arc_bio_getvol(struct arc_softc *sc, int vol, struct arc_fw_volinfo *volinfo)
        for (i = 0; i < maxvols; i++) {
                request[1] = i;
                error = arc_msgbuf(sc, request, sizeof(request), volinfo,
-                   sizeof(struct arc_fw_volinfo));
+                   sizeof(struct arc_fw_volinfo), 0);
                if (error != 0)
                        goto out;
 
@@ -1396,7 +1396,7 @@ arc_bio_disk(struct arc_softc *sc, struct bioc_disk *bd)
        request[0] = ARC_FW_RAIDINFO;
        request[1] = volinfo->raid_set_number;
        error = arc_msgbuf(sc, request, sizeof(request), raidinfo,
-           sizeof(struct arc_fw_raidinfo));
+           sizeof(struct arc_fw_raidinfo), 0);
        if (error != 0)
                goto out;
 
@@ -1421,7 +1421,7 @@ arc_bio_disk(struct arc_softc *sc, struct bioc_disk *bd)
        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));
+           sizeof(struct arc_fw_diskinfo), 1);
        if (error != 0)
                goto out;
 
@@ -1477,11 +1477,12 @@ arc_msg_cksum(void *cmd, u_int16_t len)
 
 int
 arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wbuflen, void *rptr,
-    size_t rbuflen)
+    size_t rbuflen, int sreadok)
 {
        u_int8_t                        rwbuf[ARC_RA_IOC_RWBUF_MAXLEN];
        u_int8_t                        *wbuf, *rbuf;
        int                             wlen, wdone = 0, rlen, rdone = 0;
+       u_int16_t                       rlenhdr = 0;
        struct arc_fw_bufhdr            *bufhdr;
        u_int32_t                       reg, rwlen;
        int                             error = 0;
@@ -1583,6 +1584,24 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wbuflen, void *rptr,
 
                        bcopy(rwbuf, &rbuf[rdone], rwlen);
                        rdone += rwlen;
+
+                       /*
+                        * Allow for short reads, by reading the length
+                        * value from the response header and shrinking our
+                        * idea of size, if required.
+                        * This deals with the growth of diskinfo struct from
+                        * 128 to 132 bytes.
+                        */ 
+                       if (sreadok && rdone >= sizeof(struct arc_fw_bufhdr) &&
+                           rlenhdr == 0) {
+                               bufhdr = (struct arc_fw_bufhdr *)rbuf;
+                               rlenhdr = letoh16(bufhdr->len);
+                               if (rlenhdr < rbuflen) {
+                                       rbuflen = rlenhdr;
+                                       rlen = sizeof(struct arc_fw_bufhdr) +
+                                           rbuflen + 1; /* 1 for cksum */
+                               }
+                       }
                }
        } while (rdone != rlen);