diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-10-18 20:24:11 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-10-18 20:24:11 +0000 |
commit | 24abbe046ff63dcc748d3ef22c051f98a72c72c4 (patch) | |
tree | cd5d48de677f168e276cf9b2db1b9719b1cba058 | |
parent | 02bff2e770cf30bed08a68301743697193f5e463 (diff) |
solve numerous problems:
- free up ccb before calling scsi_done;
- remove bogus tsleep/wakeup ccb availability mechanism;
- fix an off by one size reporting in read_capacity.
huge 10x to Alan Jones <RAJones@teklinks.com> and
teklinks for providing a testbed and his time for testing.
tests sustained 34 simultaneous tar zxvp at ldav of 76.
however 36 simultaneous bonnies hang the machine,
possibly for different reasons though.
regardless, this fixed version passes an installation alright.
-rw-r--r-- | sys/dev/ic/cac.c | 82 |
1 files changed, 35 insertions, 47 deletions
diff --git a/sys/dev/ic/cac.c b/sys/dev/ic/cac.c index 0bb2224ff0d..b1b983556b3 100644 --- a/sys/dev/ic/cac.c +++ b/sys/dev/ic/cac.c @@ -1,8 +1,8 @@ -/* $OpenBSD: cac.c,v 1.6 2001/08/16 17:26:51 brad Exp $ */ +/* $OpenBSD: cac.c,v 1.7 2001/10/18 20:24:10 mickey Exp $ */ /* $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $ */ /* - * Copyright (c) 2000 Michael Shalayeff + * Copyright (c) 2001 Michael Shalayeff * All rights reserved. * * The SCSI emulation layer is derived from gdt(4) driver, @@ -481,6 +481,7 @@ cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) printf("%s: invalid request\n", sc->sc_dv.dv_xname); } + cac_ccb_free(sc, ccb); if (xs) { if (error) xs->error = XS_DRIVER_STUFFUP; @@ -491,7 +492,6 @@ cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) scsi_done(xs); } - cac_ccb_free(sc, ccb); } /* @@ -504,19 +504,10 @@ cac_ccb_alloc(struct cac_softc *sc, int nosleep) int s; s = splbio(); - - for (;;) { - if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { - SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); - break; - } - if (nosleep) { - ccb = NULL; - break; - } - tsleep(&sc->sc_ccb_free, PRIBIO, "cacccb", 0); - } - + if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) + SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); + else + ccb = NULL; splx(s); return (ccb); } @@ -532,8 +523,6 @@ cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) ccb->ccb_flags = 0; s = splbio(); SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); - if (SIMPLEQ_NEXT(ccb, ccb_chain) == NULL) - wakeup(&sc->sc_ccb_free); splx(s); } @@ -599,7 +588,7 @@ cac_scsi_cmd(xs) u_int32_t blockno, blockcnt, size; struct scsi_rw *rw; struct scsi_rw_big *rwb; - int op, flags, s; + int op, flags, s, error; const char *p; if (target >= sc->sc_nunits || link->lun != 0) { @@ -697,7 +686,7 @@ cac_scsi_cmd(xs) } bzero(&rcd, sizeof rcd); _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) * - CAC_GET1(dinfo->nsectors), rcd.addr); + CAC_GET1(dinfo->nsectors) - 1, rcd.addr); _lto4b(CAC_SECTOR_SIZE, rcd.length); cac_copy_internal_data(xs, &rcd, sizeof rcd); break; @@ -723,30 +712,26 @@ cac_scsi_cmd(xs) s = splbio(); flags = 0; - if (xs->cmd->opcode != SYNCHRONIZE_CACHE) { - /* A read or write operation. */ - if (xs->cmdlen == 6) { - rw = (struct scsi_rw *)xs->cmd; - blockno = _3btol(rw->addr) & - (SRW_TOPADDR << 16 | 0xffff); - blockcnt = rw->length ? rw->length : 0x100; - } else { - rwb = (struct scsi_rw_big *)xs->cmd; - blockno = _4btol(rwb->addr); - blockcnt = _2btol(rwb->length); - } - size = CAC_GET2(dinfo->ncylinders) * - CAC_GET1(dinfo->nheads) * - CAC_GET1(dinfo->nsectors); - if (blockno >= size || blockno + blockcnt > size) { - splx(s); - printf("%s: out of bounds %u-%u >= %u\n", - sc->sc_dv.dv_xname, blockno, blockcnt, - size); - xs->error = XS_DRIVER_STUFFUP; - scsi_done(xs); - return (COMPLETE); - } + /* A read or write operation. */ + if (xs->cmdlen == 6) { + rw = (struct scsi_rw *)xs->cmd; + blockno = _3btol(rw->addr) & + (SRW_TOPADDR << 16 | 0xffff); + blockcnt = rw->length ? rw->length : 0x100; + } else { + rwb = (struct scsi_rw_big *)xs->cmd; + blockno = _4btol(rwb->addr); + blockcnt = _2btol(rwb->length); + } + size = CAC_GET2(dinfo->ncylinders) * + CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors); + if (blockno >= size || blockno + blockcnt > size) { + splx(s); + printf("%s: out of bounds %u-%u >= %u\n", + sc->sc_dv.dv_xname, blockno, blockcnt, size); + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); } switch (xs->cmd->opcode) { @@ -762,11 +747,14 @@ cac_scsi_cmd(xs) break; } - if (cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, target, - blockno, flags, xs)) { + if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, + target, blockno, flags, xs))) { splx(s); - if (xs->flags & SCSI_POLL) { + if (error == ENOMEM) { + xs->error = XS_DRIVER_STUFFUP; + return (TRY_AGAIN_LATER); + } else if (xs->flags & SCSI_POLL) { xs->error = XS_TIMEOUT; return (TRY_AGAIN_LATER); } else { |