Home | History | Annotate | Line # | Download | only in ic
isp_netbsd.c revision 1.18.2.2
      1 /* $NetBSD: isp_netbsd.c,v 1.18.2.2 1999/10/19 20:02:23 thorpej 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 void isp_scsipi_request __P((struct scsipi_channel *,
     38 	scsipi_adapter_req_t, void *));
     39 static int
     40 ispioctl __P((struct scsipi_channel *, u_long, caddr_t, int, struct proc *));
     41 
     42 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
     43 static void isp_watch __P((void *));
     44 static void isp_command_requeue __P((void *));
     45 static void isp_internal_restart __P((void *));
     46 
     47 /*
     48  * Complete attachment of hardware, include subdevices.
     49  */
     50 void
     51 isp_attach(isp)
     52 	struct ispsoftc *isp;
     53 {
     54 	struct scsipi_adapter *adapt = &isp->isp_osinfo._adapter;
     55 	struct scsipi_channel *chan;
     56 	int i;
     57 
     58 	isp->isp_state = ISP_RUNSTATE;
     59 	TAILQ_INIT(&isp->isp_osinfo.waitq);	/* XXX 2nd Bus? */
     60 
     61 	/*
     62 	 * Fill in the scsipi_adapter.
     63 	 */
     64 	adapt->adapt_dev = &isp->isp_osinfo._dev;
     65 	if (IS_FC(isp) == 0 && IS_12X0(isp) != 0)
     66 		adapt->adapt_nchannels = 2;
     67 	else
     68 		adapt->adapt_nchannels = 1;
     69 	adapt->adapt_openings = isp->isp_maxcmds;
     70 	adapt->adapt_max_periph = adapt->adapt_openings;
     71 	adapt->adapt_request = isp_scsipi_request;
     72 	adapt->adapt_minphys = ispminphys;
     73 	adapt->adapt_ioctl = ispioctl;
     74 
     75 	/*
     76 	 * Fill in the scsipi_channel(s).
     77 	 */
     78 	for (i = 0; i < adapt->adapt_nchannels; i++) {
     79 		chan = &isp->isp_osinfo._channels[i];
     80 		chan->chan_adapter = adapt;
     81 		chan->chan_bustype = &scsi_bustype;
     82 		chan->chan_channel = i;
     83 
     84 		if (IS_FC(isp)) {
     85 			fcparam *fcp = isp->isp_param;
     86 			fcp = &fcp[i];
     87 
     88 			/*
     89 			 * Give it another chance here to come alive...
     90 			 */
     91 			if (fcp->isp_fwstate != FW_READY) {
     92 				(void) isp_control(isp, ISPCTL_FCLINK_TEST,
     93 				    NULL);
     94 			}
     95 			chan->chan_ntargets = MAX_FC_TARG;
     96 #ifdef	ISP2100_SCCLUN
     97 			/*
     98 			 * 16 bits worth, but let's be reasonable..
     99 			 */
    100 			chan->chan_nluns = 256;
    101 #else
    102 			chan->chan_nluns = 16;
    103 #endif
    104 			chan->chan_id = fcp->isp_loopid;
    105 		} else {
    106 			sdparam *sdp = isp->isp_param;
    107 			sdp = &sdp[i];
    108 
    109 			chan->chan_ntargets = MAX_TARGETS;
    110 			if (isp->isp_bustype == ISP_BT_SBUS)
    111 				chan->chan_nluns = 8;
    112 			else {
    113 #if 0
    114 				/* Too many broken targets... */
    115 				if (isp->isp_fwrev >= ISP_FW_REV(7,55,0))
    116 					chan->chan_nluns = 32;
    117 				else
    118 #endif
    119 					chan->chan_nluns = 7;
    120 			}
    121 			chan->chan_id = sdp->isp_initiator_id;
    122 		}
    123 	}
    124 
    125 	/*
    126 	 * Send a SCSI Bus Reset (used to be done as part of attach,
    127 	 * but now left to the OS outer layers).
    128 	 */
    129 	if (IS_SCSI(isp)) {
    130 		for (i = 0; i < adapt->adapt_nchannels; i++)
    131 			(void) isp_control(isp, ISPCTL_RESET_BUS, &i);
    132 		SYS_DELAY(2*1000000);
    133 	}
    134 
    135 	/*
    136 	 * Start the watchdog.
    137 	 */
    138 	isp->isp_dogactive = 1;
    139 	timeout(isp_watch, isp, WATCH_INTERVAL * hz);
    140 
    141 	/*
    142 	 * And attach children (if any).
    143 	 */
    144 	for (i = 0; i < adapt->adapt_nchannels; i++)
    145 		(void) config_found((void *)isp, &isp->isp_osinfo._channels[i],
    146 		    scsiprint);
    147 }
    148 
    149 /*
    150  * minphys our xfers
    151  *
    152  * Unfortunately, the buffer pointer describes the target device- not the
    153  * adapter device, so we can't use the pointer to find out what kind of
    154  * adapter we are and adjust accordingly.
    155  */
    156 
    157 static void
    158 ispminphys(bp)
    159 	struct buf *bp;
    160 {
    161 	/*
    162 	 * XX: Only the 1020 has a 24 bit limit.
    163 	 */
    164 	if (bp->b_bcount >= (1 << 24)) {
    165 		bp->b_bcount = (1 << 24);
    166 	}
    167 	minphys(bp);
    168 }
    169 
    170 static int
    171 ispioctl(chan, cmd, addr, flag, p)
    172 	struct scsipi_channel *chan;
    173 	u_long cmd;
    174 	caddr_t addr;
    175 	int flag;
    176 	struct proc *p;
    177 {
    178 	struct ispsoftc *isp = (void *)chan->chan_adapter->adapt_dev;
    179 	int s, ch, retval = ENOTTY;
    180 
    181 	switch (cmd) {
    182 	case SCBUSIORESET:
    183 		ch = chan->chan_channel;
    184 		s = splbio();
    185 		if (isp_control(isp, ISPCTL_RESET_BUS, &ch))
    186 			retval = EIO;
    187 		else
    188 			retval = 0;
    189 		(void) splx(s);
    190 		break;
    191 	default:
    192 		break;
    193 	}
    194 	return (retval);
    195 }
    196 
    197 static void
    198 isp_scsipi_request(chan, req, arg)
    199 	struct scsipi_channel *chan;
    200 	scsipi_adapter_req_t req;
    201 	void *arg;
    202 {
    203 	struct scsipi_xfer *xs;
    204 	struct ispsoftc *isp = (void *)chan->chan_adapter->adapt_dev;
    205 	int result, s;
    206 
    207 	switch (req) {
    208 	case ADAPTER_REQ_RUN_XFER:
    209 		xs = arg;
    210 		s = splbio();
    211 		if (isp->isp_state < ISP_RUNSTATE) {
    212 			DISABLE_INTS(isp);
    213 			isp_init(isp);
    214 			if (isp->isp_state != ISP_INITSTATE) {
    215 				ENABLE_INTS(isp);
    216 				(void) splx(s);
    217 				XS_SETERR(xs, HBA_BOTCH);
    218 				XS_CMD_DONE(xs);
    219 				return;
    220 			}
    221 			isp->isp_state = ISP_RUNSTATE;
    222 			ENABLE_INTS(isp);
    223 		}
    224 
    225 		/*
    226 		 * Check for queue blockage...
    227 		 * XXX Should be done in the mid-layer.
    228 		 */
    229 		if (isp->isp_osinfo.blocked) {
    230 			if (xs->xs_control & XS_CTL_POLL) {
    231 				xs->error = XS_BUSY;
    232 				scsipi_done(xs);
    233 				splx(s);
    234 				return;
    235 			}
    236 			TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs,
    237 			    channel_q);
    238 			splx(s);
    239 			return;
    240 		}
    241 
    242 		DISABLE_INTS(isp);
    243 		result = ispscsicmd(xs);
    244 		ENABLE_INTS(isp);
    245 
    246 		switch (result) {
    247 		case CMD_QUEUED:
    248 			/*
    249 			 * If we're not polling for completion, just return.
    250 			 */
    251 			if ((xs->xs_control & XS_CTL_POLL) == 0) {
    252 				(void) splx(s);
    253 				return;
    254 			}
    255 			break;
    256 
    257 		case CMD_EAGAIN:
    258 			/*
    259 			 * Adapter resource shortage of some sort.  Should
    260 			 * retry later.
    261 			 */
    262 			XS_SETERR(xs, XS_RESOURCE_SHORTAGE);
    263 			XS_CMD_DONE(xs);
    264 			(void) splx(s);
    265 			return;
    266 
    267 		case CMD_RQLATER:
    268 			/*
    269 			 * XXX I think what we should do here is freeze
    270 			 * XXX the channel queue, and do a timed thaw
    271 			 * XXX of it.  Need to add this to the mid-layer.
    272 			 */
    273 			if ((xs->xs_control & XS_CTL_POLL) != 0) {
    274 				XS_SETERR(xs, XS_DRIVER_STUFFUP);
    275 				XS_CMD_DONE(xs);
    276 			} else
    277 				timeout(isp_command_requeue, xs, hz);
    278 			(void) splx(s);
    279 			return;
    280 
    281 		case CMD_COMPLETE:
    282 			/*
    283 			 * Something went horribly wrong, xs->error is set,
    284 			 * and we just need to finish it off.
    285 			 */
    286 			XS_CMD_DONE(xs);
    287 			(void) splx(s);
    288 			return;
    289 		}
    290 
    291 		/*
    292 		 * If we can't use interrupts, poll on completion.
    293 		 */
    294 		if (isp_poll(isp, xs, XS_TIME(xs))) {
    295 			/*
    296 			 * If no other error occurred but we didn't finish,
    297 			 * something bad happened.
    298 			 */
    299 			if (XS_IS_CMD_DONE(xs) == 0) {
    300 				if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
    301 					isp_restart(isp);
    302 				}
    303 				if (XS_NOERR(xs)) {
    304 					XS_SETERR(xs, HBA_BOTCH);
    305 				}
    306 				XS_CMD_DONE(xs);
    307 			}
    308 		}
    309 		(void) splx(s);
    310 		return;
    311 
    312 	case ADAPTER_REQ_GROW_RESOURCES:
    313 		/* XXX Not supported. */
    314 		return;
    315 
    316 	case ADAPTER_REQ_SET_XFER_MODE:
    317 		if (isp->isp_type & ISP_HA_SCSI) {
    318 			sdparam *sdp = isp->isp_param;
    319 			struct scsipi_periph *periph = arg;
    320 			u_int16_t flags;
    321 
    322 			sdp = &sdp[periph->periph_channel->chan_channel];
    323 
    324 			flags =
    325 			    sdp->isp_devparam[periph->periph_target].dev_flags;
    326 			flags &= ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING);
    327 
    328 			if (periph->periph_cap & PERIPH_CAP_SYNC)
    329 				flags |= DPARM_SYNC;
    330 
    331 			if (periph->periph_cap & PERIPH_CAP_WIDE16)
    332 				flags |= DPARM_WIDE;
    333 
    334 			if (periph->periph_cap & PERIPH_CAP_TQING)
    335 				flags |= DPARM_TQING;
    336 
    337 			sdp->isp_devparam[periph->periph_target].dev_flags =
    338 			    flags;
    339 			sdp->isp_devparam[periph->periph_target].dev_update = 1;
    340 			isp->isp_update |=
    341 			    (1 << periph->periph_channel->chan_channel);
    342 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
    343 		}
    344 		return;
    345 
    346 	case ADAPTER_REQ_GET_XFER_MODE:
    347 		if (isp->isp_type & ISP_HA_SCSI) {
    348 			sdparam *sdp = isp->isp_param;
    349 			struct scsipi_periph *periph = arg;
    350 			u_int16_t flags;
    351 
    352 			sdp = &sdp[periph->periph_channel->chan_channel];
    353 
    354 			periph->periph_mode = 0;
    355 			periph->periph_period = 0;
    356 			periph->periph_offset = 0;
    357 
    358 			flags =
    359 			    sdp->isp_devparam[periph->periph_target].cur_dflags;
    360 
    361 			if (flags & DPARM_SYNC) {
    362 				periph->periph_mode |= PERIPH_CAP_SYNC;
    363 				periph->periph_period =
    364 			    sdp->isp_devparam[periph->periph_target].cur_period;
    365 				periph->periph_offset =
    366 			    sdp->isp_devparam[periph->periph_target].cur_offset;
    367 			}
    368 			if (flags & DPARM_WIDE)
    369 				periph->periph_mode |= PERIPH_CAP_WIDE16;
    370 			if (flags & DPARM_TQING)
    371 				periph->periph_mode |= PERIPH_CAP_TQING;
    372 
    373 			periph->periph_flags |= PERIPH_MODE_VALID;
    374 		}
    375 		return;
    376 	}
    377 }
    378 
    379 static int
    380 isp_poll(isp, xs, mswait)
    381 	struct ispsoftc *isp;
    382 	ISP_SCSI_XFER_T *xs;
    383 	int mswait;
    384 {
    385 
    386 	while (mswait) {
    387 		/* Try the interrupt handling routine */
    388 		(void)isp_intr((void *)isp);
    389 
    390 		/* See if the xs is now done */
    391 		if (XS_IS_CMD_DONE(xs)) {
    392 			return (0);
    393 		}
    394 		SYS_DELAY(1000);	/* wait one millisecond */
    395 		mswait--;
    396 	}
    397 	return (1);
    398 }
    399 
    400 static void
    401 isp_watch(arg)
    402 	void *arg;
    403 {
    404 	int i;
    405 	struct ispsoftc *isp = arg;
    406 	struct scsipi_xfer *xs;
    407 	int s;
    408 
    409 	/*
    410 	 * Look for completely dead commands (but not polled ones).
    411 	 */
    412 	s = splbio();
    413 	for (i = 0; i < isp->isp_maxcmds; i++) {
    414 		xs = isp->isp_xflist[i];
    415 		if (xs == NULL) {
    416 			continue;
    417 		}
    418 		if (xs->timeout == 0 || (xs->xs_control & XS_CTL_POLL)) {
    419 			continue;
    420 		}
    421 		xs->timeout -= (WATCH_INTERVAL * 1000);
    422 		/*
    423 		 * Avoid later thinking that this
    424 		 * transaction is not being timed.
    425 		 * Then give ourselves to watchdog
    426 		 * periods of grace.
    427 		 */
    428 		if (xs->timeout == 0) {
    429 			xs->timeout = 1;
    430 		} else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) {
    431 			continue;
    432 		}
    433 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
    434 			printf("%s: isp_watch failed to abort command\n",
    435 			    isp->isp_name);
    436 			isp_restart(isp);
    437 			break;
    438 		}
    439 	}
    440 	timeout(isp_watch, isp, WATCH_INTERVAL * hz);
    441 	isp->isp_dogactive = 1;
    442 	(void) splx(s);
    443 }
    444 
    445 /*
    446  * Free any associated resources prior to decommissioning and
    447  * set the card to a known state (so it doesn't wake up and kick
    448  * us when we aren't expecting it to).
    449  *
    450  * Locks are held before coming here.
    451  */
    452 void
    453 isp_uninit(isp)
    454 	struct ispsoftc *isp;
    455 {
    456 	ISP_ILOCKVAL_DECL;
    457 	ISP_ILOCK(isp);
    458 	/*
    459 	 * Leave with interrupts disabled.
    460 	 */
    461 	DISABLE_INTS(isp);
    462 
    463 	/*
    464 	 * Turn off the watchdog (if active).
    465 	 */
    466 	if (isp->isp_dogactive) {
    467 		untimeout(isp_watch, isp);
    468 		isp->isp_dogactive = 0;
    469 	}
    470 
    471 	ISP_IUNLOCK(isp);
    472 }
    473 
    474 /*
    475  * Restart function for a command to be requeued later.
    476  */
    477 static void
    478 isp_command_requeue(arg)
    479 	void *arg;
    480 {
    481 	struct scsipi_xfer *xs = arg;
    482 	int s;
    483 
    484 	s = splbio();
    485 	scsipi_adapter_request(xs->xs_periph->periph_channel,
    486 	    ADAPTER_REQ_RUN_XFER, xs);
    487 	(void) splx(s);
    488 }
    489 
    490 /*
    491  * Restart function after a LOOP UP event (e.g.),
    492  * done as a timeout for some hysteresis.
    493  */
    494 static void
    495 isp_internal_restart(arg)
    496 	void *arg;
    497 {
    498 	struct ispsoftc *isp = arg;
    499 	int result, nrestarted = 0, s;
    500 
    501 	s = splbio();
    502 	if (isp->isp_osinfo.blocked == 0) {
    503 		struct scsipi_xfer *xs;
    504 		while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) {
    505 			TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, channel_q);
    506 			DISABLE_INTS(isp);
    507 			result = ispscsicmd(xs);
    508 			ENABLE_INTS(isp);
    509 			if (result != CMD_QUEUED) {
    510 				printf("%s: botched command restart (0x%x)\n",
    511 				    isp->isp_name, result);
    512 				if (XS_ERR(xs) == XS_NOERROR)
    513 					XS_SETERR(xs, HBA_BOTCH);
    514 				XS_CMD_DONE(xs);
    515 			}
    516 			nrestarted++;
    517 		}
    518 		printf("%s: requeued %d commands\n", isp->isp_name, nrestarted);
    519 	}
    520 	(void) splx(s);
    521 }
    522 
    523 int
    524 isp_async(isp, cmd, arg)
    525 	struct ispsoftc *isp;
    526 	ispasync_t cmd;
    527 	void *arg;
    528 {
    529 	int bus;
    530 	int s = splbio();
    531 	switch (cmd) {
    532 	case ISPASYNC_NEW_TGT_PARAMS:
    533 		/*
    534 		 * XXX Should we really do anything here?
    535 		 */
    536 		break;
    537 	case ISPASYNC_BUS_RESET:
    538 		if (arg)
    539 			bus = *((int *) arg);
    540 		else
    541 			bus = 0;
    542 		printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus);
    543 		break;
    544 	case ISPASYNC_LOOP_DOWN:
    545 		/*
    546 		 * Hopefully we get here in time to minimize the number
    547 		 * of commands we are firing off that are sure to die.
    548 		 */
    549 		isp->isp_osinfo.blocked = 1;
    550 		printf("%s: Loop DOWN\n", isp->isp_name);
    551 		break;
    552         case ISPASYNC_LOOP_UP:
    553 		isp->isp_osinfo.blocked = 0;
    554 		timeout(isp_internal_restart, isp, 1);
    555 		printf("%s: Loop UP\n", isp->isp_name);
    556 		break;
    557 	case ISPASYNC_PDB_CHANGED:
    558 	if (IS_FC(isp) && isp->isp_dblev) {
    559 		const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
    560 		    "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
    561 		const static char *roles[4] = {
    562 		    "No", "Target", "Initiator", "Target/Initiator"
    563 		};
    564 		char *ptr;
    565 		fcparam *fcp = isp->isp_param;
    566 		int tgt = *((int *) arg);
    567 		struct lportdb *lp = &fcp->portdb[tgt];
    568 
    569 		if (lp->valid) {
    570 			ptr = "arrived";
    571 		} else {
    572 			ptr = "disappeared";
    573 		}
    574 		printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
    575 		    roles[lp->roles & 0x3], ptr,
    576 		    (u_int32_t) (lp->port_wwn >> 32),
    577 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
    578 		    (u_int32_t) (lp->node_wwn >> 32),
    579 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
    580 		break;
    581 	}
    582 #ifdef	ISP2100_FABRIC
    583 	case ISPASYNC_CHANGE_NOTIFY:
    584 		printf("%s: Name Server Database Changed\n", isp->isp_name);
    585 		break;
    586 	case ISPASYNC_FABRIC_DEV:
    587 	{
    588 		int target;
    589 		struct lportdb *lp;
    590 		sns_scrsp_t *resp = (sns_scrsp_t *) arg;
    591 		u_int32_t portid;
    592 		u_int64_t wwn;
    593 		fcparam *fcp = isp->isp_param;
    594 
    595 		portid =
    596 		    (((u_int32_t) resp->snscb_port_id[0]) << 16) |
    597 		    (((u_int32_t) resp->snscb_port_id[1]) << 8) |
    598 		    (((u_int32_t) resp->snscb_port_id[2]));
    599 		wwn =
    600 		    (((u_int64_t)resp->snscb_portname[0]) << 56) |
    601 		    (((u_int64_t)resp->snscb_portname[1]) << 48) |
    602 		    (((u_int64_t)resp->snscb_portname[2]) << 40) |
    603 		    (((u_int64_t)resp->snscb_portname[3]) << 32) |
    604 		    (((u_int64_t)resp->snscb_portname[4]) << 24) |
    605 		    (((u_int64_t)resp->snscb_portname[5]) << 16) |
    606 		    (((u_int64_t)resp->snscb_portname[6]) <<  8) |
    607 		    (((u_int64_t)resp->snscb_portname[7]));
    608 		printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN "
    609 		    "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type,
    610 		    portid, ((u_int32_t)(wwn >> 32)),
    611 		    ((u_int32_t)(wwn & 0xffffffff)));
    612 		if (resp->snscb_port_type != 2)
    613 			break;
    614 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
    615 			lp = &fcp->portdb[target];
    616 			if (lp->port_wwn == wwn)
    617 				break;
    618 		}
    619 		if (target < MAX_FC_TARG) {
    620 			break;
    621 		}
    622 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
    623 			lp = &fcp->portdb[target];
    624 			if (lp->port_wwn == 0)
    625 				break;
    626 		}
    627 		if (target == MAX_FC_TARG) {
    628 			printf("%s: no more space for fabric devices\n",
    629 			    isp->isp_name);
    630 			return (-1);
    631 		}
    632 		lp->port_wwn = lp->node_wwn = wwn;
    633 		lp->portid = portid;
    634 		break;
    635 	}
    636 #endif
    637 	default:
    638 		break;
    639 	}
    640 	(void) splx(s);
    641 	return (0);
    642 }
    643