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