xref: /netbsd-src/sys/dev/ic/isp_netbsd.c (revision e4d7c2e329d54c97e0c0bd3016bbe74f550c3d5e)
1 /* $NetBSD: isp_netbsd.c,v 1.23 2000/02/12 02:25:28 mjacob Exp $ */
2 /*
3  * Platform (NetBSD) dependent common attachment code for Qlogic adapters.
4  * Matthew Jacob <mjacob@nas.nasa.gov>
5  */
6 /*
7  * Copyright (C) 1997, 1998, 1999 National Aeronautics & Space Administration
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <dev/ic/isp_netbsd.h>
34 #include <sys/scsiio.h>
35 
36 static void ispminphys __P((struct buf *));
37 static int32_t ispcmd_slow __P((ISP_SCSI_XFER_T *));
38 static int32_t ispcmd __P((ISP_SCSI_XFER_T *));
39 static int
40 ispioctl __P((struct scsipi_link *, u_long, caddr_t, int, struct proc *));
41 
42 static struct scsipi_device isp_dev = { NULL, NULL, NULL, NULL };
43 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
44 static void isp_watch __P((void *));
45 static void isp_command_requeue __P((void *));
46 static void isp_internal_restart __P((void *));
47 
48 /*
49  * Complete attachment of hardware, include subdevices.
50  */
51 void
52 isp_attach(isp)
53 	struct ispsoftc *isp;
54 {
55 
56 	isp->isp_osinfo._adapter.scsipi_minphys = ispminphys;
57 	isp->isp_osinfo._adapter.scsipi_ioctl = ispioctl;
58 
59 	isp->isp_state = ISP_RUNSTATE;
60 	isp->isp_osinfo._link.scsipi_scsi.channel =
61 	    (IS_DUALBUS(isp))? 0 : SCSI_CHANNEL_ONLY_ONE;
62 	isp->isp_osinfo._link.adapter_softc = isp;
63 	isp->isp_osinfo._link.device = &isp_dev;
64 	isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
65 	isp->isp_osinfo._link.openings = isp->isp_maxcmds;
66 	TAILQ_INIT(&isp->isp_osinfo.waitq);	/* XXX 2nd Bus? */
67 
68 	if (IS_FC(isp)) {
69 		/*
70 		 * Give it another chance here to come alive...
71 		 */
72 		isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
73 		isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1;
74 #ifdef	ISP2100_SCCLUN
75 		/*
76 		 * 16 bits worth, but let's be reasonable..
77 		 */
78 		isp->isp_osinfo._link.scsipi_scsi.max_lun = 255;
79 #else
80 		isp->isp_osinfo._link.scsipi_scsi.max_lun = 15;
81 #endif
82 		/* set below */
83 	} else {
84 		sdparam *sdp = isp->isp_param;
85 		isp->isp_osinfo._adapter.scsipi_cmd = ispcmd_slow;
86 		isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1;
87 		isp->isp_osinfo._link.scsipi_scsi.max_lun = 7;
88 		isp->isp_osinfo._link.scsipi_scsi.adapter_target =
89 		    sdp->isp_initiator_id;
90 		isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id;
91 		if (IS_DUALBUS(isp)) {
92 			isp->isp_osinfo._link_b = isp->isp_osinfo._link;
93 			sdp++;
94 			isp->isp_osinfo.discovered[1] =
95 			    1 << sdp->isp_initiator_id;
96 			isp->isp_osinfo._link_b.scsipi_scsi.adapter_target =
97 			    sdp->isp_initiator_id;
98 			isp->isp_osinfo._link_b.scsipi_scsi.channel = 1;
99 		}
100 	}
101 	isp->isp_osinfo._link.type = BUS_SCSI;
102 
103 	/*
104 	 * Send a SCSI Bus Reset (used to be done as part of attach,
105 	 * but now left to the OS outer layers).
106 	 */
107 	if (IS_SCSI(isp)) {
108 		int bus = 0;
109 		(void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
110 		if (IS_DUALBUS(isp)) {
111 			bus++;
112 			(void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
113 		}
114 		SYS_DELAY(2*1000000);
115 	} else {
116 		int i, j;
117 		fcparam *fcp = isp->isp_param;
118 		delay(2 * 1000000);
119 		for (j = 0; j < 5; j++) {
120 			for (i = 0; i < 5; i++) {
121 				if (isp_control(isp, ISPCTL_FCLINK_TEST, NULL))
122 					continue;
123 #ifdef	ISP2100_FABRIC
124 				/*
125 				 * Wait extra time to see if the f/w
126 				 * eventually completed an FLOGI that
127 				 * will allow us to know we're on a
128 				 * fabric.
129 				 */
130 				if (fcp->isp_onfabric == 0) {
131 					delay(1 * 1000000);
132 					continue;
133 				}
134 #endif
135 				break;
136 			}
137 			if (fcp->isp_fwstate == FW_READY &&
138 			    fcp->isp_loopstate >= LOOP_PDB_RCVD) {
139 				break;
140 			}
141 		}
142 		isp->isp_osinfo._link.scsipi_scsi.adapter_target =
143 			fcp->isp_loopid;
144 	}
145 
146 	/*
147 	 * Start the watchdog.
148 	 */
149 	isp->isp_dogactive = 1;
150 	timeout(isp_watch, isp, WATCH_INTERVAL * hz);
151 
152 	/*
153 	 * And attach children (if any).
154 	 */
155 	config_found((void *)isp, &isp->isp_osinfo._link, scsiprint);
156 	if (IS_DUALBUS(isp)) {
157 		config_found((void *)isp, &isp->isp_osinfo._link_b, scsiprint);
158 	}
159 }
160 
161 /*
162  * minphys our xfers
163  *
164  * Unfortunately, the buffer pointer describes the target device- not the
165  * adapter device, so we can't use the pointer to find out what kind of
166  * adapter we are and adjust accordingly.
167  */
168 
169 static void
170 ispminphys(bp)
171 	struct buf *bp;
172 {
173 	/*
174 	 * XX: Only the 1020 has a 24 bit limit.
175 	 */
176 	if (bp->b_bcount >= (1 << 24)) {
177 		bp->b_bcount = (1 << 24);
178 	}
179 	minphys(bp);
180 }
181 
182 static int32_t
183 ispcmd_slow(xs)
184 	ISP_SCSI_XFER_T *xs;
185 {
186 	sdparam *sdp;
187 	int tgt, chan, s;
188 	u_int16_t flags;
189 	struct ispsoftc *isp = XS_ISP(xs);
190 
191 	/*
192 	 * Have we completed discovery for this target on this adapter?
193 	 */
194 	tgt = XS_TGT(xs);
195 	chan = XS_CHANNEL(xs);
196 	if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 ||
197 	    (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) {
198 		return (ispcmd(xs));
199 	}
200 
201 	flags = DPARM_DEFAULT;
202 	if (xs->sc_link->quirks & SDEV_NOSYNC) {
203 		flags ^= DPARM_SYNC;
204 #ifdef	DEBUG
205 	} else {
206 		printf("%s: channel %d target %d can do SYNC xfers\n",
207 		    isp->isp_name, chan, tgt);
208 #endif
209 	}
210 	if (xs->sc_link->quirks & SDEV_NOWIDE) {
211 		flags ^= DPARM_WIDE;
212 #ifdef	DEBUG
213 	} else {
214 		printf("%s: channel %d target %d can do WIDE xfers\n",
215 		    isp->isp_name, chan, tgt);
216 #endif
217 	}
218 	if (xs->sc_link->quirks & SDEV_NOTAG) {
219 		flags ^= DPARM_TQING;
220 #ifdef	DEBUG
221 	} else {
222 		printf("%s: channel %d target %d can do TAGGED xfers\n",
223 		    isp->isp_name, chan, tgt);
224 #endif
225 	}
226 	/*
227 	 * Okay, we know about this device now,
228 	 * so mark parameters to be updated for it.
229 	 */
230 	s = splbio();
231 	isp->isp_osinfo.discovered[chan] |= (1 << tgt);
232 	sdp = isp->isp_param;
233 	sdp += chan;
234 	sdp->isp_devparam[tgt].dev_flags = flags;
235 	sdp->isp_devparam[tgt].dev_update = 1;
236 	isp->isp_update |= (1 << chan);
237 	splx(s);
238 	return (ispcmd(xs));
239 }
240 
241 static int
242 ispioctl(sc_link, cmd, addr, flag, p)
243 	struct scsipi_link *sc_link;
244 	u_long cmd;
245 	caddr_t addr;
246 	int flag;
247 	struct proc *p;
248 {
249 	struct ispsoftc *isp = sc_link->adapter_softc;
250 	int s, chan, retval = ENOTTY;
251 
252 	switch (cmd) {
253 	case SCBUSIORESET:
254 		chan = sc_link->scsipi_scsi.channel;
255 		s = splbio();
256 		if (isp_control(isp, ISPCTL_RESET_BUS, &chan))
257 			retval = EIO;
258 		else
259 			retval = 0;
260 		(void) splx(s);
261 		break;
262 	default:
263 		break;
264 	}
265 	return (retval);
266 }
267 
268 
269 static int32_t
270 ispcmd(xs)
271 	ISP_SCSI_XFER_T *xs;
272 {
273 	struct ispsoftc *isp;
274 	int result, s;
275 
276 	isp = XS_ISP(xs);
277 	s = splbio();
278 	if (isp->isp_state < ISP_RUNSTATE) {
279 		DISABLE_INTS(isp);
280 		isp_init(isp);
281                 if (isp->isp_state != ISP_INITSTATE) {
282 			ENABLE_INTS(isp);
283                         (void) splx(s);
284                         XS_SETERR(xs, HBA_BOTCH);
285                         return (COMPLETE);
286                 }
287                 isp->isp_state = ISP_RUNSTATE;
288 		ENABLE_INTS(isp);
289         }
290 
291 	/*
292 	 * Check for queue blockage...
293 	 */
294 	if (isp->isp_osinfo.blocked) {
295 		if (xs->xs_control & XS_CTL_POLL) {
296 			xs->error = XS_DRIVER_STUFFUP;
297 			splx(s);
298 			return (TRY_AGAIN_LATER);
299 		}
300 		TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs, adapter_q);
301 		splx(s);
302 		return (SUCCESSFULLY_QUEUED);
303 	}
304 	DISABLE_INTS(isp);
305 	result = ispscsicmd(xs);
306 	ENABLE_INTS(isp);
307 
308 	if ((xs->xs_control & XS_CTL_POLL) == 0) {
309 		switch (result) {
310 		case CMD_QUEUED:
311 			result = SUCCESSFULLY_QUEUED;
312 			break;
313 		case CMD_EAGAIN:
314 			result = TRY_AGAIN_LATER;
315 			break;
316 		case CMD_RQLATER:
317 			result = SUCCESSFULLY_QUEUED;
318 			timeout(isp_command_requeue, xs, hz);
319 			break;
320 		case CMD_COMPLETE:
321 			result = COMPLETE;
322 			break;
323 		}
324 		(void) splx(s);
325 		return (result);
326 	}
327 
328 	switch (result) {
329 	case CMD_QUEUED:
330 		result = SUCCESSFULLY_QUEUED;
331 		break;
332 	case CMD_RQLATER:
333 	case CMD_EAGAIN:
334 		if (XS_NOERR(xs)) {
335 			xs->error = XS_DRIVER_STUFFUP;
336 		}
337 		result = TRY_AGAIN_LATER;
338 		break;
339 	case CMD_COMPLETE:
340 		result = COMPLETE;
341 		break;
342 
343 	}
344 	/*
345 	 * If we can't use interrupts, poll on completion.
346 	 */
347 	if (result == SUCCESSFULLY_QUEUED) {
348 		if (isp_poll(isp, xs, XS_TIME(xs))) {
349 			/*
350 			 * If no other error occurred but we didn't finish,
351 			 * something bad happened.
352 			 */
353 			if (XS_IS_CMD_DONE(xs) == 0) {
354 				if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
355 					isp_restart(isp);
356 				}
357 				if (XS_NOERR(xs)) {
358 					XS_SETERR(xs, HBA_BOTCH);
359 				}
360 			}
361 		}
362 		result = COMPLETE;
363 	}
364 	(void) splx(s);
365 	return (result);
366 }
367 
368 static int
369 isp_poll(isp, xs, mswait)
370 	struct ispsoftc *isp;
371 	ISP_SCSI_XFER_T *xs;
372 	int mswait;
373 {
374 
375 	while (mswait) {
376 		/* Try the interrupt handling routine */
377 		(void)isp_intr((void *)isp);
378 
379 		/* See if the xs is now done */
380 		if (XS_IS_CMD_DONE(xs)) {
381 			return (0);
382 		}
383 		SYS_DELAY(1000);	/* wait one millisecond */
384 		mswait--;
385 	}
386 	return (1);
387 }
388 
389 static void
390 isp_watch(arg)
391 	void *arg;
392 {
393 	int i;
394 	struct ispsoftc *isp = arg;
395 	struct scsipi_xfer *xs;
396 	int s;
397 
398 	/*
399 	 * Look for completely dead commands (but not polled ones).
400 	 */
401 	s = splbio();
402 	for (i = 0; i < isp->isp_maxcmds; i++) {
403 		xs = isp->isp_xflist[i];
404 		if (xs == NULL) {
405 			continue;
406 		}
407 		if (xs->timeout == 0 || (xs->xs_control & XS_CTL_POLL)) {
408 			continue;
409 		}
410 		xs->timeout -= (WATCH_INTERVAL * 1000);
411 		/*
412 		 * Avoid later thinking that this
413 		 * transaction is not being timed.
414 		 * Then give ourselves to watchdog
415 		 * periods of grace.
416 		 */
417 		if (xs->timeout == 0) {
418 			xs->timeout = 1;
419 		} else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) {
420 			continue;
421 		}
422 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
423 			printf("%s: isp_watch failed to abort command\n",
424 			    isp->isp_name);
425 			isp_restart(isp);
426 			break;
427 		}
428 	}
429 	timeout(isp_watch, isp, WATCH_INTERVAL * hz);
430 	isp->isp_dogactive = 1;
431 	(void) splx(s);
432 }
433 
434 /*
435  * Free any associated resources prior to decommissioning and
436  * set the card to a known state (so it doesn't wake up and kick
437  * us when we aren't expecting it to).
438  *
439  * Locks are held before coming here.
440  */
441 void
442 isp_uninit(isp)
443 	struct ispsoftc *isp;
444 {
445 	ISP_ILOCKVAL_DECL;
446 	ISP_ILOCK(isp);
447 	/*
448 	 * Leave with interrupts disabled.
449 	 */
450 	DISABLE_INTS(isp);
451 
452 	/*
453 	 * Turn off the watchdog (if active).
454 	 */
455 	if (isp->isp_dogactive) {
456 		untimeout(isp_watch, isp);
457 		isp->isp_dogactive = 0;
458 	}
459 
460 	ISP_IUNLOCK(isp);
461 }
462 
463 /*
464  * Restart function for a command to be requeued later.
465  */
466 static void
467 isp_command_requeue(arg)
468 	void *arg;
469 {
470 	struct scsipi_xfer *xs = arg;
471 	struct ispsoftc *isp = XS_ISP(xs);
472 	int s = splbio();
473 	switch (ispcmd_slow(xs)) {
474 	case SUCCESSFULLY_QUEUED:
475 		printf("%s: isp_command_requeue: requeued for %d.%d\n",
476 		    isp->isp_name, XS_TGT(xs), XS_LUN(xs));
477 		break;
478 	case TRY_AGAIN_LATER:
479 		printf("%s: EAGAIN for %d.%d\n",
480 		    isp->isp_name, XS_TGT(xs), XS_LUN(xs));
481 		/* FALLTHROUGH */
482 	case COMPLETE:
483 		/* can only be an error */
484 		xs->xs_status |= XS_STS_DONE;
485 		if (XS_NOERR(xs)) {
486 			XS_SETERR(xs, HBA_BOTCH);
487 		}
488 		scsipi_done(xs);
489 		break;
490 	}
491 	(void) splx(s);
492 }
493 
494 /*
495  * Restart function after a LOOP UP event (e.g.),
496  * done as a timeout for some hysteresis.
497  */
498 static void
499 isp_internal_restart(arg)
500 	void *arg;
501 {
502 	struct ispsoftc *isp = arg;
503 	int result, nrestarted = 0, s;
504 
505 	s = splbio();
506 	if (isp->isp_osinfo.blocked == 0) {
507 		struct scsipi_xfer *xs;
508 		while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) {
509 			TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, adapter_q);
510 			DISABLE_INTS(isp);
511 			result = ispscsicmd(xs);
512 			ENABLE_INTS(isp);
513 			if (result != CMD_QUEUED) {
514 				printf("%s: botched command restart (0x%x)\n",
515 				    isp->isp_name, result);
516 				xs->xs_status |= XS_STS_DONE;
517 				if (xs->error == XS_NOERROR)
518 					xs->error = XS_DRIVER_STUFFUP;
519 				scsipi_done(xs);
520 			}
521 			nrestarted++;
522 		}
523 		printf("%s: requeued %d commands\n", isp->isp_name, nrestarted);
524 	}
525 	(void) splx(s);
526 }
527 
528 int
529 isp_async(isp, cmd, arg)
530 	struct ispsoftc *isp;
531 	ispasync_t cmd;
532 	void *arg;
533 {
534 	int bus, tgt;
535 	int s = splbio();
536 	switch (cmd) {
537 	case ISPASYNC_NEW_TGT_PARAMS:
538 	if (IS_SCSI(isp) && isp->isp_dblev) {
539 		sdparam *sdp = isp->isp_param;
540 		char *wt;
541 		int mhz, flags, period;
542 
543 		tgt = *((int *) arg);
544 		bus = (tgt >> 16) & 0xffff;
545 		tgt &= 0xffff;
546 		sdp += bus;
547 		flags = sdp->isp_devparam[tgt].cur_dflags;
548 		period = sdp->isp_devparam[tgt].cur_period;
549 
550 		if ((flags & DPARM_SYNC) && period &&
551 		    (sdp->isp_devparam[tgt].cur_offset) != 0) {
552 #if	0
553 			/* CAUSES PANICS */
554 			static char *m = "%s: bus %d now %s mode\n";
555 			u_int16_t r, l;
556 			if (bus == 1)
557 				r = SXP_PINS_DIFF | SXP_BANK1_SELECT;
558 			else
559 				r = SXP_PINS_DIFF;
560 			l = ISP_READ(isp, r) & ISP1080_MODE_MASK;
561 			switch (l) {
562 			case ISP1080_LVD_MODE:
563 				sdp->isp_lvdmode = 1;
564 				printf(m, isp->isp_name, bus, "LVD");
565 				break;
566 			case ISP1080_HVD_MODE:
567 				sdp->isp_diffmode = 1;
568 				printf(m, isp->isp_name, bus, "Differential");
569 				break;
570 			case ISP1080_SE_MODE:
571 				sdp->isp_ultramode = 1;
572 				printf(m, isp->isp_name, bus, "Single-Ended");
573 				break;
574 			default:
575 				printf("%s: unknown mode on bus %d (0x%x)\n",
576 				    isp->isp_name, bus, l);
577 				break;
578 			}
579 #endif
580 			/*
581 			 * There's some ambiguity about our negotiated speed
582 			 * if we haven't detected LVD mode correctly (which
583 			 * seems to happen, unfortunately). If we're in LVD
584 			 * mode, then different rules apply about speed.
585 			 */
586 			if (sdp->isp_lvdmode || period < 0xc) {
587 				switch (period) {
588 				case 0x9:
589 					mhz = 80;
590 					break;
591 				case 0xa:
592 					mhz = 40;
593 					break;
594 				case 0xb:
595 					mhz = 33;
596 					break;
597 				case 0xc:
598 					mhz = 25;
599 					break;
600 				default:
601 					mhz = 1000 / (period * 4);
602 					break;
603 				}
604 			} else {
605 				mhz = 1000 / (period * 4);
606 			}
607 		} else {
608 			mhz = 0;
609 		}
610 		switch (flags & (DPARM_WIDE|DPARM_TQING)) {
611 		case DPARM_WIDE:
612 			wt = ", 16 bit wide\n";
613 			break;
614 		case DPARM_TQING:
615 			wt = ", Tagged Queueing Enabled\n";
616 			break;
617 		case DPARM_WIDE|DPARM_TQING:
618 			wt = ", 16 bit wide, Tagged Queueing Enabled\n";
619 			break;
620 		default:
621 			wt = "\n";
622 			break;
623 		}
624 		if (mhz) {
625 			CFGPRINTF("%s: Bus %d Target %d at %dMHz Max "
626 			    "Offset %d%s", isp->isp_name, bus, tgt, mhz,
627 			    sdp->isp_devparam[tgt].cur_offset, wt);
628 		} else {
629 			CFGPRINTF("%s: Bus %d Target %d Async Mode%s",
630 			    isp->isp_name, bus, tgt, wt);
631 		}
632 		break;
633 	}
634 	case ISPASYNC_BUS_RESET:
635 		if (arg)
636 			bus = *((int *) arg);
637 		else
638 			bus = 0;
639 		printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus);
640 		break;
641 	case ISPASYNC_LOOP_DOWN:
642 		/*
643 		 * Hopefully we get here in time to minimize the number
644 		 * of commands we are firing off that are sure to die.
645 		 */
646 		isp->isp_osinfo.blocked = 1;
647 		printf("%s: Loop DOWN\n", isp->isp_name);
648 		break;
649         case ISPASYNC_LOOP_UP:
650 		isp->isp_osinfo.blocked = 0;
651 		timeout(isp_internal_restart, isp, 1);
652 		printf("%s: Loop UP\n", isp->isp_name);
653 		break;
654 	case ISPASYNC_PDB_CHANGED:
655 	if (IS_FC(isp) && isp->isp_dblev) {
656 		const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
657 		    "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
658 		const static char *roles[4] = {
659 		    "No", "Target", "Initiator", "Target/Initiator"
660 		};
661 		char *ptr;
662 		fcparam *fcp = isp->isp_param;
663 		int tgt = *((int *) arg);
664 		struct lportdb *lp = &fcp->portdb[tgt];
665 
666 		if (lp->valid) {
667 			ptr = "arrived";
668 		} else {
669 			ptr = "disappeared";
670 		}
671 		printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
672 		    roles[lp->roles & 0x3], ptr,
673 		    (u_int32_t) (lp->port_wwn >> 32),
674 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
675 		    (u_int32_t) (lp->node_wwn >> 32),
676 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
677 		break;
678 	}
679 #ifdef	ISP2100_FABRIC
680 	case ISPASYNC_CHANGE_NOTIFY:
681 		printf("%s: Name Server Database Changed\n", isp->isp_name);
682 		break;
683 	case ISPASYNC_FABRIC_DEV:
684 	{
685 		int target;
686 		struct lportdb *lp;
687 		sns_scrsp_t *resp = (sns_scrsp_t *) arg;
688 		u_int32_t portid;
689 		u_int64_t wwn;
690 		fcparam *fcp = isp->isp_param;
691 
692 		portid =
693 		    (((u_int32_t) resp->snscb_port_id[0]) << 16) |
694 		    (((u_int32_t) resp->snscb_port_id[1]) << 8) |
695 		    (((u_int32_t) resp->snscb_port_id[2]));
696 		wwn =
697 		    (((u_int64_t)resp->snscb_portname[0]) << 56) |
698 		    (((u_int64_t)resp->snscb_portname[1]) << 48) |
699 		    (((u_int64_t)resp->snscb_portname[2]) << 40) |
700 		    (((u_int64_t)resp->snscb_portname[3]) << 32) |
701 		    (((u_int64_t)resp->snscb_portname[4]) << 24) |
702 		    (((u_int64_t)resp->snscb_portname[5]) << 16) |
703 		    (((u_int64_t)resp->snscb_portname[6]) <<  8) |
704 		    (((u_int64_t)resp->snscb_portname[7]));
705 		printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN "
706 		    "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type,
707 		    portid, ((u_int32_t)(wwn >> 32)),
708 		    ((u_int32_t)(wwn & 0xffffffff)));
709 		if (resp->snscb_port_type != 2)
710 			break;
711 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
712 			lp = &fcp->portdb[target];
713 			if (lp->port_wwn == wwn)
714 				break;
715 		}
716 		if (target < MAX_FC_TARG) {
717 			break;
718 		}
719 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
720 			lp = &fcp->portdb[target];
721 			if (lp->port_wwn == 0)
722 				break;
723 		}
724 		if (target == MAX_FC_TARG) {
725 			printf("%s: no more space for fabric devices\n",
726 			    isp->isp_name);
727 			return (-1);
728 		}
729 		lp->port_wwn = lp->node_wwn = wwn;
730 		lp->portid = portid;
731 		break;
732 	}
733 #endif
734 	default:
735 		break;
736 	}
737 	(void) splx(s);
738 	return (0);
739 }
740