-/* $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>
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 {
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);
}
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)
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)
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;
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;
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);
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;
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;
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;
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;
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;
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);