diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2008-07-17 13:16:30 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2008-07-17 13:16:30 +0000 |
commit | 2adbce083b5957abfe218a36a4ce448dfe0ebbb9 (patch) | |
tree | 1c6524c215eb936310791e9d2da766c525c8dd04 /sys/dev/pci | |
parent | 2a617ec98b1bb0e73dd63cafaab4d04c84c5c6e6 (diff) |
Increase the size of the diskinfo struct, which has grown
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@
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/arc.c | 45 |
1 files changed, 32 insertions, 13 deletions
diff --git a/sys/dev/pci/arc.c b/sys/dev/pci/arc.c index eb6bb0fe971..4ab3d708ec7 100644 --- a/sys/dev/pci/arc.c +++ b/sys/dev/pci/arc.c @@ -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); |