isp_netbsd.c revision 1.22 1 /* $NetBSD: isp_netbsd.c,v 1.22 1999/12/20 00:38:21 mjacob Exp $ */
2 /*
3 * Platform (NetBSD) dependent common attachment code for Qlogic adapters.
4 * Matthew Jacob <mjacob (at) 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 0xa:
589 mhz = 40;
590 break;
591 case 0xb:
592 mhz = 33;
593 break;
594 case 0xc:
595 mhz = 25;
596 break;
597 default:
598 mhz = 1000 / (period * 4);
599 break;
600 }
601 } else {
602 mhz = 1000 / (period * 4);
603 }
604 } else {
605 mhz = 0;
606 }
607 switch (flags & (DPARM_WIDE|DPARM_TQING)) {
608 case DPARM_WIDE:
609 wt = ", 16 bit wide\n";
610 break;
611 case DPARM_TQING:
612 wt = ", Tagged Queueing Enabled\n";
613 break;
614 case DPARM_WIDE|DPARM_TQING:
615 wt = ", 16 bit wide, Tagged Queueing Enabled\n";
616 break;
617 default:
618 wt = "\n";
619 break;
620 }
621 if (mhz) {
622 CFGPRINTF("%s: Bus %d Target %d at %dMHz Max "
623 "Offset %d%s", isp->isp_name, bus, tgt, mhz,
624 sdp->isp_devparam[tgt].cur_offset, wt);
625 } else {
626 CFGPRINTF("%s: Bus %d Target %d Async Mode%s",
627 isp->isp_name, bus, tgt, wt);
628 }
629 break;
630 }
631 case ISPASYNC_BUS_RESET:
632 if (arg)
633 bus = *((int *) arg);
634 else
635 bus = 0;
636 printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus);
637 break;
638 case ISPASYNC_LOOP_DOWN:
639 /*
640 * Hopefully we get here in time to minimize the number
641 * of commands we are firing off that are sure to die.
642 */
643 isp->isp_osinfo.blocked = 1;
644 printf("%s: Loop DOWN\n", isp->isp_name);
645 break;
646 case ISPASYNC_LOOP_UP:
647 isp->isp_osinfo.blocked = 0;
648 timeout(isp_internal_restart, isp, 1);
649 printf("%s: Loop UP\n", isp->isp_name);
650 break;
651 case ISPASYNC_PDB_CHANGED:
652 if (IS_FC(isp) && isp->isp_dblev) {
653 const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
654 "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
655 const static char *roles[4] = {
656 "No", "Target", "Initiator", "Target/Initiator"
657 };
658 char *ptr;
659 fcparam *fcp = isp->isp_param;
660 int tgt = *((int *) arg);
661 struct lportdb *lp = &fcp->portdb[tgt];
662
663 if (lp->valid) {
664 ptr = "arrived";
665 } else {
666 ptr = "disappeared";
667 }
668 printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
669 roles[lp->roles & 0x3], ptr,
670 (u_int32_t) (lp->port_wwn >> 32),
671 (u_int32_t) (lp->port_wwn & 0xffffffffLL),
672 (u_int32_t) (lp->node_wwn >> 32),
673 (u_int32_t) (lp->node_wwn & 0xffffffffLL));
674 break;
675 }
676 #ifdef ISP2100_FABRIC
677 case ISPASYNC_CHANGE_NOTIFY:
678 printf("%s: Name Server Database Changed\n", isp->isp_name);
679 break;
680 case ISPASYNC_FABRIC_DEV:
681 {
682 int target;
683 struct lportdb *lp;
684 sns_scrsp_t *resp = (sns_scrsp_t *) arg;
685 u_int32_t portid;
686 u_int64_t wwn;
687 fcparam *fcp = isp->isp_param;
688
689 portid =
690 (((u_int32_t) resp->snscb_port_id[0]) << 16) |
691 (((u_int32_t) resp->snscb_port_id[1]) << 8) |
692 (((u_int32_t) resp->snscb_port_id[2]));
693 wwn =
694 (((u_int64_t)resp->snscb_portname[0]) << 56) |
695 (((u_int64_t)resp->snscb_portname[1]) << 48) |
696 (((u_int64_t)resp->snscb_portname[2]) << 40) |
697 (((u_int64_t)resp->snscb_portname[3]) << 32) |
698 (((u_int64_t)resp->snscb_portname[4]) << 24) |
699 (((u_int64_t)resp->snscb_portname[5]) << 16) |
700 (((u_int64_t)resp->snscb_portname[6]) << 8) |
701 (((u_int64_t)resp->snscb_portname[7]));
702 printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN "
703 "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type,
704 portid, ((u_int32_t)(wwn >> 32)),
705 ((u_int32_t)(wwn & 0xffffffff)));
706 if (resp->snscb_port_type != 2)
707 break;
708 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
709 lp = &fcp->portdb[target];
710 if (lp->port_wwn == wwn)
711 break;
712 }
713 if (target < MAX_FC_TARG) {
714 break;
715 }
716 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
717 lp = &fcp->portdb[target];
718 if (lp->port_wwn == 0)
719 break;
720 }
721 if (target == MAX_FC_TARG) {
722 printf("%s: no more space for fabric devices\n",
723 isp->isp_name);
724 return (-1);
725 }
726 lp->port_wwn = lp->node_wwn = wwn;
727 lp->portid = portid;
728 break;
729 }
730 #endif
731 default:
732 break;
733 }
734 (void) splx(s);
735 return (0);
736 }
737