Annotation of sys/dev/ic/isp_openbsd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: isp_openbsd.c,v 1.30 2007/04/10 17:47:55 miod Exp $ */
! 2: /*
! 3: * Platform (OpenBSD) dependent common attachment code for Qlogic adapters.
! 4: *
! 5: * Copyright (c) 1999, 2000, 2001 by Matthew Jacob
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice immediately at the beginning of the file, without modification,
! 13: * this list of conditions, and the following disclaimer.
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 2. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
! 22: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: *
! 30: * The author may be reached via electronic communications at
! 31: *
! 32: * mjacob@feral.com
! 33: *
! 34: * or, via United States Postal Address
! 35: *
! 36: * Matthew Jacob
! 37: * Feral Software
! 38: * PMB#825
! 39: * 5214-F Diamond Heights Blvd.
! 40: * San Francisco, CA, 94131
! 41: */
! 42:
! 43: /* expand expensive inline functions here. */
! 44: #define EXPENSIVE_INLINE
! 45: #include <dev/ic/isp_openbsd.h>
! 46:
! 47: /*
! 48: * Set a timeout for the watchdogging of a command.
! 49: *
! 50: * The dimensional analysis is
! 51: *
! 52: * milliseconds * (seconds/millisecond) * (ticks/second) = ticks
! 53: *
! 54: * =
! 55: *
! 56: * (milliseconds / 1000) * hz = ticks
! 57: *
! 58: *
! 59: * For timeouts less than 1 second, we'll get zero. Because of this, and
! 60: * because we want to establish *our* timeout to be longer than what the
! 61: * firmware might do, we just add 3 seconds at the back end.
! 62: */
! 63: #define _XT(xs) ((((xs)->timeout/1000) * hz) + (3 * hz))
! 64:
! 65: static void ispminphys(struct buf *);
! 66: static int32_t ispcmd_slow(XS_T *);
! 67: static int32_t ispcmd(XS_T *);
! 68:
! 69: static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
! 70:
! 71: static int isp_polled_cmd (struct ispsoftc *, XS_T *);
! 72: static void isp_wdog (void *);
! 73: static void isp_requeue(void *);
! 74: static void isp_trestart(void *);
! 75: static void isp_restart(struct ispsoftc *);
! 76:
! 77: struct cfdriver isp_cd = {
! 78: NULL, "isp", DV_DULL
! 79: };
! 80:
! 81:
! 82: /*
! 83: * Complete attachment of hardware, include subdevices.
! 84: */
! 85: void
! 86: isp_attach(struct ispsoftc *isp)
! 87: {
! 88: struct scsibus_attach_args saa;
! 89: struct scsi_link *lptr = &isp->isp_osinfo._link[0];
! 90: isp->isp_osinfo._adapter.scsi_minphys = ispminphys;
! 91:
! 92: isp->isp_state = ISP_RUNSTATE;
! 93:
! 94: /*
! 95: * We only manage a single wait queues for dual bus controllers.
! 96: * This is arguably broken.
! 97: */
! 98: isp->isp_osinfo.wqf = isp->isp_osinfo.wqt = NULL;
! 99:
! 100: lptr->adapter_softc = isp;
! 101: lptr->device = &isp_dev;
! 102: lptr->adapter = &isp->isp_osinfo._adapter;
! 103: lptr->openings = imin(isp->isp_maxcmds, MAXISPREQUEST(isp));
! 104: isp->isp_osinfo._adapter.scsi_cmd = ispcmd_slow;
! 105: if (IS_FC(isp)) {
! 106: lptr->adapter_buswidth = MAX_FC_TARG;
! 107: /* We can set max lun width here */
! 108: /* loopid set below */
! 109: } else {
! 110: sdparam *sdp = isp->isp_param;
! 111: lptr->adapter_buswidth = MAX_TARGETS;
! 112: /* We can set max lun width here */
! 113: lptr->adapter_target = sdp->isp_initiator_id;
! 114: isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id;
! 115: if (IS_DUALBUS(isp)) {
! 116: struct scsi_link *lptrb = &isp->isp_osinfo._link[1];
! 117: lptrb->adapter_softc = isp;
! 118: lptrb->device = &isp_dev;
! 119: lptrb->adapter = &isp->isp_osinfo._adapter;
! 120: lptrb->openings = lptr->openings;
! 121: lptrb->adapter_buswidth = MAX_TARGETS;
! 122: lptrb->adapter_target = sdp->isp_initiator_id;
! 123: lptrb->flags = SDEV_2NDBUS;
! 124: isp->isp_osinfo.discovered[1] =
! 125: 1 << (sdp+1)->isp_initiator_id;
! 126: }
! 127: }
! 128:
! 129: /*
! 130: * Send a SCSI Bus Reset (used to be done as part of attach,
! 131: * but now left to the OS outer layers).
! 132: *
! 133: * We don't do 'bus resets' for FC because the LIP that occurs
! 134: * when we start the firmware does all that for us.
! 135: */
! 136: if (IS_SCSI(isp)) {
! 137: int bus = 0;
! 138: ISP_LOCK(isp);
! 139: (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
! 140: if (IS_DUALBUS(isp)) {
! 141: bus++;
! 142: (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
! 143: }
! 144: ISP_UNLOCK(isp);
! 145: /*
! 146: * wait for the bus to settle.
! 147: */
! 148: delay(4 * 1000000);
! 149: } else {
! 150: fcparam *fcp = isp->isp_param;
! 151: int defid = MAX_FC_TARG;
! 152: delay(2 * 1000000);
! 153: ISP_LOCK(isp);
! 154: isp_fc_runstate(isp, 10 * 1000000);
! 155: if (fcp->isp_fwstate == FW_READY &&
! 156: fcp->isp_loopstate >= LOOP_PDB_RCVD) {
! 157: defid = fcp->isp_loopid;
! 158: }
! 159: ISP_UNLOCK(isp);
! 160: lptr->adapter_target = defid;
! 161: }
! 162:
! 163: bzero(&saa, sizeof(saa));
! 164: saa.saa_sc_link = lptr;
! 165:
! 166: /*
! 167: * And attach children (if any).
! 168: */
! 169: config_found((void *)isp, &saa, scsiprint);
! 170: if (IS_DUALBUS(isp)) {
! 171: lptr++;
! 172: bzero(&saa, sizeof(saa));
! 173: saa.saa_sc_link = lptr;
! 174: config_found((void *)isp, &saa, scsiprint);
! 175: }
! 176: }
! 177:
! 178: /*
! 179: * minphys our xfers
! 180: *
! 181: * Unfortunately, the buffer pointer describes the target device- not the
! 182: * adapter device, so we can't use the pointer to find out what kind of
! 183: * adapter we are and adjust accordingly.
! 184: */
! 185:
! 186: static void
! 187: ispminphys(struct buf *bp)
! 188: {
! 189: /*
! 190: * XX: Only the 1020 has a 24 bit limit.
! 191: */
! 192: if (bp->b_bcount >= (1 << 24)) {
! 193: bp->b_bcount = (1 << 24);
! 194: }
! 195: minphys(bp);
! 196: }
! 197:
! 198: static int32_t
! 199: ispcmd_slow(XS_T *xs)
! 200: {
! 201: sdparam *sdp;
! 202: int tgt, chan;
! 203: u_int16_t f;
! 204: struct ispsoftc *isp = XS_ISP(xs);
! 205:
! 206: if (IS_FC(isp)) {
! 207: if (cold == 0) {
! 208: isp->isp_osinfo.no_mbox_ints = 0;
! 209: isp->isp_osinfo._adapter.scsi_cmd = ispcmd;
! 210: }
! 211: return (ispcmd(xs));
! 212: }
! 213:
! 214: /*
! 215: * Have we completed discovery for this target on this adapter?
! 216: */
! 217: sdp = isp->isp_param;
! 218: tgt = XS_TGT(xs);
! 219: chan = XS_CHANNEL(xs);
! 220: sdp += chan;
! 221: if ((xs->flags & SCSI_POLL) != 0 ||
! 222: (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) {
! 223: return (ispcmd(xs));
! 224: }
! 225: if (cold == 0) {
! 226: isp->isp_osinfo.no_mbox_ints = 0;
! 227: }
! 228:
! 229: f = DPARM_DEFAULT;
! 230: if (xs->sc_link->quirks & SDEV_NOSYNC) {
! 231: f &= ~DPARM_SYNC;
! 232: }
! 233: if (xs->sc_link->quirks & SDEV_NOWIDE) {
! 234: f &= ~DPARM_WIDE;
! 235: }
! 236: if (xs->sc_link->quirks & SDEV_NOTAGS) {
! 237: f &= ~DPARM_TQING;
! 238: }
! 239:
! 240: /*
! 241: * Okay, we know about this device now,
! 242: * so mark parameters to be updated for it.
! 243: */
! 244: sdp->isp_devparam[tgt].goal_flags = f;
! 245: sdp->isp_devparam[tgt].dev_update = 1;
! 246: isp->isp_update |= (1 << chan);
! 247:
! 248: /*
! 249: * Now check to see whether we can get out of this checking mode now.
! 250: * XXX: WE CANNOT AS YET BECAUSE THERE IS NO MECHANISM TO TELL US
! 251: * XXX: WHEN WE'RE DONE DISCOVERY BECAUSE WE NEED ONE COMMAND AFTER
! 252: * XXX: DISCOVERY IS DONE FOR EACH TARGET TO TELL US THAT WE'RE DONE
! 253: * XXX: AND THAT DOESN'T HAPPEN HERE. AT BEST WE CAN MARK OURSELVES
! 254: * XXX: DONE WITH DISCOVERY FOR THIS TARGET AND SO SAVE MAYBE 20
! 255: * XXX: LINES OF C CODE.
! 256: */
! 257: isp->isp_osinfo.discovered[chan] |= (1 << tgt);
! 258: /* do not bother with these lines- they'll never execute correctly */
! 259: #if 0
! 260: sdp = isp->isp_param;
! 261: for (chan = 0; chan < (IS_12X0(isp)? 2 : 1); chan++, sdp++) {
! 262: f = 0xffff & ~(1 << sdp->isp_initiator_id);
! 263: if (isp->isp_osinfo.discovered[chan] != f) {
! 264: break;
! 265: }
! 266: }
! 267: if (chan == (IS_12X0(isp)? 2 : 1)) {
! 268: isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
! 269: if (IS_12X0(isp))
! 270: isp->isp_update |= 2;
! 271: }
! 272: #endif
! 273: return (ispcmd(xs));
! 274: }
! 275:
! 276: static INLINE void isp_add2_blocked_queue(struct ispsoftc *, XS_T *);
! 277:
! 278: static INLINE void
! 279: isp_add2_blocked_queue(struct ispsoftc *isp, XS_T *xs)
! 280: {
! 281: if (isp->isp_osinfo.wqf != NULL) {
! 282: isp->isp_osinfo.wqt->free_list.le_next = xs;
! 283: } else {
! 284: isp->isp_osinfo.wqf = xs;
! 285: }
! 286: isp->isp_osinfo.wqt = xs;
! 287: xs->free_list.le_next = NULL;
! 288: }
! 289:
! 290: static int32_t
! 291: ispcmd(XS_T *xs)
! 292: {
! 293: struct ispsoftc *isp;
! 294: int result;
! 295:
! 296:
! 297: /*
! 298: * Make sure that there's *some* kind of sane setting.
! 299: */
! 300: isp = XS_ISP(xs);
! 301:
! 302: timeout_set(&xs->stimeout, isp_wdog, isp);
! 303:
! 304: if (XS_LUN(xs) >= isp->isp_maxluns) {
! 305: xs->error = XS_SELTIMEOUT;
! 306: return (COMPLETE);
! 307: }
! 308:
! 309: ISP_LOCK(isp);
! 310: if (isp->isp_state < ISP_RUNSTATE) {
! 311: DISABLE_INTS(isp);
! 312: isp_init(isp);
! 313: if (isp->isp_state != ISP_INITSTATE) {
! 314: ENABLE_INTS(isp);
! 315: ISP_UNLOCK(isp);
! 316: XS_SETERR(xs, HBA_BOTCH);
! 317: return (CMD_COMPLETE);
! 318: }
! 319: isp->isp_state = ISP_RUNSTATE;
! 320: ENABLE_INTS(isp);
! 321: }
! 322:
! 323: /*
! 324: * Check for queue blockage...
! 325: */
! 326: if (isp->isp_osinfo.blocked) {
! 327: if (xs->flags & SCSI_POLL) {
! 328: ISP_UNLOCK(isp);
! 329: return (TRY_AGAIN_LATER);
! 330: }
! 331: if (isp->isp_osinfo.blocked == 2) {
! 332: isp_restart(isp);
! 333: }
! 334: if (isp->isp_osinfo.blocked) {
! 335: isp_add2_blocked_queue(isp, xs);
! 336: ISP_UNLOCK(isp);
! 337: isp_prt(isp, ISP_LOGDEBUG0, "added to blocked queue");
! 338: return (SUCCESSFULLY_QUEUED);
! 339: }
! 340: }
! 341:
! 342: if (xs->flags & SCSI_POLL) {
! 343: volatile u_int8_t ombi = isp->isp_osinfo.no_mbox_ints;
! 344: isp->isp_osinfo.no_mbox_ints = 1;
! 345: result = isp_polled_cmd(isp, xs);
! 346: isp->isp_osinfo.no_mbox_ints = ombi;
! 347: ISP_UNLOCK(isp);
! 348: return (result);
! 349: }
! 350:
! 351: result = isp_start(xs);
! 352:
! 353: switch (result) {
! 354: case CMD_QUEUED:
! 355: result = SUCCESSFULLY_QUEUED;
! 356: if (xs->timeout) {
! 357: timeout_add(&xs->stimeout, _XT(xs));
! 358: XS_CMD_S_TIMER(xs);
! 359: }
! 360: if (isp->isp_osinfo.hiwater < isp->isp_nactive) {
! 361: isp->isp_osinfo.hiwater = isp->isp_nactive;
! 362: isp_prt(isp, ISP_LOGDEBUG0,
! 363: "Active Hiwater Mark=%d", isp->isp_nactive);
! 364: }
! 365: break;
! 366: case CMD_EAGAIN:
! 367: isp->isp_osinfo.blocked |= 2;
! 368: isp_prt(isp, ISP_LOGDEBUG0, "blocking queue");
! 369: isp_add2_blocked_queue(isp, xs);
! 370: result = SUCCESSFULLY_QUEUED;
! 371: break;
! 372: case CMD_RQLATER:
! 373: result = SUCCESSFULLY_QUEUED; /* Lie */
! 374: isp_prt(isp, ISP_LOGDEBUG1, "retrying later for %d.%d",
! 375: XS_TGT(xs), XS_LUN(xs));
! 376: timeout_set(&xs->stimeout, isp_requeue, xs);
! 377: timeout_add(&xs->stimeout, hz);
! 378: XS_CMD_S_TIMER(xs);
! 379: break;
! 380: case CMD_COMPLETE:
! 381: result = COMPLETE;
! 382: break;
! 383: }
! 384: ISP_UNLOCK(isp);
! 385: return (result);
! 386: }
! 387:
! 388: static int
! 389: isp_polled_cmd(struct ispsoftc *isp, XS_T *xs)
! 390: {
! 391: int result;
! 392: int infinite = 0, mswait;
! 393:
! 394: result = isp_start(xs);
! 395:
! 396: switch (result) {
! 397: case CMD_QUEUED:
! 398: result = SUCCESSFULLY_QUEUED;
! 399: break;
! 400: case CMD_RQLATER:
! 401: case CMD_EAGAIN:
! 402: result = TRY_AGAIN_LATER;
! 403: break;
! 404: case CMD_COMPLETE:
! 405: result = COMPLETE;
! 406: break;
! 407:
! 408: }
! 409:
! 410: if (result != SUCCESSFULLY_QUEUED) {
! 411: return (result);
! 412: }
! 413:
! 414: /*
! 415: * If we can't use interrupts, poll on completion.
! 416: */
! 417: if ((mswait = XS_TIME(xs)) == 0)
! 418: infinite = 1;
! 419:
! 420: while (mswait || infinite) {
! 421: u_int16_t isr, sema, mbox;
! 422: if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
! 423: isp_intr(isp, isr, sema, mbox);
! 424: if (XS_CMD_DONE_P(xs)) {
! 425: break;
! 426: }
! 427: }
! 428: USEC_DELAY(1000);
! 429: mswait -= 1;
! 430: }
! 431:
! 432: /*
! 433: * If no other error occurred but we didn't finish,
! 434: * something bad happened.
! 435: */
! 436: if (XS_CMD_DONE_P(xs) == 0) {
! 437: if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
! 438: isp_reinit(isp);
! 439: }
! 440: if (XS_NOERR(xs)) {
! 441: XS_SETERR(xs, HBA_BOTCH);
! 442: }
! 443: }
! 444: result = COMPLETE;
! 445: return (result);
! 446: }
! 447:
! 448: void
! 449: isp_done(XS_T *xs)
! 450: {
! 451: XS_CMD_S_DONE(xs);
! 452: if (XS_CMD_WDOG_P(xs) == 0) {
! 453: struct ispsoftc *isp = XS_ISP(xs);
! 454: if (XS_CMD_TIMER_P(xs)) {
! 455: timeout_del(&xs->stimeout);
! 456: XS_CMD_C_TIMER(xs);
! 457: }
! 458: if (XS_CMD_GRACE_P(xs)) {
! 459: struct ispsoftc *isp = XS_ISP(xs);
! 460: isp_prt(isp, ISP_LOGWARN,
! 461: "finished command on borrowed time");
! 462: }
! 463: XS_CMD_S_CLEAR(xs);
! 464: scsi_done(xs);
! 465: if (isp->isp_osinfo.blocked == 2) {
! 466: isp->isp_osinfo.blocked = 0;
! 467: isp_prt(isp, ISP_LOGDEBUG0, "restarting blocked queue");
! 468: isp_restart(isp);
! 469: }
! 470: }
! 471: }
! 472:
! 473: static void
! 474: isp_wdog(void *arg)
! 475: {
! 476: XS_T *xs = arg;
! 477: struct ispsoftc *isp = XS_ISP(xs);
! 478: u_int32_t handle;
! 479:
! 480: /*
! 481: * We've decided this command is dead. Make sure we're not trying
! 482: * to kill a command that's already dead by getting its handle and
! 483: * and seeing whether it's still alive.
! 484: */
! 485: ISP_LOCK(isp);
! 486: handle = isp_find_handle(isp, xs);
! 487: if (handle) {
! 488: u_int16_t isr, sema, mbox;
! 489:
! 490: if (XS_CMD_DONE_P(xs)) {
! 491: isp_prt(isp, ISP_LOGDEBUG1,
! 492: "watchdog found done cmd (handle 0x%x)",
! 493: handle);
! 494: ISP_UNLOCK(isp);
! 495: return;
! 496: }
! 497:
! 498: if (XS_CMD_WDOG_P(xs)) {
! 499: isp_prt(isp, ISP_LOGDEBUG1,
! 500: "recursive watchdog (handle 0x%x)",
! 501: handle);
! 502: ISP_UNLOCK(isp);
! 503: return;
! 504: }
! 505:
! 506: XS_CMD_S_WDOG(xs);
! 507:
! 508: if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
! 509: isp_intr(isp, isr, sema, mbox);
! 510: }
! 511:
! 512: if (XS_CMD_DONE_P(xs)) {
! 513: isp_prt(isp, ISP_LOGINFO,
! 514: "watchdog cleanup for handle 0x%x", handle);
! 515: XS_CMD_C_WDOG(xs);
! 516: isp_done(xs);
! 517: } else if (XS_CMD_GRACE_P(xs)) {
! 518: /*
! 519: * Make sure the command is *really* dead before we
! 520: * release the handle (and DMA resources) for reuse.
! 521: */
! 522: (void) isp_control(isp, ISPCTL_ABORT_CMD, arg);
! 523:
! 524: /*
! 525: * After this point, the command is really dead.
! 526: */
! 527: if (XS_XFRLEN(xs)) {
! 528: ISP_DMAFREE(isp, xs, handle);
! 529: }
! 530: isp_prt(isp, ISP_LOGWARN,
! 531: "watchdog timeout on handle %x", handle);
! 532: isp_destroy_handle(isp, handle);
! 533: XS_SETERR(xs, XS_TIMEOUT);
! 534: XS_CMD_S_CLEAR(xs);
! 535: isp_done(xs);
! 536: } else {
! 537: u_int16_t nxti, optr;
! 538: ispreq_t local, *mp = &local, *qe;
! 539:
! 540: isp_prt(isp, ISP_LOGWARN,
! 541: "possible command timeout on handle %x", handle);
! 542:
! 543: XS_CMD_C_WDOG(xs);
! 544: timeout_add(&xs->stimeout, _XT(xs));
! 545: XS_CMD_S_TIMER(xs);
! 546: if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) {
! 547: ISP_UNLOCK(isp);
! 548: return;
! 549: }
! 550: XS_CMD_S_GRACE(xs);
! 551: MEMZERO((void *) mp, sizeof (*mp));
! 552: mp->req_header.rqs_entry_count = 1;
! 553: mp->req_header.rqs_entry_type = RQSTYPE_MARKER;
! 554: mp->req_modifier = SYNC_ALL;
! 555: mp->req_target = XS_CHANNEL(xs) << 7;
! 556: isp_put_request(isp, mp, qe);
! 557: ISP_ADD_REQUEST(isp, nxti);
! 558: }
! 559: } else if (isp->isp_dblev) {
! 560: isp_prt(isp, ISP_LOGDEBUG1, "watchdog with no command");
! 561: }
! 562: ISP_UNLOCK(isp);
! 563: }
! 564:
! 565: /*
! 566: * Free any associated resources prior to decommissioning and
! 567: * set the card to a known state (so it doesn't wake up and kick
! 568: * us when we aren't expecting it to).
! 569: *
! 570: * Locks are held before coming here.
! 571: */
! 572: void
! 573: isp_uninit(struct ispsoftc *isp)
! 574: {
! 575: ISP_LOCK(isp);
! 576: /*
! 577: * Leave with interrupts disabled.
! 578: */
! 579: DISABLE_INTS(isp);
! 580:
! 581: ISP_UNLOCK(isp);
! 582: }
! 583:
! 584: /*
! 585: * Restart function for a command to be requeued later.
! 586: */
! 587: static void
! 588: isp_requeue(void *arg)
! 589: {
! 590: int r;
! 591: struct scsi_xfer *xs = arg;
! 592: struct ispsoftc *isp = XS_ISP(xs);
! 593: ISP_LOCK(isp);
! 594: r = isp_start(xs);
! 595: switch (r) {
! 596: case CMD_QUEUED:
! 597: isp_prt(isp, ISP_LOGDEBUG1, "restarted command for %d.%d",
! 598: XS_TGT(xs), XS_LUN(xs));
! 599: if (xs->timeout) {
! 600: timeout_set(&xs->stimeout, isp_wdog, isp);
! 601: timeout_add(&xs->stimeout, _XT(xs));
! 602: XS_CMD_S_TIMER(xs);
! 603: }
! 604: break;
! 605: case CMD_EAGAIN:
! 606: isp_prt(isp, ISP_LOGDEBUG0, "blocked cmd again");
! 607: isp->isp_osinfo.blocked |= 2;
! 608: isp_add2_blocked_queue(isp, xs);
! 609: break;
! 610: case CMD_RQLATER:
! 611: isp_prt(isp, ISP_LOGDEBUG0, "%s for %d.%d",
! 612: (r == CMD_EAGAIN)? "CMD_EAGAIN" : "CMD_RQLATER",
! 613: XS_TGT(xs), XS_LUN(xs));
! 614: timeout_set(&xs->stimeout, isp_requeue, xs);
! 615: timeout_add(&xs->stimeout, hz);
! 616: XS_CMD_S_TIMER(xs);
! 617: break;
! 618: case CMD_COMPLETE:
! 619: /* can only be an error */
! 620: if (XS_NOERR(xs))
! 621: XS_SETERR(xs, XS_DRIVER_STUFFUP);
! 622: isp_done(xs);
! 623: break;
! 624: }
! 625: ISP_UNLOCK(isp);
! 626: }
! 627:
! 628: /*
! 629: * Restart function after a LOOP UP event or a command completing,
! 630: * sometimes done as a timeout for some hysteresis.
! 631: */
! 632: static void
! 633: isp_trestart(void *arg)
! 634: {
! 635: struct ispsoftc *isp = arg;
! 636: struct scsi_xfer *list;
! 637:
! 638: ISP_LOCK(isp);
! 639: isp->isp_osinfo.rtpend = 0;
! 640: list = isp->isp_osinfo.wqf;
! 641: if (isp->isp_osinfo.blocked == 0 && list != NULL) {
! 642: int nrestarted = 0;
! 643:
! 644: isp->isp_osinfo.wqf = NULL;
! 645: ISP_UNLOCK(isp);
! 646: do {
! 647: struct scsi_xfer *xs = list;
! 648: list = xs->free_list.le_next;
! 649: xs->free_list.le_next = NULL;
! 650: isp_requeue(xs);
! 651: if (isp->isp_osinfo.wqf == NULL)
! 652: nrestarted++;
! 653: } while (list != NULL);
! 654: isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted);
! 655: } else {
! 656: ISP_UNLOCK(isp);
! 657: }
! 658: }
! 659:
! 660: static void
! 661: isp_restart(struct ispsoftc *isp)
! 662: {
! 663: struct scsi_xfer *list;
! 664:
! 665: list = isp->isp_osinfo.wqf;
! 666: if (isp->isp_osinfo.blocked == 0 && list != NULL) {
! 667: int nrestarted = 0;
! 668:
! 669: isp->isp_osinfo.wqf = NULL;
! 670: do {
! 671: struct scsi_xfer *xs = list;
! 672: list = xs->free_list.le_next;
! 673: xs->free_list.le_next = NULL;
! 674: isp_requeue(xs);
! 675: if (isp->isp_osinfo.wqf == NULL)
! 676: nrestarted++;
! 677: } while (list != NULL);
! 678: isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted);
! 679: }
! 680: }
! 681:
! 682: int
! 683: isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
! 684: {
! 685: int bus, tgt;
! 686:
! 687: switch (cmd) {
! 688: case ISPASYNC_NEW_TGT_PARAMS:
! 689: if (IS_SCSI(isp) && isp->isp_dblev) {
! 690: sdparam *sdp = isp->isp_param;
! 691: char *wt;
! 692: int mhz, flags, period;
! 693:
! 694: tgt = *((int *) arg);
! 695: bus = (tgt >> 16) & 0xffff;
! 696: tgt &= 0xffff;
! 697: sdp += bus;
! 698: flags = sdp->isp_devparam[tgt].actv_flags;
! 699: period = sdp->isp_devparam[tgt].actv_period;
! 700:
! 701: if ((flags & DPARM_SYNC) && period &&
! 702: (sdp->isp_devparam[tgt].actv_offset) != 0) {
! 703: /*
! 704: * There's some ambiguity about our negotiated speed
! 705: * if we haven't detected LVD mode correctly (which
! 706: * seems to happen, unfortunately). If we're in LVD
! 707: * mode, then different rules apply about speed.
! 708: */
! 709: if (sdp->isp_lvdmode || period < 0xc) {
! 710: switch (period) {
! 711: case 0x9:
! 712: mhz = 80;
! 713: break;
! 714: case 0xa:
! 715: mhz = 40;
! 716: break;
! 717: case 0xb:
! 718: mhz = 33;
! 719: break;
! 720: case 0xc:
! 721: mhz = 25;
! 722: break;
! 723: default:
! 724: mhz = 1000 / (period * 4);
! 725: break;
! 726: }
! 727: } else {
! 728: mhz = 1000 / (period * 4);
! 729: }
! 730: } else {
! 731: mhz = 0;
! 732: }
! 733: switch (flags & (DPARM_WIDE|DPARM_TQING)) {
! 734: case DPARM_WIDE:
! 735: wt = ", 16 bit wide";
! 736: break;
! 737: case DPARM_TQING:
! 738: wt = ", Tagged Queueing Enabled";
! 739: break;
! 740: case DPARM_WIDE|DPARM_TQING:
! 741: wt = ", 16 bit wide, Tagged Queueing Enabled";
! 742: break;
! 743: default:
! 744: wt = " ";
! 745: break;
! 746: }
! 747: if (mhz) {
! 748: isp_prt(isp, ISP_LOGINFO,
! 749: "Bus %d Target %d at %dMHz Max Offset %d%s",
! 750: bus, tgt, mhz, sdp->isp_devparam[tgt].actv_offset,
! 751: wt);
! 752: } else {
! 753: isp_prt(isp, ISP_LOGINFO,
! 754: "Bus %d Target %d Async Mode%s", bus, tgt, wt);
! 755: }
! 756: break;
! 757: }
! 758: case ISPASYNC_BUS_RESET:
! 759: if (arg)
! 760: bus = *((int *) arg);
! 761: else
! 762: bus = 0;
! 763: isp_prt(isp, ISP_LOGINFO, "SCSI bus %d reset detected", bus);
! 764: break;
! 765: case ISPASYNC_LOOP_DOWN:
! 766: /*
! 767: * Hopefully we get here in time to minimize the number
! 768: * of commands we are firing off that are sure to die.
! 769: */
! 770: isp->isp_osinfo.blocked |= 1;
! 771: isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
! 772: break;
! 773: case ISPASYNC_LOOP_UP:
! 774: isp->isp_osinfo.blocked &= ~1;
! 775: if (isp->isp_osinfo.rtpend == 0) {
! 776: timeout_set(&isp->isp_osinfo.rqt, isp_trestart, isp);
! 777: isp->isp_osinfo.rtpend = 1;
! 778: }
! 779: timeout_add(&isp->isp_osinfo.rqt, 1);
! 780: isp_prt(isp, ISP_LOGINFO, "Loop UP");
! 781: break;
! 782: case ISPASYNC_PROMENADE:
! 783: if (IS_FC(isp) && isp->isp_dblev) {
! 784: const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x "
! 785: "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x";
! 786: const static char *roles[4] = {
! 787: "No", "Target", "Initiator", "Target/Initiator"
! 788: };
! 789: fcparam *fcp = isp->isp_param;
! 790: int tgt = *((int *) arg);
! 791: struct lportdb *lp = &fcp->portdb[tgt];
! 792:
! 793: isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid,
! 794: roles[lp->roles & 0x3],
! 795: (lp->valid)? "Arrived" : "Departed",
! 796: (u_int32_t) (lp->port_wwn >> 32),
! 797: (u_int32_t) (lp->port_wwn & 0xffffffffLL),
! 798: (u_int32_t) (lp->node_wwn >> 32),
! 799: (u_int32_t) (lp->node_wwn & 0xffffffffLL));
! 800: break;
! 801: }
! 802: case ISPASYNC_CHANGE_NOTIFY:
! 803: if (arg == (void *) 1) {
! 804: isp_prt(isp, ISP_LOGINFO,
! 805: "Name Server Database Changed");
! 806: } else {
! 807: isp_prt(isp, ISP_LOGINFO,
! 808: "Name Server Database Changed");
! 809: }
! 810: break;
! 811: case ISPASYNC_FABRIC_DEV:
! 812: {
! 813: int target, base, lim;
! 814: fcparam *fcp = isp->isp_param;
! 815: struct lportdb *lp = NULL;
! 816: struct lportdb *clp = (struct lportdb *) arg;
! 817: char *pt;
! 818:
! 819: switch (clp->port_type) {
! 820: case 1:
! 821: pt = " N_Port";
! 822: break;
! 823: case 2:
! 824: pt = " NL_Port";
! 825: break;
! 826: case 3:
! 827: pt = "F/NL_Port";
! 828: break;
! 829: case 0x7f:
! 830: pt = " Nx_Port";
! 831: break;
! 832: case 0x81:
! 833: pt = " F_port";
! 834: break;
! 835: case 0x82:
! 836: pt = " FL_Port";
! 837: break;
! 838: case 0x84:
! 839: pt = " E_port";
! 840: break;
! 841: default:
! 842: pt = " ";
! 843: break;
! 844: }
! 845:
! 846: isp_prt(isp, ISP_LOGINFO,
! 847: "%s Fabric Device @ PortID 0x%x", pt, clp->portid);
! 848:
! 849: /*
! 850: * If we don't have an initiator role we bail.
! 851: *
! 852: * We just use ISPASYNC_FABRIC_DEV for announcement purposes.
! 853: */
! 854:
! 855: if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) {
! 856: break;
! 857: }
! 858:
! 859: /*
! 860: * Is this entry for us? If so, we bail.
! 861: */
! 862:
! 863: if (fcp->isp_portid == clp->portid) {
! 864: break;
! 865: }
! 866:
! 867: /*
! 868: * Else, the default policy is to find room for it in
! 869: * our local port database. Later, when we execute
! 870: * the call to isp_pdb_sync either this newly arrived
! 871: * or already logged in device will be (re)announced.
! 872: */
! 873:
! 874: if (fcp->isp_topo == TOPO_FL_PORT)
! 875: base = FC_SNS_ID+1;
! 876: else
! 877: base = 0;
! 878:
! 879: if (fcp->isp_topo == TOPO_N_PORT)
! 880: lim = 1;
! 881: else
! 882: lim = MAX_FC_TARG;
! 883:
! 884: /*
! 885: * Is it already in our list?
! 886: */
! 887: for (target = base; target < lim; target++) {
! 888: if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
! 889: continue;
! 890: }
! 891: lp = &fcp->portdb[target];
! 892: if (lp->port_wwn == clp->port_wwn &&
! 893: lp->node_wwn == clp->node_wwn) {
! 894: lp->fabric_dev = 1;
! 895: break;
! 896: }
! 897: }
! 898: if (target < lim) {
! 899: break;
! 900: }
! 901: for (target = base; target < lim; target++) {
! 902: if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
! 903: continue;
! 904: }
! 905: lp = &fcp->portdb[target];
! 906: if (lp->port_wwn == 0) {
! 907: break;
! 908: }
! 909: }
! 910: if (target == lim) {
! 911: isp_prt(isp, ISP_LOGWARN,
! 912: "out of space for fabric devices");
! 913: break;
! 914: }
! 915: lp->port_type = clp->port_type;
! 916: lp->fc4_type = clp->fc4_type;
! 917: lp->node_wwn = clp->node_wwn;
! 918: lp->port_wwn = clp->port_wwn;
! 919: lp->portid = clp->portid;
! 920: lp->fabric_dev = 1;
! 921: break;
! 922: }
! 923: case ISPASYNC_FW_CRASH:
! 924: {
! 925: u_int16_t mbox1, mbox6;
! 926: mbox1 = ISP_READ(isp, OUTMAILBOX1);
! 927: if (IS_DUALBUS(isp)) {
! 928: mbox6 = ISP_READ(isp, OUTMAILBOX6);
! 929: } else {
! 930: mbox6 = 0;
! 931: }
! 932: isp_prt(isp, ISP_LOGERR,
! 933: "Internal Firmware Error on bus %d @ RISC Address 0x%x",
! 934: mbox6, mbox1);
! 935: #ifdef ISP_FW_CRASH_DUMP
! 936: if (IS_FC(isp)) {
! 937: isp->isp_osinfo.blocked |= 1;
! 938: isp_fw_dump(isp);
! 939: }
! 940: isp_reinit(isp);
! 941: isp_async(isp, ISPASYNC_FW_RESTART, NULL);
! 942: #endif
! 943: break;
! 944: }
! 945: default:
! 946: break;
! 947: }
! 948: return (0);
! 949: }
! 950:
! 951: void
! 952: isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...)
! 953: {
! 954: va_list ap;
! 955: if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
! 956: return;
! 957: }
! 958: printf("%s: ", isp->isp_name);
! 959: va_start(ap, fmt);
! 960: vprintf(fmt, ap);
! 961: va_end(ap);
! 962: printf("\n");
! 963: }
CVSweb