Annotation of sys/dev/i2o/ioprbs.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ioprbs.c,v 1.11 2006/11/28 23:59:45 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001 Niklas Hallqvist
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 26: * SUCH DAMAGE.
! 27: */
! 28:
! 29: /*-
! 30: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
! 31: * All rights reserved.
! 32: *
! 33: * This code is derived from software contributed to The NetBSD Foundation
! 34: * by Andrew Doran.
! 35: *
! 36: * Redistribution and use in source and binary forms, with or without
! 37: * modification, are permitted provided that the following conditions
! 38: * are met:
! 39: * 1. Redistributions of source code must retain the above copyright
! 40: * notice, this list of conditions and the following disclaimer.
! 41: * 2. Redistributions in binary form must reproduce the above copyright
! 42: * notice, this list of conditions and the following disclaimer in the
! 43: * documentation and/or other materials provided with the distribution.
! 44: * 3. All advertising materials mentioning features or use of this software
! 45: * must display the following acknowledgement:
! 46: * This product includes software developed by the NetBSD
! 47: * Foundation, Inc. and its contributors.
! 48: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 49: * contributors may be used to endorse or promote products derived
! 50: * from this software without specific prior written permission.
! 51: *
! 52: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 53: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 54: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 55: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 56: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 57: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 58: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 59: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 60: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 61: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 62: * POSSIBILITY OF SUCH DAMAGE.
! 63: */
! 64:
! 65: /*
! 66: * A driver for I2O "Random block storage" devices, like RAID.
! 67: */
! 68:
! 69: /*
! 70: * This driver would not have been written if it was not for the hardware
! 71: * donation from pi.se. I want to thank them for their support. It also
! 72: * had been much harder without Andrew Doran's work in NetBSD's ld_iop.c
! 73: * driver, from which I have both gotten inspiration and actual code.
! 74: * - Niklas Hallqvist
! 75: */
! 76:
! 77: #include <sys/param.h>
! 78: #include <sys/buf.h>
! 79: #include <sys/device.h>
! 80: #include <sys/kernel.h>
! 81: #include <sys/proc.h>
! 82: #include <sys/systm.h>
! 83:
! 84: #include <machine/bus.h>
! 85:
! 86: #include <scsi/scsi_all.h>
! 87: #include <scsi/scsi_disk.h>
! 88: #include <scsi/scsiconf.h>
! 89:
! 90: #include <dev/i2o/i2o.h>
! 91: #include <dev/i2o/iopio.h>
! 92: #include <dev/i2o/iopvar.h>
! 93: #include <dev/i2o/ioprbsvar.h>
! 94:
! 95: #ifdef I2ODEBUG
! 96: #define DPRINTF(x) printf x
! 97: #else
! 98: #define DPRINTF(x)
! 99: #endif
! 100:
! 101: void ioprbsminphys(struct buf *);
! 102: void ioprbs_adjqparam(struct device *, int);
! 103: void ioprbs_attach(struct device *, struct device *, void *);
! 104: void ioprbs_copy_internal_data(struct scsi_xfer *, u_int8_t *,
! 105: size_t);
! 106: struct scsi_xfer *ioprbs_dequeue(struct ioprbs_softc *);
! 107: void ioprbs_enqueue(struct ioprbs_softc *, struct scsi_xfer *, int);
! 108: void ioprbs_enqueue_ccb(struct ioprbs_softc *, struct ioprbs_ccb *);
! 109: int ioprbs_exec_ccb(struct ioprbs_ccb *);
! 110: void ioprbs_free_ccb(struct ioprbs_softc *, struct ioprbs_ccb *);
! 111: struct ioprbs_ccb *ioprbs_get_ccb(struct ioprbs_softc *, int);
! 112: void ioprbs_internal_cache_cmd(struct scsi_xfer *);
! 113: void ioprbs_intr(struct device *, struct iop_msg *, void *);
! 114: void ioprbs_intr_event(struct device *, struct iop_msg *, void *);
! 115: int ioprbs_match(struct device *, void *, void *);
! 116: int ioprbs_scsi_cmd(struct scsi_xfer *);
! 117: int ioprbs_start(struct ioprbs_ccb *);
! 118: void ioprbs_start_ccbs(struct ioprbs_softc *);
! 119: void ioprbs_timeout(void *);
! 120: void ioprbs_unconfig(struct ioprbs_softc *, int);
! 121: void ioprbs_watchdog(void *);
! 122:
! 123: struct cfdriver ioprbs_cd = {
! 124: NULL, "ioprbs", DV_DULL
! 125: };
! 126:
! 127: struct cfattach ioprbs_ca = {
! 128: sizeof(struct ioprbs_softc), ioprbs_match, ioprbs_attach
! 129: };
! 130:
! 131: struct scsi_adapter ioprbs_switch = {
! 132: ioprbs_scsi_cmd, ioprbsminphys, 0, 0,
! 133: };
! 134:
! 135: struct scsi_device ioprbs_dev = {
! 136: NULL, NULL, NULL, NULL
! 137: };
! 138:
! 139: #ifdef I2OVERBOSE
! 140: static const char *const ioprbs_errors[] = {
! 141: "success",
! 142: "media error",
! 143: "access error",
! 144: "device failure",
! 145: "device not ready",
! 146: "media not present",
! 147: "media locked",
! 148: "media failure",
! 149: "protocol failure",
! 150: "bus failure",
! 151: "access violation",
! 152: "media write protected",
! 153: "device reset",
! 154: "volume changed, waiting for acknowledgement",
! 155: "timeout",
! 156: };
! 157: #endif
! 158:
! 159: /*
! 160: * Match a supported device.
! 161: */
! 162: int
! 163: ioprbs_match(parent, match, aux)
! 164: struct device *parent;
! 165: void *match;
! 166: void *aux;
! 167: {
! 168: struct iop_attach_args *ia = aux;
! 169:
! 170: return (ia->ia_class == I2O_CLASS_RANDOM_BLOCK_STORAGE);
! 171: }
! 172:
! 173: /*
! 174: * Attach a supported device.
! 175: */
! 176: void
! 177: ioprbs_attach(struct device *parent, struct device *self, void *aux)
! 178: {
! 179: struct iop_attach_args *ia = aux;
! 180: struct ioprbs_softc *sc = (struct ioprbs_softc *)self;
! 181: struct iop_softc *iop = (struct iop_softc *)parent;
! 182: struct scsibus_attach_args saa;
! 183: int rv, state = 0;
! 184: int enable;
! 185: u_int32_t cachesz;
! 186: char *typestr, *fixedstr;
! 187: struct {
! 188: struct i2o_param_op_results pr;
! 189: struct i2o_param_read_results prr;
! 190: union {
! 191: struct i2o_param_rbs_cache_control cc;
! 192: struct i2o_param_rbs_device_info bdi;
! 193: struct i2o_param_rbs_operation op;
! 194: } p;
! 195: } param /* XXX gcc __attribute__ ((__packed__)) */;
! 196: int i;
! 197:
! 198: TAILQ_INIT(&sc->sc_free_ccb);
! 199: TAILQ_INIT(&sc->sc_ccbq);
! 200: LIST_INIT(&sc->sc_queue);
! 201:
! 202: /* Initialize the ccbs */
! 203: for (i = 0; i < IOPRBS_MAX_CCBS; i++)
! 204: TAILQ_INSERT_TAIL(&sc->sc_free_ccb, &sc->sc_ccbs[i],
! 205: ic_chain);
! 206:
! 207: /* Register us as an initiator. */
! 208: sc->sc_ii.ii_dv = self;
! 209: sc->sc_ii.ii_intr = ioprbs_intr;
! 210: sc->sc_ii.ii_adjqparam = ioprbs_adjqparam;
! 211: sc->sc_ii.ii_flags = 0;
! 212: sc->sc_ii.ii_tid = ia->ia_tid;
! 213: iop_initiator_register(iop, &sc->sc_ii);
! 214:
! 215: /* Register another initiator to handle events from the device. */
! 216: sc->sc_eventii.ii_dv = self;
! 217: sc->sc_eventii.ii_intr = ioprbs_intr_event;
! 218: sc->sc_eventii.ii_flags = II_DISCARD | II_UTILITY;
! 219: sc->sc_eventii.ii_tid = ia->ia_tid;
! 220: iop_initiator_register(iop, &sc->sc_eventii);
! 221:
! 222: rv = iop_util_eventreg(iop, &sc->sc_eventii,
! 223: I2O_EVENT_GEN_EVENT_MASK_MODIFIED | I2O_EVENT_GEN_DEVICE_RESET |
! 224: I2O_EVENT_GEN_STATE_CHANGE | I2O_EVENT_GEN_GENERAL_WARNING);
! 225: if (rv != 0) {
! 226: printf("%s: unable to register for events", self->dv_xname);
! 227: goto bad;
! 228: }
! 229: state++;
! 230:
! 231: /*
! 232: * Start out with one queued command. The `iop' driver will adjust
! 233: * the queue parameters once we're up and running.
! 234: */
! 235: sc->sc_maxqueuecnt = 1;
! 236:
! 237: sc->sc_maxxfer = IOP_MAX_XFER;
! 238:
! 239: /* Say what the device is. */
! 240: printf(":");
! 241: iop_print_ident(iop, ia->ia_tid);
! 242:
! 243: /*
! 244: * Claim the device so that we don't get any nasty surprises. Allow
! 245: * failure.
! 246: */
! 247: rv = iop_util_claim(iop, &sc->sc_ii, 0,
! 248: I2O_UTIL_CLAIM_CAPACITY_SENSITIVE |
! 249: I2O_UTIL_CLAIM_NO_PEER_SERVICE |
! 250: I2O_UTIL_CLAIM_NO_MANAGEMENT_SERVICE |
! 251: I2O_UTIL_CLAIM_PRIMARY_USER);
! 252: sc->sc_flags = rv ? 0 : IOPRBS_CLAIMED;
! 253:
! 254: rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_RBS_DEVICE_INFO,
! 255: ¶m, sizeof param);
! 256: if (rv != 0) {
! 257: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 258: sc->sc_dv.dv_xname, I2O_PARAM_RBS_DEVICE_INFO, rv);
! 259: goto bad;
! 260: }
! 261:
! 262: sc->sc_secsize = letoh32(param.p.bdi.blocksize);
! 263: sc->sc_secperunit = (int)
! 264: (letoh64(param.p.bdi.capacity) / sc->sc_secsize);
! 265:
! 266: switch (param.p.bdi.type) {
! 267: case I2O_RBS_TYPE_DIRECT:
! 268: typestr = "direct access";
! 269: enable = 1;
! 270: break;
! 271: case I2O_RBS_TYPE_WORM:
! 272: typestr = "WORM";
! 273: enable = 0;
! 274: break;
! 275: case I2O_RBS_TYPE_CDROM:
! 276: typestr = "CD-ROM";
! 277: enable = 0;
! 278: break;
! 279: case I2O_RBS_TYPE_OPTICAL:
! 280: typestr = "optical";
! 281: enable = 0;
! 282: break;
! 283: default:
! 284: typestr = "unknown";
! 285: enable = 0;
! 286: break;
! 287: }
! 288:
! 289: if ((letoh32(param.p.bdi.capabilities) & I2O_RBS_CAP_REMOVABLE_MEDIA)
! 290: != 0) {
! 291: /* sc->sc_flags = IOPRBS_REMOVABLE; */
! 292: fixedstr = "removable";
! 293: enable = 0;
! 294: } else
! 295: fixedstr = "fixed";
! 296:
! 297: printf(" %s, %s", typestr, fixedstr);
! 298:
! 299: /*
! 300: * Determine if the device has an private cache. If so, print the
! 301: * cache size. Even if the device doesn't appear to have a cache,
! 302: * we perform a flush at shutdown.
! 303: */
! 304: rv = iop_param_op(iop, ia->ia_tid, NULL, 0,
! 305: I2O_PARAM_RBS_CACHE_CONTROL, ¶m, sizeof(param));
! 306: if (rv != 0) {
! 307: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 308: sc->sc_dv.dv_xname, I2O_PARAM_RBS_CACHE_CONTROL, rv);
! 309: goto bad;
! 310: }
! 311:
! 312: if ((cachesz = letoh32(param.p.cc.totalcachesize)) != 0)
! 313: printf(", %dkB cache", cachesz >> 10);
! 314:
! 315: printf("\n");
! 316:
! 317: /*
! 318: * Configure the DDM's timeout functions to time out all commands
! 319: * after 30 seconds.
! 320: */
! 321: rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_RBS_OPERATION,
! 322: ¶m, sizeof(param));
! 323: if (rv != 0) {
! 324: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 325: sc->sc_dv.dv_xname, I2O_PARAM_RBS_OPERATION, rv);
! 326: goto bad;
! 327: }
! 328:
! 329: param.p.op.timeoutbase = htole32(IOPRBS_TIMEOUT * 1000);
! 330: param.p.op.rwvtimeoutbase = htole32(IOPRBS_TIMEOUT * 1000);
! 331: param.p.op.rwvtimeout = 0;
! 332:
! 333: rv = iop_param_op(iop, ia->ia_tid, NULL, 1, I2O_PARAM_RBS_OPERATION,
! 334: ¶m, sizeof(param));
! 335: #ifdef notdef
! 336: /*
! 337: * Intel RAID adapters don't like the above, but do post a
! 338: * `parameter changed' event. Perhaps we're doing something
! 339: * wrong...
! 340: */
! 341: if (rv != 0) {
! 342: printf("%s: unable to set parameters (0x%04x; %d)\n",
! 343: sc->sc_dv.dv_xname, I2O_PARAM_RBS_OPERATION, rv);
! 344: goto bad;
! 345: }
! 346: #endif
! 347:
! 348: if (enable)
! 349: sc->sc_flags |= IOPRBS_ENABLED;
! 350: else
! 351: printf("%s: device not yet supported\n", self->dv_xname);
! 352:
! 353: /* Fill in the prototype scsi_link. */
! 354: sc->sc_link.adapter_softc = sc;
! 355: sc->sc_link.adapter = &ioprbs_switch;
! 356: sc->sc_link.device = &ioprbs_dev;
! 357: sc->sc_link.openings = 1;
! 358: sc->sc_link.adapter_buswidth = 1;
! 359: sc->sc_link.adapter_target = 1;
! 360:
! 361: bzero(&saa, sizeof(saa));
! 362: saa.saa_sc_link = &sc->sc_link;
! 363:
! 364: config_found(&sc->sc_dv, &saa, scsiprint);
! 365:
! 366: return;
! 367:
! 368: bad:
! 369: ioprbs_unconfig(sc, state > 0);
! 370: }
! 371:
! 372: void
! 373: ioprbs_unconfig(struct ioprbs_softc *sc, int evreg)
! 374: {
! 375: struct iop_softc *iop;
! 376: int s;
! 377:
! 378: iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 379:
! 380: if ((sc->sc_flags & IOPRBS_CLAIMED) != 0)
! 381: iop_util_claim(iop, &sc->sc_ii, 1,
! 382: I2O_UTIL_CLAIM_PRIMARY_USER);
! 383:
! 384: if (evreg) {
! 385: /*
! 386: * Mask off events, and wait up to 5 seconds for a reply.
! 387: * Note that some adapters won't reply to this (XXX We
! 388: * should check the event capabilities).
! 389: */
! 390: sc->sc_flags &= ~IOPRBS_NEW_EVTMASK;
! 391: iop_util_eventreg(iop, &sc->sc_eventii,
! 392: I2O_EVENT_GEN_EVENT_MASK_MODIFIED);
! 393: s = splbio();
! 394: if ((sc->sc_flags & IOPRBS_NEW_EVTMASK) == 0)
! 395: tsleep(&sc->sc_eventii, PRIBIO, "ioprbsevt", hz * 5);
! 396: splx(s);
! 397: #ifdef I2ODEBUG
! 398: if ((sc->sc_flags & IOPRBS_NEW_EVTMASK) == 0)
! 399: printf("%s: didn't reply to event unregister",
! 400: sc->sc_dv.dv_xname);
! 401: #endif
! 402: }
! 403:
! 404: iop_initiator_unregister(iop, &sc->sc_eventii);
! 405: iop_initiator_unregister(iop, &sc->sc_ii);
! 406: }
! 407:
! 408: int
! 409: ioprbs_scsi_cmd(xs)
! 410: struct scsi_xfer *xs;
! 411: {
! 412: struct scsi_link *link = xs->sc_link;
! 413: struct ioprbs_softc *sc = link->adapter_softc;
! 414: struct ioprbs_ccb *ccb;
! 415: u_int32_t blockno, blockcnt;
! 416: struct scsi_rw *rw;
! 417: struct scsi_rw_big *rwb;
! 418: ioprbs_lock_t lock;
! 419: int retval = SUCCESSFULLY_QUEUED;
! 420:
! 421: lock = IOPRBS_LOCK(sc);
! 422:
! 423: /* Don't double enqueue if we came from ioprbs_chain. */
! 424: if (xs != LIST_FIRST(&sc->sc_queue))
! 425: ioprbs_enqueue(sc, xs, 0);
! 426:
! 427: while ((xs = ioprbs_dequeue(sc))) {
! 428: xs->error = XS_NOERROR;
! 429:
! 430: ccb = NULL;
! 431:
! 432: switch (xs->cmd->opcode) {
! 433: case TEST_UNIT_READY:
! 434: case REQUEST_SENSE:
! 435: case INQUIRY:
! 436: case MODE_SENSE:
! 437: case START_STOP:
! 438: case READ_CAPACITY:
! 439: #if 0
! 440: case VERIFY:
! 441: #endif
! 442: ioprbs_internal_cache_cmd(xs);
! 443: xs->flags |= ITSDONE;
! 444: scsi_done(xs);
! 445: goto ready;
! 446:
! 447: case PREVENT_ALLOW:
! 448: DPRINTF(("PREVENT/ALLOW "));
! 449: /* XXX Not yet implemented */
! 450: xs->error = XS_NOERROR;
! 451: xs->flags |= ITSDONE;
! 452: scsi_done(xs);
! 453: goto ready;
! 454:
! 455: case SYNCHRONIZE_CACHE:
! 456: DPRINTF(("SYNCHRONIZE_CACHE "));
! 457: /* XXX Not yet implemented */
! 458: xs->error = XS_NOERROR;
! 459: xs->flags |= ITSDONE;
! 460: scsi_done(xs);
! 461: goto ready;
! 462:
! 463: default:
! 464: DPRINTF(("unknown opc %d ", xs->cmd->opcode));
! 465: /* XXX Not yet implemented */
! 466: xs->error = XS_DRIVER_STUFFUP;
! 467: xs->flags |= ITSDONE;
! 468: scsi_done(xs);
! 469: goto ready;
! 470:
! 471: case READ_COMMAND:
! 472: case READ_BIG:
! 473: case WRITE_COMMAND:
! 474: case WRITE_BIG:
! 475: DPRINTF(("rw opc %d ", xs->cmd->opcode));
! 476:
! 477: if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
! 478: /* A read or write operation. */
! 479: if (xs->cmdlen == 6) {
! 480: rw = (struct scsi_rw *)xs->cmd;
! 481: blockno = _3btol(rw->addr) &
! 482: (SRW_TOPADDR << 16 | 0xffff);
! 483: blockcnt =
! 484: rw->length ? rw->length : 0x100;
! 485: } else {
! 486: rwb = (struct scsi_rw_big *)xs->cmd;
! 487: blockno = _4btol(rwb->addr);
! 488: blockcnt = _2btol(rwb->length);
! 489: }
! 490: if (blockno >= sc->sc_secperunit ||
! 491: blockno + blockcnt > sc->sc_secperunit) {
! 492: printf(
! 493: "%s: out of bounds %u-%u >= %u\n",
! 494: sc->sc_dv.dv_xname, blockno,
! 495: blockcnt, sc->sc_secperunit);
! 496: /*
! 497: * XXX Should be XS_SENSE but that
! 498: * would require setting up a faked
! 499: * sense too.
! 500: */
! 501: xs->error = XS_DRIVER_STUFFUP;
! 502: xs->flags |= ITSDONE;
! 503: scsi_done(xs);
! 504: goto ready;
! 505: }
! 506: }
! 507:
! 508: ccb = ioprbs_get_ccb(sc, xs->flags);
! 509:
! 510: /*
! 511: * We are out of commands, try again in a little while.
! 512: */
! 513: if (ccb == NULL) {
! 514: IOPRBS_UNLOCK(sc, lock);
! 515: return (TRY_AGAIN_LATER);
! 516: }
! 517:
! 518: ccb->ic_blockno = blockno;
! 519: ccb->ic_blockcnt = blockcnt;
! 520: ccb->ic_xs = xs;
! 521: ccb->ic_timeout = xs->timeout;
! 522:
! 523: ioprbs_enqueue_ccb(sc, ccb);
! 524:
! 525: /* XXX what if enqueue did not start a transfer? */
! 526: if (xs->flags & SCSI_POLL) {
! 527: #if 0
! 528: if (!ioprbs_wait(sc, ccb, ccb->ic_timeout)) {
! 529: IOPRBS_UNLOCK(sc, lock);
! 530: printf("%s: command timed out\n",
! 531: sc->sc_dv.dv_xname);
! 532: return (TRY_AGAIN_LATER);
! 533: }
! 534: xs->flags |= ITSDONE;
! 535: scsi_done(xs);
! 536: #endif
! 537: }
! 538: }
! 539:
! 540: ready:
! 541: /*
! 542: * Don't process the queue if we are polling.
! 543: */
! 544: if (xs->flags & SCSI_POLL) {
! 545: retval = COMPLETE;
! 546: break;
! 547: }
! 548: }
! 549:
! 550: IOPRBS_UNLOCK(sc, lock);
! 551: return (retval);
! 552: }
! 553:
! 554: void
! 555: ioprbsminphys(bp)
! 556: struct buf *bp;
! 557: {
! 558: minphys(bp);
! 559: }
! 560:
! 561: void
! 562: ioprbs_intr(struct device *dv, struct iop_msg *im, void *reply)
! 563: {
! 564: struct i2o_rbs_reply *rb = reply;
! 565: struct ioprbs_ccb *ccb = im->im_dvcontext;
! 566: struct buf *bp = ccb->ic_xs->bp;
! 567: struct ioprbs_softc *sc = (struct ioprbs_softc *)dv;
! 568: struct iop_softc *iop = (struct iop_softc *)dv->dv_parent;
! 569: int err, detail;
! 570: #ifdef I2OVERBOSE
! 571: const char *errstr;
! 572: #endif
! 573:
! 574: DPRINTF(("ioprbs_intr(%p, %p, %p) ", dv, im, reply));
! 575:
! 576: timeout_del(&ccb->ic_xs->stimeout);
! 577:
! 578: err = ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0);
! 579:
! 580: if (!err && rb->reqstatus != I2O_STATUS_SUCCESS) {
! 581: detail = letoh16(rb->detail);
! 582: #ifdef I2OVERBOSE
! 583: if (detail > sizeof(ioprbs_errors) / sizeof(ioprbs_errors[0]))
! 584: errstr = "<unknown>";
! 585: else
! 586: errstr = ioprbs_errors[detail];
! 587: printf("%s: error 0x%04x: %s\n", dv->dv_xname, detail, errstr);
! 588: #else
! 589: printf("%s: error 0x%04x\n", dv->dv_xname, detail);
! 590: #endif
! 591: err = 1;
! 592: }
! 593:
! 594: if (bp) {
! 595: if (err) {
! 596: bp->b_flags |= B_ERROR;
! 597: bp->b_error = EIO;
! 598: bp->b_resid = bp->b_bcount;
! 599: } else
! 600: bp->b_resid = bp->b_bcount - letoh32(rb->transfercount);
! 601: }
! 602:
! 603: iop_msg_unmap(iop, im);
! 604: iop_msg_free(iop, im);
! 605: scsi_done(ccb->ic_xs);
! 606: ioprbs_free_ccb(sc, ccb);
! 607: }
! 608:
! 609: void
! 610: ioprbs_intr_event(struct device *dv, struct iop_msg *im, void *reply)
! 611: {
! 612: struct i2o_util_event_register_reply *rb;
! 613: struct ioprbs_softc *sc;
! 614: u_int event;
! 615:
! 616: rb = reply;
! 617:
! 618: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0)
! 619: return;
! 620:
! 621: event = letoh32(rb->event);
! 622: sc = (struct ioprbs_softc *)dv;
! 623:
! 624: if (event == I2O_EVENT_GEN_EVENT_MASK_MODIFIED) {
! 625: sc->sc_flags |= IOPRBS_NEW_EVTMASK;
! 626: wakeup(&sc->sc_eventii);
! 627: #ifndef I2ODEBUG
! 628: return;
! 629: #endif
! 630: }
! 631:
! 632: printf("%s: event 0x%08x received\n", dv->dv_xname, event);
! 633: }
! 634:
! 635: void
! 636: ioprbs_adjqparam(struct device *dv, int mpi)
! 637: {
! 638: #if 0
! 639: struct iop_softc *iop;
! 640:
! 641: /*
! 642: * AMI controllers seem to lose the plot if you hand off lots of
! 643: * queued commands.
! 644: */
! 645: iop = (struct iop_softc *)dv->dv_parent;
! 646: if (letoh16(I2O_ORG_AMI) == iop->sc_status.orgid && mpi > 64)
! 647: mpi = 64;
! 648:
! 649: ldadjqparam((struct ld_softc *)dv, mpi);
! 650: #endif
! 651: }
! 652:
! 653: /*
! 654: * Insert a command into the driver queue, either at the front or at the tail.
! 655: * It's ok to overload the freelist link as these structures are never on
! 656: * the freelist at this time.
! 657: */
! 658: void
! 659: ioprbs_enqueue(sc, xs, infront)
! 660: struct ioprbs_softc *sc;
! 661: struct scsi_xfer *xs;
! 662: int infront;
! 663: {
! 664: if (infront || LIST_FIRST(&sc->sc_queue) == NULL) {
! 665: if (LIST_FIRST(&sc->sc_queue) == NULL)
! 666: sc->sc_queuelast = xs;
! 667: LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
! 668: return;
! 669: }
! 670: LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
! 671: sc->sc_queuelast = xs;
! 672: }
! 673:
! 674: /*
! 675: * Pull a command off the front of the driver queue.
! 676: */
! 677: struct scsi_xfer *
! 678: ioprbs_dequeue(sc)
! 679: struct ioprbs_softc *sc;
! 680: {
! 681: struct scsi_xfer *xs;
! 682:
! 683: xs = LIST_FIRST(&sc->sc_queue);
! 684: if (xs == NULL)
! 685: return (NULL);
! 686: LIST_REMOVE(xs, free_list);
! 687:
! 688: if (LIST_FIRST(&sc->sc_queue) == NULL)
! 689: sc->sc_queuelast = NULL;
! 690:
! 691: return (xs);
! 692: }
! 693:
! 694: void
! 695: ioprbs_copy_internal_data(xs, data, size)
! 696: struct scsi_xfer *xs;
! 697: u_int8_t *data;
! 698: size_t size;
! 699: {
! 700: size_t copy_cnt;
! 701:
! 702: DPRINTF(("ioprbs_copy_internal_data "));
! 703:
! 704: if (!xs->datalen)
! 705: printf("uio move not yet supported\n");
! 706: else {
! 707: copy_cnt = MIN(size, xs->datalen);
! 708: bcopy(data, xs->data, copy_cnt);
! 709: }
! 710: }
! 711:
! 712: /* Emulated SCSI operation on cache device */
! 713: void
! 714: ioprbs_internal_cache_cmd(xs)
! 715: struct scsi_xfer *xs;
! 716: {
! 717: struct scsi_link *link = xs->sc_link;
! 718: struct ioprbs_softc *sc = link->adapter_softc;
! 719: u_int8_t target = link->target;
! 720: struct scsi_inquiry_data inq;
! 721: struct scsi_sense_data sd;
! 722: struct scsi_read_cap_data rcd;
! 723:
! 724: DPRINTF(("ioprbs_internal_cache_cmd "));
! 725:
! 726: xs->error = XS_NOERROR;
! 727:
! 728: if (target > 0 || link->lun != 0) {
! 729: xs->error = XS_DRIVER_STUFFUP;
! 730: return;
! 731: }
! 732:
! 733: switch (xs->cmd->opcode) {
! 734: case TEST_UNIT_READY:
! 735: case START_STOP:
! 736: #if 0
! 737: case VERIFY:
! 738: #endif
! 739: DPRINTF(("opc %d tgt %d ", xs->cmd->opcode, target));
! 740: break;
! 741:
! 742: case REQUEST_SENSE:
! 743: DPRINTF(("REQUEST SENSE tgt %d ", target));
! 744: bzero(&sd, sizeof sd);
! 745: sd.error_code = 0x70;
! 746: sd.segment = 0;
! 747: sd.flags = SKEY_NO_SENSE;
! 748: bzero(sd.info, sizeof sd.info);
! 749: sd.extra_len = 0;
! 750: ioprbs_copy_internal_data(xs, (u_int8_t *)&sd, sizeof sd);
! 751: break;
! 752:
! 753: case INQUIRY:
! 754: DPRINTF(("INQUIRY tgt %d", target));
! 755: bzero(&inq, sizeof inq);
! 756: /* XXX How do we detect removable/CD-ROM devices? */
! 757: inq.device = T_DIRECT;
! 758: inq.dev_qual2 = 0;
! 759: inq.version = 2;
! 760: inq.response_format = 2;
! 761: inq.additional_length = 32;
! 762: strlcpy(inq.vendor, "I2O", sizeof inq.vendor);
! 763: snprintf(inq.product, sizeof inq.product, "Container #%02d",
! 764: target);
! 765: strlcpy(inq.revision, " ", sizeof inq.revision);
! 766: ioprbs_copy_internal_data(xs, (u_int8_t *)&inq, sizeof inq);
! 767: break;
! 768:
! 769: case READ_CAPACITY:
! 770: DPRINTF(("READ CAPACITY tgt %d ", target));
! 771: bzero(&rcd, sizeof rcd);
! 772: _lto4b(sc->sc_secperunit - 1, rcd.addr);
! 773: _lto4b(IOPRBS_BLOCK_SIZE, rcd.length);
! 774: ioprbs_copy_internal_data(xs, (u_int8_t *)&rcd, sizeof rcd);
! 775: break;
! 776:
! 777: default:
! 778: DPRINTF(("unsupported scsi command %#x tgt %d ",
! 779: xs->cmd->opcode, target));
! 780: xs->error = XS_DRIVER_STUFFUP;
! 781: return;
! 782: }
! 783:
! 784: xs->error = XS_NOERROR;
! 785: }
! 786:
! 787: struct ioprbs_ccb *
! 788: ioprbs_get_ccb(sc, flags)
! 789: struct ioprbs_softc *sc;
! 790: int flags;
! 791: {
! 792: struct ioprbs_ccb *ccb;
! 793: ioprbs_lock_t lock;
! 794:
! 795: DPRINTF(("ioprbs_get_ccb(%p, 0x%x) ", sc, flags));
! 796:
! 797: lock = IOPRBS_LOCK(sc);
! 798:
! 799: for (;;) {
! 800: ccb = TAILQ_FIRST(&sc->sc_free_ccb);
! 801: if (ccb != NULL)
! 802: break;
! 803: if (flags & SCSI_NOSLEEP)
! 804: goto bail_out;
! 805: tsleep(&sc->sc_free_ccb, PRIBIO, "ioprbs_ccb", 0);
! 806: }
! 807:
! 808: TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ic_chain);
! 809:
! 810: /* initialise the command */
! 811: ccb->ic_flags = 0;
! 812:
! 813: bail_out:
! 814: IOPRBS_UNLOCK(sc, lock);
! 815: return (ccb);
! 816: }
! 817:
! 818: void
! 819: ioprbs_free_ccb(sc, ccb)
! 820: struct ioprbs_softc *sc;
! 821: struct ioprbs_ccb *ccb;
! 822: {
! 823: ioprbs_lock_t lock;
! 824:
! 825: DPRINTF(("ioprbs_free_ccb(%p, %p) ", sc, ccb));
! 826:
! 827: lock = IOPRBS_LOCK(sc);
! 828:
! 829: TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, ic_chain);
! 830:
! 831: /* If the free list was empty, wake up potential waiters. */
! 832: if (TAILQ_NEXT(ccb, ic_chain) == NULL)
! 833: wakeup(&sc->sc_free_ccb);
! 834:
! 835: IOPRBS_UNLOCK(sc, lock);
! 836: }
! 837:
! 838: void
! 839: ioprbs_enqueue_ccb(sc, ccb)
! 840: struct ioprbs_softc *sc;
! 841: struct ioprbs_ccb *ccb;
! 842: {
! 843: DPRINTF(("ioprbs_enqueue_ccb(%p, %p) ", sc, ccb));
! 844:
! 845: timeout_set(&ccb->ic_xs->stimeout, ioprbs_timeout, ccb);
! 846: TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ic_chain);
! 847: ioprbs_start_ccbs(sc);
! 848: }
! 849:
! 850: void
! 851: ioprbs_start_ccbs(sc)
! 852: struct ioprbs_softc *sc;
! 853: {
! 854: struct ioprbs_ccb *ccb;
! 855: struct scsi_xfer *xs;
! 856:
! 857: DPRINTF(("ioprbs_start_ccbs(%p) ", sc));
! 858:
! 859: while ((ccb = TAILQ_FIRST(&sc->sc_ccbq)) != NULL) {
! 860:
! 861: xs = ccb->ic_xs;
! 862: if (ccb->ic_flags & IOPRBS_ICF_WATCHDOG)
! 863: timeout_del(&xs->stimeout);
! 864:
! 865: if (ioprbs_exec_ccb(ccb) == 0) {
! 866: ccb->ic_flags |= IOPRBS_ICF_WATCHDOG;
! 867: timeout_set(&ccb->ic_xs->stimeout, ioprbs_watchdog,
! 868: ccb);
! 869: timeout_add(&xs->stimeout,
! 870: (IOPRBS_WATCH_TIMEOUT * hz) / 1000);
! 871: break;
! 872: }
! 873: TAILQ_REMOVE(&sc->sc_ccbq, ccb, ic_chain);
! 874:
! 875: if ((xs->flags & SCSI_POLL) == 0) {
! 876: timeout_set(&ccb->ic_xs->stimeout, ioprbs_timeout,
! 877: ccb);
! 878: timeout_add(&xs->stimeout,
! 879: (ccb->ic_timeout * hz) / 1000);
! 880: }
! 881: }
! 882: }
! 883:
! 884: int
! 885: ioprbs_exec_ccb(ccb)
! 886: struct ioprbs_ccb *ccb;
! 887: {
! 888: struct scsi_xfer *xs = ccb->ic_xs;
! 889:
! 890: DPRINTF(("ioprbs_exec_ccb(%p, %p) ", xs, ccb));
! 891:
! 892: ioprbs_start(ccb);
! 893:
! 894: xs->error = XS_NOERROR;
! 895: xs->resid = 0;
! 896: return (1);
! 897: }
! 898:
! 899: /*
! 900: * Deliver a command to the controller; allocate controller resources at the
! 901: * last moment when possible.
! 902: */
! 903: int
! 904: ioprbs_start(struct ioprbs_ccb *ccb)
! 905: {
! 906: struct scsi_xfer *xs = ccb->ic_xs;
! 907: struct scsi_link *link = xs->sc_link;
! 908: struct ioprbs_softc *sc = link->adapter_softc;
! 909: #ifdef I2ODEBUG
! 910: u_int8_t target = link->target;
! 911: #endif
! 912: struct iop_msg *im;
! 913: struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 914: struct i2o_rbs_block_read *mf;
! 915: u_int rv, flags = 0, mode = I2O_RBS_BLOCK_READ;
! 916: u_int64_t ba;
! 917: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 918:
! 919: im = iop_msg_alloc(iop, &sc->sc_ii, 0);
! 920: im->im_dvcontext = ccb;
! 921:
! 922: switch (xs->cmd->opcode) {
! 923: case PREVENT_ALLOW:
! 924: case SYNCHRONIZE_CACHE:
! 925: if (xs->cmd->opcode == PREVENT_ALLOW) {
! 926: /* XXX PREVENT_ALLOW support goes here */
! 927: } else {
! 928: DPRINTF(("SYNCHRONIZE CACHE tgt %d ", target));
! 929: }
! 930: break;
! 931:
! 932: case WRITE_COMMAND:
! 933: case WRITE_BIG:
! 934: flags = I2O_RBS_BLOCK_WRITE_CACHE_WB;
! 935: mode = I2O_RBS_BLOCK_WRITE;
! 936: /* FALLTHROUGH */
! 937:
! 938: case READ_COMMAND:
! 939: case READ_BIG:
! 940: ba = (u_int64_t)ccb->ic_blockno * DEV_BSIZE;
! 941:
! 942: /*
! 943: * Fill the message frame. We can use the block_read
! 944: * structure for both reads and writes, as it's almost
! 945: * identical to the * block_write structure.
! 946: */
! 947: mf = (struct i2o_rbs_block_read *)mb;
! 948: mf->msgflags = I2O_MSGFLAGS(i2o_rbs_block_read);
! 949: mf->msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, mode);
! 950: mf->msgictx = sc->sc_ii.ii_ictx;
! 951: mf->msgtctx = im->im_tctx;
! 952: mf->flags = flags | (1 << 16); /* flags & time multiplier */
! 953: mf->datasize = ccb->ic_blockcnt * DEV_BSIZE;
! 954: mf->lowoffset = (u_int32_t)ba;
! 955: mf->highoffset = (u_int32_t)(ba >> 32);
! 956:
! 957: /* Map the data transfer and enqueue the command. */
! 958: rv = iop_msg_map_bio(iop, im, mb, xs->data,
! 959: ccb->ic_blockcnt * DEV_BSIZE, mode == I2O_RBS_BLOCK_WRITE);
! 960: if (rv == 0) {
! 961: if ((rv = iop_msg_post(iop, im, mb, 0)) != 0) {
! 962: iop_msg_unmap(iop, im);
! 963: iop_msg_free(iop, im);
! 964: }
! 965: }
! 966: break;
! 967: }
! 968: return (0);
! 969: }
! 970:
! 971: void
! 972: ioprbs_timeout(arg)
! 973: void *arg;
! 974: {
! 975: struct ioprbs_ccb *ccb = arg;
! 976: struct scsi_link *link = ccb->ic_xs->sc_link;
! 977: struct ioprbs_softc *sc = link->adapter_softc;
! 978: ioprbs_lock_t lock;
! 979:
! 980: sc_print_addr(link);
! 981: printf("timed out\n");
! 982:
! 983: /* XXX Test for multiple timeouts */
! 984:
! 985: ccb->ic_xs->error = XS_TIMEOUT;
! 986: lock = IOPRBS_LOCK(sc);
! 987: ioprbs_enqueue_ccb(sc, ccb);
! 988: IOPRBS_UNLOCK(sc, lock);
! 989: }
! 990:
! 991: void
! 992: ioprbs_watchdog(arg)
! 993: void *arg;
! 994: {
! 995: struct ioprbs_ccb *ccb = arg;
! 996: struct scsi_link *link = ccb->ic_xs->sc_link;
! 997: struct ioprbs_softc *sc = link->adapter_softc;
! 998: ioprbs_lock_t lock;
! 999:
! 1000: lock = IOPRBS_LOCK(sc);
! 1001: ccb->ic_flags &= ~IOPRBS_ICF_WATCHDOG;
! 1002: ioprbs_start_ccbs(sc);
! 1003: IOPRBS_UNLOCK(sc, lock);
! 1004: }
CVSweb