Annotation of sys/dev/ic/isp_openbsd.c, Revision 1.1.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