xref: /illumos-gate/usr/src/uts/common/io/comstar/port/fct/fct.c (revision 3290ae8418c12896dd59182e67b2c3b6130812f3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/conf.h>
26 #include <sys/file.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/modctl.h>
30 #include <sys/scsi/scsi.h>
31 #include <sys/scsi/impl/scsi_reset_notify.h>
32 #include <sys/disp.h>
33 #include <sys/byteorder.h>
34 #include <sys/varargs.h>
35 #include <sys/atomic.h>
36 #include <sys/sdt.h>
37 
38 #include <sys/stmf.h>
39 #include <sys/stmf_ioctl.h>
40 #include <sys/portif.h>
41 #include <sys/fct.h>
42 #include <sys/fctio.h>
43 
44 #include "fct_impl.h"
45 #include "discovery.h"
46 
47 static int fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
48 static int fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
49 static int fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
50     void **result);
51 static int fct_open(dev_t *devp, int flag, int otype, cred_t *credp);
52 static int fct_close(dev_t dev, int flag, int otype, cred_t *credp);
53 static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
54     cred_t *credp, int *rval);
55 static int fct_fctiocmd(intptr_t data, int mode);
56 void fct_init_kstats(fct_i_local_port_t *iport);
57 
58 static dev_info_t *fct_dip;
59 static struct cb_ops fct_cb_ops = {
60 	fct_open,			/* open */
61 	fct_close,			/* close */
62 	nodev,				/* strategy */
63 	nodev,				/* print */
64 	nodev,				/* dump */
65 	nodev,				/* read */
66 	nodev,				/* write */
67 	fct_ioctl,			/* ioctl */
68 	nodev,				/* devmap */
69 	nodev,				/* mmap */
70 	nodev,				/* segmap */
71 	nochpoll,			/* chpoll */
72 	ddi_prop_op,			/* cb_prop_op */
73 	0,				/* streamtab */
74 	D_NEW | D_MP,			/* cb_flag */
75 	CB_REV,				/* rev */
76 	nodev,				/* aread */
77 	nodev				/* awrite */
78 };
79 
80 static struct dev_ops fct_ops = {
81 	DEVO_REV,
82 	0,
83 	fct_getinfo,
84 	nulldev,		/* identify */
85 	nulldev,		/* probe */
86 	fct_attach,
87 	fct_detach,
88 	nodev,			/* reset */
89 	&fct_cb_ops,
90 	NULL,			/* bus_ops */
91 	NULL			/* power */
92 };
93 
94 #define	FCT_NAME	"COMSTAR FCT"
95 #define	FCT_MODULE_NAME	"fct"
96 
97 extern struct mod_ops mod_driverops;
98 static struct modldrv modldrv = {
99 	&mod_driverops,
100 	FCT_NAME,
101 	&fct_ops
102 };
103 
104 static struct modlinkage modlinkage = {
105 	MODREV_1,
106 	&modldrv,
107 	NULL
108 };
109 
110 static uint32_t	rportid_table_size = FCT_HASH_TABLE_SIZE;
111 static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
112 static fct_i_local_port_t *fct_iport_list = NULL;
113 static kmutex_t fct_global_mutex;
114 uint32_t fct_rscn_options = RSCN_OPTION_VERIFY;
115 
116 int
117 _init(void)
118 {
119 	int ret;
120 
121 	ret = mod_install(&modlinkage);
122 	if (ret)
123 		return (ret);
124 	/* XXX */
125 	mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL);
126 	return (ret);
127 }
128 
129 int
130 _fini(void)
131 {
132 	int ret;
133 
134 	ret = mod_remove(&modlinkage);
135 	if (ret)
136 		return (ret);
137 	/* XXX */
138 	mutex_destroy(&fct_global_mutex);
139 	return (ret);
140 }
141 
142 int
143 _info(struct modinfo *modinfop)
144 {
145 	return (mod_info(&modlinkage, modinfop));
146 }
147 
148 /* ARGSUSED */
149 static int
150 fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
151 {
152 	switch (cmd) {
153 	case DDI_INFO_DEVT2DEVINFO:
154 		*result = fct_dip;
155 		break;
156 	case DDI_INFO_DEVT2INSTANCE:
157 		*result = (void *)(uintptr_t)ddi_get_instance(fct_dip);
158 		break;
159 	default:
160 		return (DDI_FAILURE);
161 	}
162 
163 	return (DDI_SUCCESS);
164 }
165 
166 static int
167 fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
168 {
169 	switch (cmd) {
170 	case DDI_ATTACH:
171 		fct_dip = dip;
172 
173 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
174 		    DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
175 			break;
176 		}
177 		ddi_report_dev(dip);
178 		return (DDI_SUCCESS);
179 	}
180 
181 	return (DDI_FAILURE);
182 }
183 
184 static int
185 fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
186 {
187 	switch (cmd) {
188 	case DDI_DETACH:
189 		ddi_remove_minor_node(dip, 0);
190 		return (DDI_SUCCESS);
191 	}
192 
193 	return (DDI_FAILURE);
194 }
195 
196 /* ARGSUSED */
197 static int
198 fct_open(dev_t *devp, int flag, int otype, cred_t *credp)
199 {
200 	if (otype != OTYP_CHR)
201 		return (EINVAL);
202 	return (0);
203 }
204 
205 /* ARGSUSED */
206 static int
207 fct_close(dev_t dev, int flag, int otype, cred_t *credp)
208 {
209 	return (0);
210 }
211 
212 /* ARGSUSED */
213 static int
214 fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
215     cred_t *credp, int *rval)
216 {
217 	int		ret = 0;
218 
219 	if ((cmd & 0xff000000) != FCT_IOCTL) {
220 		return (ENOTTY);
221 	}
222 
223 	if (drv_priv(credp) != 0) {
224 		return (EPERM);
225 	}
226 
227 	switch (cmd) {
228 	case FCTIO_CMD:
229 		ret = fct_fctiocmd(data, mode);
230 		break;
231 	default:
232 		ret = ENOTTY;
233 		break;
234 	}
235 
236 	return (ret);
237 }
238 
239 int
240 fct_copyin_iocdata(intptr_t data, int mode, fctio_t **fctio,
241     void **ibuf, void **abuf, void **obuf)
242 {
243 	int ret = 0;
244 
245 	*ibuf = NULL;
246 	*abuf = NULL;
247 	*obuf = NULL;
248 	*fctio = kmem_zalloc(sizeof (fctio_t), KM_SLEEP);
249 	if (ddi_copyin((void *)data, *fctio, sizeof (fctio_t), mode)) {
250 		ret = EFAULT;
251 		goto copyin_iocdata_done;
252 	}
253 
254 	if ((*fctio)->fctio_ilen) {
255 		*ibuf = kmem_zalloc((*fctio)->fctio_ilen, KM_SLEEP);
256 		if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_ibuf,
257 		    *ibuf, (*fctio)->fctio_ilen, mode)) {
258 			ret = EFAULT;
259 			goto copyin_iocdata_done;
260 		}
261 	}
262 	if ((*fctio)->fctio_alen) {
263 		*abuf = kmem_zalloc((*fctio)->fctio_alen, KM_SLEEP);
264 		if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_abuf,
265 		    *abuf, (*fctio)->fctio_alen, mode)) {
266 			ret = EFAULT;
267 			goto copyin_iocdata_done;
268 		}
269 	}
270 	if ((*fctio)->fctio_olen)
271 		*obuf = kmem_zalloc((*fctio)->fctio_olen, KM_SLEEP);
272 	if (ret == 0)
273 		return (0);
274 	ret = EFAULT;
275 copyin_iocdata_done:
276 	if (*obuf) {
277 		kmem_free(*obuf, (*fctio)->fctio_olen);
278 		*obuf = NULL;
279 	}
280 	if (*abuf) {
281 		kmem_free(*abuf, (*fctio)->fctio_alen);
282 		*abuf = NULL;
283 	}
284 	if (*ibuf) {
285 		kmem_free(*ibuf, (*fctio)->fctio_ilen);
286 		*ibuf = NULL;
287 	}
288 	kmem_free(*fctio, sizeof (fctio_t));
289 	return (ret);
290 }
291 
292 int
293 fct_copyout_iocdata(intptr_t data, int mode, fctio_t *fctio, void *obuf)
294 {
295 	int ret = 0;
296 
297 	if (fctio->fctio_olen) {
298 		ret = ddi_copyout(obuf,
299 		    (void *)(unsigned long)fctio->fctio_obuf, fctio->fctio_olen,
300 		    mode);
301 		if (ret) {
302 			return (EFAULT);
303 		}
304 	}
305 	ret = ddi_copyout(fctio, (void *)data, sizeof (fctio_t), mode);
306 	if (ret) {
307 		return (EFAULT);
308 	}
309 	return (0);
310 }
311 
312 int
313 fct_get_port_list(char *pathList, int count)
314 {
315 	fct_i_local_port_t *iport;
316 	int	i = 0, maxPorts = 0;
317 
318 	ASSERT(pathList != NULL);
319 
320 	mutex_enter(&fct_global_mutex);
321 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
322 		if (i < count)
323 			bcopy(iport->iport_port->port_pwwn,
324 			    pathList + 8 * i, 8);
325 		maxPorts ++;
326 		i++;
327 	}
328 	mutex_exit(&fct_global_mutex);
329 	return (maxPorts);
330 }
331 
332 /* invoked with fct_global_mutex locked */
333 fct_i_local_port_t *
334 fct_get_iport_per_wwn(uint8_t *pwwn)
335 {
336 	fct_i_local_port_t *iport;
337 
338 	ASSERT(mutex_owned(&fct_global_mutex));
339 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
340 		if (bcmp(iport->iport_port->port_pwwn, pwwn, 8) == 0)
341 			return (iport);
342 	}
343 	return (NULL);
344 }
345 
346 int
347 fct_get_adapter_attr(uint8_t *pwwn, fc_tgt_hba_adapter_attributes_t *hba_attr,
348     uint32_t *err_detail)
349 {
350 	fct_i_local_port_t *iport;
351 	fct_port_attrs_t *attr;
352 
353 	hba_attr->version = FCT_HBA_ADAPTER_ATTRIBUTES_VERSION;
354 	iport = fct_get_iport_per_wwn(pwwn);
355 	if (!iport) {
356 		*err_detail = FCTIO_BADWWN;
357 		return (ENXIO);
358 	}
359 
360 	attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
361 	    KM_SLEEP);
362 	mutex_exit(&fct_global_mutex);
363 	iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
364 	mutex_enter(&fct_global_mutex);
365 
366 	bcopy(attr->manufacturer, hba_attr->Manufacturer,
367 	    sizeof (hba_attr->Manufacturer));
368 	bcopy(attr->serial_number, hba_attr->SerialNumber,
369 	    sizeof (hba_attr->SerialNumber));
370 	bcopy(attr->model, hba_attr->Model, sizeof (hba_attr->Model));
371 	bcopy(attr->model_description, hba_attr->ModelDescription,
372 	    sizeof (hba_attr->ModelDescription));
373 	if (iport->iport_port->port_sym_node_name)
374 		bcopy(iport->iport_port->port_sym_node_name,
375 		    hba_attr->NodeSymbolicName,
376 		    strlen(iport->iport_port->port_sym_node_name));
377 	else
378 		bcopy(utsname.nodename, hba_attr->NodeSymbolicName,
379 		    strlen(utsname.nodename));
380 	bcopy(attr->hardware_version, hba_attr->HardwareVersion,
381 	    sizeof (hba_attr->HardwareVersion));
382 	bcopy(attr->option_rom_version, hba_attr->OptionROMVersion,
383 	    sizeof (hba_attr->OptionROMVersion));
384 	bcopy(attr->firmware_version, hba_attr->FirmwareVersion,
385 	    sizeof (hba_attr->FirmwareVersion));
386 	hba_attr->VendorSpecificID = attr->vendor_specific_id;
387 	bcopy(iport->iport_port->port_nwwn, hba_attr->NodeWWN,
388 	    sizeof (hba_attr->NodeWWN));
389 
390 	bcopy(attr->driver_name, hba_attr->DriverName,
391 	    sizeof (hba_attr->DriverName));
392 	bcopy(attr->driver_version, hba_attr->DriverVersion,
393 	    sizeof (hba_attr->DriverVersion));
394 
395 
396 	/* hba_attr->NumberOfPorts = fct_count_fru_ports(iport); */
397 	hba_attr->NumberOfPorts = 1;
398 
399 	kmem_free(attr, sizeof (fct_port_attrs_t));
400 	return (0);
401 }
402 
403 int
404 fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn,
405     fc_tgt_hba_port_attributes_t *port_attr, uint32_t *err_detail)
406 {
407 	fct_i_local_port_t *iport = ilport;
408 	fct_i_remote_port_t *irp = NULL;
409 	fct_port_attrs_t *attr;
410 	int i = 0;
411 
412 	port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
413 
414 	if (!ilport) {
415 		iport = fct_get_iport_per_wwn(pwwn);
416 		if (!iport) {
417 			*err_detail = FCTIO_BADWWN;
418 			return (ENXIO);
419 		}
420 	}
421 
422 	attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
423 	    KM_SLEEP);
424 	mutex_exit(&fct_global_mutex);
425 	iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
426 	mutex_enter(&fct_global_mutex);
427 
428 	port_attr->lastChange = iport->iport_last_change;
429 	bcopy(iport->iport_port->port_nwwn, port_attr->NodeWWN,
430 	    sizeof (port_attr->NodeWWN));
431 	bcopy(iport->iport_port->port_pwwn, port_attr->PortWWN,
432 	    sizeof (port_attr->PortWWN));
433 	bzero(port_attr->FabricName, sizeof (port_attr->FabricName));
434 	port_attr->PortFcId = iport->iport_link_info.portid;
435 	if ((iport->iport_link_state & S_LINK_ONLINE) ||
436 	    (iport->iport_link_state & S_RCVD_LINK_UP)) {
437 		port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
438 	} else {
439 		port_attr->PortState = FC_HBA_PORTSTATE_OFFLINE;
440 	}
441 	switch (iport->iport_link_info.port_topology) {
442 		case PORT_TOPOLOGY_PT_TO_PT:
443 			port_attr->PortType = FC_HBA_PORTTYPE_PTP;
444 			break;
445 		case PORT_TOPOLOGY_PRIVATE_LOOP:
446 			port_attr->PortType = FC_HBA_PORTTYPE_LPORT;
447 			break;
448 		case PORT_TOPOLOGY_PUBLIC_LOOP:
449 			port_attr->PortType = FC_HBA_PORTTYPE_NLPORT;
450 			break;
451 		case PORT_TOPOLOGY_FABRIC_PT_TO_PT:
452 			port_attr->PortType = FC_HBA_PORTTYPE_FPORT;
453 			break;
454 		default:
455 			port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
456 			break;
457 	}
458 	port_attr->PortSupportedClassofService = attr->supported_cos;
459 	port_attr->PortSupportedFc4Types[0] = 0;
460 	port_attr->PortActiveFc4Types[2] = 1;
461 	if (iport->iport_port->port_sym_port_name)
462 		bcopy(iport->iport_port->port_sym_port_name,
463 		    port_attr->PortSymbolicName,
464 		    strlen(iport->iport_port->port_sym_port_name));
465 	else if (iport->iport_port->port_default_alias)
466 		bcopy(iport->iport_port->port_default_alias,
467 		    port_attr->PortSymbolicName,
468 		    strlen(iport->iport_port->port_default_alias));
469 	else
470 		port_attr->PortSymbolicName[0] = 0;
471 	/* the definition is different so need to translate */
472 	if (attr->supported_speed & PORT_SPEED_1G)
473 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT;
474 	if (attr->supported_speed & PORT_SPEED_2G)
475 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT;
476 	if (attr->supported_speed & PORT_SPEED_4G)
477 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT;
478 	if (attr->supported_speed & PORT_SPEED_8G)
479 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT;
480 	if (attr->supported_speed & PORT_SPEED_10G)
481 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT;
482 	switch (iport->iport_link_info.port_speed) {
483 		case PORT_SPEED_1G:
484 			port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
485 			break;
486 		case PORT_SPEED_2G:
487 			port_attr->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
488 			break;
489 		case PORT_SPEED_4G:
490 			port_attr->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
491 			break;
492 		case PORT_SPEED_8G:
493 			port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
494 			break;
495 		case PORT_SPEED_10G:
496 			port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
497 			break;
498 		default:
499 			port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
500 			break;
501 	}
502 	port_attr->PortMaxFrameSize = attr->max_frame_size;
503 	rw_enter(&iport->iport_lock, RW_READER);
504 	port_attr->NumberofDiscoveredPorts = iport->iport_nrps_login;
505 	for (; i < iport->iport_port->port_max_logins; i++) {
506 		irp = iport->iport_rp_slots[i];
507 		if (irp && irp->irp_flags & IRP_PLOGI_DONE) {
508 			if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
509 				port_attr->NumberofDiscoveredPorts --;
510 		}
511 	}
512 	rw_exit(&iport->iport_lock);
513 
514 	kmem_free(attr, sizeof (fct_port_attrs_t));
515 
516 	return (0);
517 }
518 
519 int
520 fct_get_discovered_port_attr(fct_i_remote_port_t *remote_port,
521     uint8_t *port_wwn, uint32_t index, fc_tgt_hba_port_attributes_t *port_attr,
522     uint32_t *error_detail)
523 {
524 	fct_i_local_port_t *iport;
525 	fct_i_remote_port_t *irp = remote_port;
526 	int	count = 0, i = 0;
527 
528 	port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
529 	if (!remote_port) {
530 		iport = fct_get_iport_per_wwn(port_wwn);
531 		if (!iport) {
532 			*error_detail = FCTIO_BADWWN;
533 			return (ENXIO);
534 		}
535 
536 		rw_enter(&iport->iport_lock, RW_READER);
537 
538 		if (index >= iport->iport_nrps_login) {
539 			rw_exit(&iport->iport_lock);
540 			*error_detail = FCTIO_OUTOFBOUNDS;
541 			return (EINVAL);
542 		}
543 		for (; i < iport->iport_port->port_max_logins; i++) {
544 			irp = iport->iport_rp_slots[i];
545 			if (irp && irp->irp_flags & IRP_PLOGI_DONE &&
546 			    !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
547 				count ++;
548 				if ((index + 1) <= count)
549 					break;
550 			}
551 		}
552 		if (i >= iport->iport_port->port_max_logins) {
553 			rw_exit(&iport->iport_lock);
554 			*error_detail = FCTIO_OUTOFBOUNDS;
555 			return (EINVAL);
556 		}
557 		ASSERT(irp);
558 	} else {
559 		iport = (fct_i_local_port_t *)
560 		    irp->irp_rp->rp_port->port_fct_private;
561 	}
562 	port_attr->lastChange = iport->iport_last_change;
563 	rw_enter(&irp->irp_lock, RW_READER);
564 	bcopy(irp->irp_rp->rp_pwwn, port_attr->PortWWN,
565 	    sizeof (port_attr->PortWWN));
566 	bcopy(irp->irp_rp->rp_nwwn, port_attr->NodeWWN,
567 	    sizeof (port_attr->NodeWWN));
568 	port_attr->PortFcId = irp->irp_portid;
569 	if (irp->irp_spn)
570 		(void) strncpy(port_attr->PortSymbolicName, irp->irp_spn,
571 		    strlen(irp->irp_spn));
572 	else
573 		port_attr->PortSymbolicName[0] = '\0';
574 	port_attr->PortSupportedClassofService = irp->irp_cos;
575 	bcopy((caddr_t)irp->irp_fc4types, port_attr->PortActiveFc4Types,
576 	    sizeof (irp->irp_fc4types));
577 	bcopy((caddr_t)irp->irp_fc4types, port_attr->PortSupportedFc4Types,
578 	    sizeof (irp->irp_fc4types));
579 	if (irp->irp_flags & IRP_PLOGI_DONE)
580 		port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
581 	else
582 		port_attr->PortState = FC_HBA_PORTSTATE_UNKNOWN;
583 
584 	port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
585 	port_attr->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
586 	port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
587 	port_attr->PortMaxFrameSize = 0;
588 	port_attr->NumberofDiscoveredPorts = 0;
589 	rw_exit(&irp->irp_lock);
590 	if (!remote_port) {
591 		rw_exit(&iport->iport_lock);
592 	}
593 	return (0);
594 }
595 
596 int
597 fct_get_port_attr(uint8_t *port_wwn,
598     fc_tgt_hba_port_attributes_t *port_attr, uint32_t *error_detail)
599 {
600 	fct_i_local_port_t *iport;
601 	fct_i_remote_port_t *irp;
602 	int i, ret;
603 
604 	iport = fct_get_iport_per_wwn(port_wwn);
605 	if (iport) {
606 		return (fct_get_adapter_port_attr(iport, port_wwn,
607 		    port_attr, error_detail));
608 	}
609 	/* else */
610 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
611 		rw_enter(&iport->iport_lock, RW_READER);
612 		for (i = 0; i < rportid_table_size; i++) {
613 			irp = iport->iport_rp_tb[i];
614 			while (irp) {
615 				if (bcmp(irp->irp_rp->rp_pwwn,
616 				    port_wwn, 8) == 0 &&
617 				    irp->irp_flags & IRP_PLOGI_DONE) {
618 					ret = fct_get_discovered_port_attr(
619 					    irp, NULL, 0, port_attr,
620 					    error_detail);
621 					rw_exit(&iport->iport_lock);
622 					return (ret);
623 				}
624 				irp = irp->irp_next;
625 			}
626 		}
627 		rw_exit(&iport->iport_lock);
628 	}
629 	*error_detail = FCTIO_BADWWN;
630 	return (ENXIO);
631 }
632 
633 /* ARGSUSED */
634 int
635 fct_get_port_stats(uint8_t *port_wwn,
636     fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail)
637 {
638 	int ret;
639 	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
640 	fct_port_link_status_t	stat;
641 	uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t);
642 
643 	if (!iport)
644 		return (ENXIO);
645 	port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION;
646 
647 	if (iport->iport_port->port_info == NULL) {
648 		*error_detail = FCTIO_FAILURE;
649 		return (EIO);
650 	}
651 	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
652 	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
653 	if (ret != STMF_SUCCESS) {
654 		*error_detail = FCTIO_FAILURE;
655 		return (EIO);
656 	}
657 
658 	port_stats->SecondsSinceLastReset = 0;
659 	port_stats->TxFrames = 0;
660 	port_stats->TxWords = 0;
661 	port_stats->RxFrames = 0;
662 	port_stats->RxWords = 0;
663 	port_stats->LIPCount = 0;
664 	port_stats->NOSCount = 0;
665 	port_stats->ErrorFrames = 0;
666 	port_stats->DumpedFrames = 0;
667 	port_stats->LinkFailureCount = stat.LinkFailureCount;
668 	port_stats->LossOfSyncCount = stat.LossOfSyncCount;
669 	port_stats->LossOfSignalCount = stat.LossOfSignalsCount;
670 	port_stats->PrimitiveSeqProtocolErrCount =
671 	    stat.PrimitiveSeqProtocolErrorCount;
672 	port_stats->InvalidTxWordCount =
673 	    stat.InvalidTransmissionWordCount;
674 	port_stats->InvalidCRCCount = stat.InvalidCRCCount;
675 
676 	return (ret);
677 }
678 
679 int
680 fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id,
681     fct_port_link_status_t *link_status, uint32_t *error_detail)
682 {
683 	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
684 	fct_i_remote_port_t *irp = NULL;
685 	uint32_t buf_size = sizeof (fct_port_link_status_t);
686 	stmf_status_t ret = 0;
687 	int i;
688 	fct_cmd_t *cmd = NULL;
689 
690 	if (!iport) {
691 		*error_detail = FCTIO_BADWWN;
692 		return (ENXIO);
693 	}
694 
695 	/*
696 	 * If what we are requesting is zero or same as local port,
697 	 * then we use port_info()
698 	 */
699 	if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) {
700 		if (iport->iport_port->port_info == NULL) {
701 			*error_detail = FCTIO_FAILURE;
702 			return (EIO);
703 		}
704 		ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
705 		    iport->iport_port, NULL,
706 		    (uint8_t *)link_status, &buf_size);
707 		if (ret == STMF_SUCCESS) {
708 			return (0);
709 		} else {
710 			*error_detail = FCTIO_FAILURE;
711 			return (EIO);
712 		}
713 	}
714 
715 	/*
716 	 * For remote port, we will send RLS
717 	 */
718 	for (i = 0; i < rportid_table_size; i++) {
719 		irp = iport->iport_rp_tb[i];
720 		while (irp) {
721 			if (irp->irp_rp->rp_id == *dest_id &&
722 			    irp->irp_flags & IRP_PLOGI_DONE) {
723 				goto SEND_RLS_ELS;
724 			}
725 			irp = irp->irp_next;
726 		}
727 	}
728 	return (ENXIO);
729 
730 SEND_RLS_ELS:
731 	cmd = fct_create_solels(iport->iport_port,
732 	    irp->irp_rp, 0, ELS_OP_RLS,
733 	    0, fct_rls_cb);
734 	if (!cmd)
735 		return (ENOMEM);
736 	iport->iport_rls_cb_data.fct_link_status = link_status;
737 	CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data;
738 	fct_post_to_solcmd_queue(iport->iport_port, cmd);
739 	sema_p(&iport->iport_rls_sema);
740 	if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS)
741 		ret = EIO;
742 	return (ret);
743 }
744 
745 static int
746 fct_forcelip(uint8_t *port_wwn, uint32_t *fctio_errno)
747 {
748 	fct_status_t		 rval;
749 	fct_i_local_port_t	*iport;
750 
751 	mutex_enter(&fct_global_mutex);
752 	iport = fct_get_iport_per_wwn(port_wwn);
753 	mutex_exit(&fct_global_mutex);
754 	if (iport == NULL) {
755 		return (-1);
756 	}
757 
758 	iport->iport_port->port_ctl(iport->iport_port,
759 	    FCT_CMD_FORCE_LIP, &rval);
760 	if (rval != FCT_SUCCESS) {
761 		*fctio_errno = FCTIO_FAILURE;
762 	} else {
763 		*fctio_errno = 0;
764 	}
765 
766 	return (0);
767 }
768 
769 static int
770 fct_fctiocmd(intptr_t data, int mode)
771 {
772 	int ret	 = 0;
773 	void		*ibuf = NULL;
774 	void		*obuf = NULL;
775 	void		*abuf = NULL;
776 	fctio_t		*fctio;
777 	uint32_t	attr_length;
778 
779 	ret = fct_copyin_iocdata(data, mode, &fctio, &ibuf, &abuf, &obuf);
780 	if (ret) {
781 		return (ret);
782 	}
783 
784 	switch (fctio->fctio_cmd) {
785 	case FCTIO_ADAPTER_LIST: {
786 		fc_tgt_hba_list_t *list = (fc_tgt_hba_list_t *)obuf;
787 		int		count;
788 
789 		if (fctio->fctio_olen < sizeof (fc_tgt_hba_list_t)) {
790 			ret = EINVAL;
791 			break;
792 		}
793 		list->numPorts = (fctio->fctio_olen -
794 		    sizeof (fc_tgt_hba_list_t))/8 + 1;
795 
796 		list->version = FCT_HBA_LIST_VERSION;
797 		count = fct_get_port_list((char *)list->port_wwn,
798 		    list->numPorts);
799 		if (count < 0) {
800 			ret = ENXIO;
801 			break;
802 		}
803 		if (count > list->numPorts) {
804 			fctio->fctio_errno = FCTIO_MOREDATA;
805 			ret = ENOSPC;
806 		}
807 		list->numPorts = count;
808 		break;
809 		}
810 	case FCTIO_GET_ADAPTER_ATTRIBUTES: {
811 		fc_tgt_hba_adapter_attributes_t *hba_attr;
812 		uint8_t	*port_wwn = (uint8_t *)ibuf;
813 
814 		attr_length = sizeof (fc_tgt_hba_adapter_attributes_t);
815 		if (fctio->fctio_olen < attr_length ||
816 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
817 			ret = EINVAL;
818 			break;
819 		}
820 		hba_attr = (fc_tgt_hba_adapter_attributes_t *)obuf;
821 
822 		mutex_enter(&fct_global_mutex);
823 		ret = fct_get_adapter_attr(port_wwn, hba_attr,
824 		    &fctio->fctio_errno);
825 		mutex_exit(&fct_global_mutex);
826 
827 		break;
828 		}
829 	case FCTIO_GET_ADAPTER_PORT_ATTRIBUTES: {
830 		fc_tgt_hba_port_attributes_t *port_attr;
831 
832 		uint8_t *port_wwn = (uint8_t *)ibuf;
833 
834 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
835 		if (fctio->fctio_olen < attr_length ||
836 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
837 			ret = EINVAL;
838 			break;
839 		}
840 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
841 
842 		mutex_enter(&fct_global_mutex);
843 		ret = fct_get_adapter_port_attr(NULL, port_wwn, port_attr,
844 		    &fctio->fctio_errno);
845 		mutex_exit(&fct_global_mutex);
846 
847 		break;
848 		}
849 	case FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
850 		uint8_t *port_wwn = (uint8_t *)ibuf;
851 		uint32_t *port_index = (uint32_t *)abuf;
852 		fc_tgt_hba_port_attributes_t *port_attr;
853 
854 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
855 		if (fctio->fctio_olen < attr_length ||
856 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
857 			ret = EINVAL;
858 			break;
859 		}
860 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
861 
862 		mutex_enter(&fct_global_mutex);
863 		ret = fct_get_discovered_port_attr(NULL, port_wwn,
864 		    *port_index, port_attr, &fctio->fctio_errno);
865 		mutex_exit(&fct_global_mutex);
866 
867 		break;
868 		}
869 	case FCTIO_GET_PORT_ATTRIBUTES: {
870 		uint8_t *port_wwn = (uint8_t *)ibuf;
871 		fc_tgt_hba_port_attributes_t *port_attr;
872 
873 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
874 		if (fctio->fctio_olen < attr_length ||
875 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
876 			ret = EINVAL;
877 			break;
878 		}
879 
880 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
881 
882 		mutex_enter(&fct_global_mutex);
883 		ret = fct_get_port_attr(port_wwn, port_attr,
884 		    &fctio->fctio_errno);
885 		mutex_exit(&fct_global_mutex);
886 
887 		break;
888 		}
889 	case FCTIO_GET_ADAPTER_PORT_STATS: {
890 		uint8_t *port_wwn = (uint8_t *)ibuf;
891 		fc_tgt_hba_adapter_port_stats_t *port_stats =
892 		    (fc_tgt_hba_adapter_port_stats_t *)obuf;
893 		mutex_enter(&fct_global_mutex);
894 		ret = fct_get_port_stats(port_wwn, port_stats,
895 		    &fctio->fctio_errno);
896 		mutex_exit(&fct_global_mutex);
897 		break;
898 		}
899 	case FCTIO_GET_LINK_STATUS: {
900 		uint8_t *port_wwn = (uint8_t *)ibuf;
901 		fct_port_link_status_t *link_status =
902 		    (fct_port_link_status_t *)obuf;
903 		uint64_t *dest_id = abuf;
904 
905 		mutex_enter(&fct_global_mutex);
906 		ret = fct_get_link_status(port_wwn, dest_id, link_status,
907 		    &fctio->fctio_errno);
908 		mutex_exit(&fct_global_mutex);
909 		break;
910 		}
911 
912 	case FCTIO_FORCE_LIP:
913 		ret = fct_forcelip((uint8_t *)ibuf, &fctio->fctio_errno);
914 		break;
915 
916 	default:
917 		break;
918 	}
919 	if (ret == 0) {
920 		ret = fct_copyout_iocdata(data, mode, fctio, obuf);
921 	} else if (fctio->fctio_errno) {
922 		(void) fct_copyout_iocdata(data, mode, fctio, obuf);
923 	}
924 
925 	if (obuf) {
926 		kmem_free(obuf, fctio->fctio_olen);
927 		obuf = NULL;
928 	}
929 	if (abuf) {
930 		kmem_free(abuf, fctio->fctio_alen);
931 		abuf = NULL;
932 	}
933 
934 	if (ibuf) {
935 		kmem_free(ibuf, fctio->fctio_ilen);
936 		ibuf = NULL;
937 	}
938 	kmem_free(fctio, sizeof (fctio_t));
939 	return (ret);
940 }
941 
942 typedef struct {
943 	void	*bp;	/* back pointer from internal struct to main struct */
944 	int	alloc_size;
945 	fct_struct_id_t struct_id;
946 } __ifct_t;
947 
948 typedef struct {
949 	__ifct_t	*fp;	/* Framework private */
950 	void		*cp;	/* Caller private */
951 	void		*ss;	/* struct specific */
952 } __fct_t;
953 
954 static struct {
955 	int shared;
956 	int fw_private;
957 	int struct_specific;
958 } fct_sizes[] = { { 0, 0, 0 },
959 	{ GET_STRUCT_SIZE(fct_local_port_t),
960 		GET_STRUCT_SIZE(fct_i_local_port_t), 0 },
961 	{ GET_STRUCT_SIZE(fct_remote_port_t),
962 		GET_STRUCT_SIZE(fct_i_remote_port_t), 0 },
963 	{ GET_STRUCT_SIZE(fct_cmd_t),
964 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
965 	{ GET_STRUCT_SIZE(fct_cmd_t),
966 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
967 	{ GET_STRUCT_SIZE(fct_cmd_t),
968 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_sol_ct_t) },
969 	{ GET_STRUCT_SIZE(fct_cmd_t), GET_STRUCT_SIZE(fct_i_cmd_t),
970 		GET_STRUCT_SIZE(fct_rcvd_abts_t) },
971 	{ GET_STRUCT_SIZE(fct_cmd_t),	/* FCT_STRUCT_CMD_FCP_XCHG */
972 		GET_STRUCT_SIZE(fct_i_cmd_t), 0 },
973 	{ GET_STRUCT_SIZE(fct_dbuf_store_t),
974 		GET_STRUCT_SIZE(__ifct_t), 0 }
975 };
976 
977 void *
978 fct_alloc(fct_struct_id_t struct_id, int additional_size, int flags)
979 {
980 	int fct_size;
981 	int kmem_flag;
982 	__fct_t *sh;
983 
984 	if ((struct_id == 0) || (struct_id >= FCT_MAX_STRUCT_IDS))
985 		return (NULL);
986 
987 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
988 		kmem_flag = KM_NOSLEEP;
989 	} else {
990 		kmem_flag = KM_SLEEP;
991 	}
992 
993 	additional_size = (additional_size + 7) & (~7);
994 	fct_size = fct_sizes[struct_id].shared +
995 	    fct_sizes[struct_id].fw_private +
996 	    fct_sizes[struct_id].struct_specific + additional_size;
997 
998 	if (struct_id == FCT_STRUCT_LOCAL_PORT) {
999 		stmf_local_port_t *lport;
1000 
1001 		lport = (stmf_local_port_t *)stmf_alloc(
1002 		    STMF_STRUCT_STMF_LOCAL_PORT, fct_size, flags);
1003 		if (lport) {
1004 			sh = (__fct_t *)lport->lport_port_private;
1005 			sh->ss = lport;
1006 		} else {
1007 			return (NULL);
1008 		}
1009 	} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
1010 		stmf_dbuf_store_t *ds;
1011 
1012 		ds = (stmf_dbuf_store_t *)stmf_alloc(STMF_STRUCT_DBUF_STORE,
1013 		    fct_size, flags);
1014 		if (ds) {
1015 			sh = (__fct_t *)ds->ds_port_private;
1016 			sh->ss = ds;
1017 		} else {
1018 			return (NULL);
1019 		}
1020 	} else {
1021 		sh = (__fct_t *)kmem_zalloc(fct_size, kmem_flag);
1022 	}
1023 
1024 	if (sh == NULL)
1025 		return (NULL);
1026 
1027 	sh->fp = (__ifct_t *)GET_BYTE_OFFSET(sh, fct_sizes[struct_id].shared);
1028 	sh->cp = GET_BYTE_OFFSET(sh->fp, fct_sizes[struct_id].fw_private);
1029 	if (fct_sizes[struct_id].struct_specific)
1030 		sh->ss = GET_BYTE_OFFSET(sh->cp, additional_size);
1031 
1032 	sh->fp->bp = sh;
1033 	sh->fp->alloc_size = fct_size;
1034 	sh->fp->struct_id = struct_id;
1035 
1036 	if (struct_id == FCT_STRUCT_CMD_FCP_XCHG) {
1037 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_FCP_XCHG;
1038 	} else if (struct_id == FCT_STRUCT_CMD_RCVD_ELS) {
1039 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ELS;
1040 	} else if (struct_id == FCT_STRUCT_CMD_SOL_ELS) {
1041 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_ELS;
1042 	} else if (struct_id == FCT_STRUCT_CMD_RCVD_ABTS) {
1043 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ABTS;
1044 	} else if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
1045 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_CT;
1046 	}
1047 
1048 	return (sh);
1049 }
1050 
1051 void
1052 fct_free(void *ptr)
1053 {
1054 	__fct_t *sh = (__fct_t *)ptr;
1055 	fct_struct_id_t struct_id = sh->fp->struct_id;
1056 
1057 	if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
1058 		fct_sol_ct_t *ct = (fct_sol_ct_t *)
1059 		    ((fct_cmd_t *)ptr)->cmd_specific;
1060 
1061 		if (ct->ct_req_alloc_size) {
1062 			kmem_free(ct->ct_req_payload, ct->ct_req_alloc_size);
1063 		}
1064 		if (ct->ct_resp_alloc_size) {
1065 			kmem_free(ct->ct_resp_payload, ct->ct_resp_alloc_size);
1066 		}
1067 	} else if ((struct_id == FCT_STRUCT_CMD_RCVD_ELS) ||
1068 	    (struct_id == FCT_STRUCT_CMD_SOL_ELS)) {
1069 		fct_els_t *els = (fct_els_t *)
1070 			((fct_cmd_t *)ptr)->cmd_specific;
1071 		if (els->els_req_alloc_size)
1072 			kmem_free(els->els_req_payload,
1073 				els->els_req_alloc_size);
1074 		if (els->els_resp_alloc_size)
1075 			kmem_free(els->els_resp_payload,
1076 				els->els_resp_alloc_size);
1077 	}
1078 
1079 	if (struct_id == FCT_STRUCT_LOCAL_PORT) {
1080 		stmf_free(((fct_local_port_t *)ptr)->port_lport);
1081 	} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
1082 		stmf_free(((fct_dbuf_store_t *)ptr)->fds_ds);
1083 	} else {
1084 		kmem_free(ptr, sh->fp->alloc_size);
1085 	}
1086 }
1087 
1088 stmf_data_buf_t *
1089 fct_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
1090     uint32_t flags)
1091 {
1092 	fct_local_port_t *port = (fct_local_port_t *)
1093 	    task->task_lport->lport_port_private;
1094 
1095 	return (port->port_fds->fds_alloc_data_buf(port, size,
1096 	    pminsize, flags));
1097 }
1098 
1099 stmf_status_t
1100 fct_setup_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t flags)
1101 {
1102 	fct_local_port_t *port = (fct_local_port_t *)
1103 	    task->task_lport->lport_port_private;
1104 
1105 	ASSERT(port->port_fds->fds_setup_dbuf != NULL);
1106 	if (port->port_fds->fds_setup_dbuf == NULL)
1107 		return (STMF_FAILURE);
1108 
1109 	return (port->port_fds->fds_setup_dbuf(port, dbuf, flags));
1110 }
1111 
1112 void
1113 fct_teardown_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
1114 {
1115 	fct_dbuf_store_t *fds = ds->ds_port_private;
1116 
1117 	fds->fds_teardown_dbuf(fds, dbuf);
1118 }
1119 
1120 void
1121 fct_free_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
1122 {
1123 	fct_dbuf_store_t *fds;
1124 
1125 	fds = (fct_dbuf_store_t *)ds->ds_port_private;
1126 
1127 	fds->fds_free_data_buf(fds, dbuf);
1128 }
1129 
1130 static uint32_t taskq_cntr = 0;
1131 
1132 fct_status_t
1133 fct_register_local_port(fct_local_port_t *port)
1134 {
1135 	fct_i_local_port_t	*iport;
1136 	stmf_local_port_t	*lport;
1137 	fct_cmd_slot_t		*slot;
1138 	int			i;
1139 	char			taskq_name[FCT_TASKQ_NAME_LEN];
1140 
1141 	iport = (fct_i_local_port_t *)port->port_fct_private;
1142 	if (port->port_fca_version != FCT_FCA_MODREV_1) {
1143 		cmn_err(CE_WARN,
1144 		    "fct: %s driver version mismatch",
1145 		    port->port_default_alias);
1146 		return (FCT_FAILURE);
1147 	}
1148 	if (port->port_default_alias) {
1149 		int l = strlen(port->port_default_alias);
1150 
1151 		if (l < 16) {
1152 			iport->iport_alias = iport->iport_alias_mem;
1153 		} else {
1154 			iport->iport_alias =
1155 			    (char *)kmem_zalloc(l+1, KM_SLEEP);
1156 		}
1157 		(void) strcpy(iport->iport_alias, port->port_default_alias);
1158 	} else {
1159 		iport->iport_alias = NULL;
1160 	}
1161 	stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id,
1162 	    port->port_pwwn, PROTOCOL_FIBRE_CHANNEL);
1163 	(void) snprintf(taskq_name, sizeof (taskq_name), "stmf_fct_taskq_%d",
1164 	    atomic_add_32_nv(&taskq_cntr, 1));
1165 	if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1166 	    taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1167 		return (FCT_FAILURE);
1168 	}
1169 	mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1170 	cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1171 	rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1172 	sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1173 
1174 	/* Remote port mgmt */
1175 	iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1176 	    port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1177 	iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1178 	    sizeof (fct_i_remote_port_t *), KM_SLEEP);
1179 
1180 	/* fct_cmds for SCSI traffic */
1181 	iport->iport_total_alloced_ncmds = 0;
1182 	iport->iport_cached_ncmds = 0;
1183 	port->port_fca_fcp_cmd_size =
1184 	    (port->port_fca_fcp_cmd_size + 7) & ~7;
1185 	iport->iport_cached_cmdlist = NULL;
1186 	mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL);
1187 
1188 	/* Initialize cmd slots */
1189 	iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc(
1190 	    port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP);
1191 	iport->iport_next_free_slot = 0;
1192 	for (i = 0; i < port->port_max_xchges; ) {
1193 		slot = &iport->iport_cmd_slots[i];
1194 		slot->slot_no = (uint16_t)i;
1195 		slot->slot_next = (uint16_t)(++i);
1196 	}
1197 	slot->slot_next = FCT_SLOT_EOL;
1198 	iport->iport_nslots_free = port->port_max_xchges;
1199 
1200 	iport->iport_task_green_limit =
1201 	    (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100;
1202 	iport->iport_task_yellow_limit =
1203 	    (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100;
1204 	iport->iport_task_red_limit =
1205 	    (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100;
1206 
1207 	/* Start worker thread */
1208 	atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
1209 	(void) ddi_taskq_dispatch(iport->iport_worker_taskq,
1210 	    fct_port_worker, port, DDI_SLEEP);
1211 	/* Wait for taskq to start */
1212 	while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
1213 		delay(1);
1214 	}
1215 
1216 	lport = port->port_lport;
1217 	lport->lport_id = (scsi_devid_desc_t *)iport->iport_id;
1218 	lport->lport_alias = iport->iport_alias;
1219 	lport->lport_pp = port->port_pp;
1220 	port->port_fds->fds_ds->ds_alloc_data_buf = fct_alloc_dbuf;
1221 	port->port_fds->fds_ds->ds_free_data_buf = fct_free_dbuf;
1222 	port->port_fds->fds_ds->ds_setup_dbuf = fct_setup_dbuf;
1223 	port->port_fds->fds_ds->ds_teardown_dbuf = fct_teardown_dbuf;
1224 	lport->lport_ds = port->port_fds->fds_ds;
1225 	lport->lport_xfer_data = fct_xfer_scsi_data;
1226 	lport->lport_send_status = fct_send_scsi_status;
1227 	lport->lport_task_free = fct_scsi_task_free;
1228 	lport->lport_abort = fct_scsi_abort;
1229 	lport->lport_ctl = fct_ctl;
1230 	lport->lport_info = fct_info;
1231 	lport->lport_event_handler = fct_event_handler;
1232 	/* set up as alua participating port */
1233 	stmf_set_port_alua(lport);
1234 	if (stmf_register_local_port(port->port_lport) != FCT_SUCCESS) {
1235 		goto fct_regport_fail1;
1236 	}
1237 	(void) stmf_lport_add_event(lport, LPORT_EVENT_INITIAL_LUN_MAPPED);
1238 
1239 	mutex_enter(&fct_global_mutex);
1240 	iport->iport_next = fct_iport_list;
1241 	iport->iport_prev = NULL;
1242 	if (iport->iport_next)
1243 		iport->iport_next->iport_prev = iport;
1244 	fct_iport_list = iport;
1245 	mutex_exit(&fct_global_mutex);
1246 
1247 	fct_init_kstats(iport);
1248 
1249 	fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH);
1250 
1251 	return (FCT_SUCCESS);
1252 
1253 fct_regport_fail1:;
1254 	/* Stop the taskq 1st */
1255 	if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1256 		atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1257 		cv_broadcast(&iport->iport_worker_cv);
1258 		while (iport->iport_flags & IPORT_WORKER_RUNNING) {
1259 			delay(1);
1260 		}
1261 	}
1262 	ddi_taskq_destroy(iport->iport_worker_taskq);
1263 	if (iport->iport_rp_tb) {
1264 		kmem_free(iport->iport_rp_tb, rportid_table_size *
1265 		    sizeof (fct_i_remote_port_t *));
1266 	}
1267 	return (FCT_FAILURE);
1268 }
1269 
1270 fct_status_t
1271 fct_deregister_local_port(fct_local_port_t *port)
1272 {
1273 	fct_i_local_port_t	*iport;
1274 	fct_i_cmd_t		*icmd, *next_icmd;
1275 	int			ndx;
1276 
1277 	iport = (fct_i_local_port_t *)port->port_fct_private;
1278 
1279 	if ((iport->iport_state != FCT_STATE_OFFLINE) ||
1280 	    iport->iport_state_not_acked) {
1281 		return (FCT_FAILURE);
1282 	}
1283 
1284 	/* Stop the taskq 1st */
1285 	if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1286 		atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1287 		cv_broadcast(&iport->iport_worker_cv);
1288 		for (ndx = 0; ndx < 100; ndx++) {
1289 			if ((iport->iport_flags & IPORT_WORKER_RUNNING)
1290 			    == 0) {
1291 				break;
1292 			}
1293 			delay(drv_usectohz(10000));
1294 		}
1295 		if (ndx == 100) {
1296 			atomic_and_32(&iport->iport_flags,
1297 			    ~IPORT_TERMINATE_WORKER);
1298 			return (FCT_WORKER_STUCK);
1299 		}
1300 	}
1301 
1302 	if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) {
1303 		goto fct_deregport_fail1;
1304 	}
1305 
1306 	mutex_enter(&fct_global_mutex);
1307 	if (iport->iport_next)
1308 		iport->iport_next->iport_prev = iport->iport_prev;
1309 	if (iport->iport_prev)
1310 		iport->iport_prev->iport_next = iport->iport_next;
1311 	else
1312 		fct_iport_list = iport->iport_next;
1313 	mutex_exit(&fct_global_mutex);
1314 	/*
1315 	 * At this time, there should be no outstanding and pending
1316 	 * I/Os, so we can just release resources.
1317 	 */
1318 	ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds);
1319 	for (icmd = iport->iport_cached_cmdlist; icmd; icmd = next_icmd) {
1320 		next_icmd = icmd->icmd_next;
1321 		fct_free(icmd->icmd_cmd);
1322 	}
1323 	mutex_destroy(&iport->iport_cached_cmd_lock);
1324 	kmem_free(iport->iport_cmd_slots, port->port_max_xchges *
1325 	    sizeof (fct_cmd_slot_t));
1326 	kmem_free(iport->iport_rp_slots, port->port_max_logins *
1327 	    sizeof (fct_i_remote_port_t *));
1328 	rw_destroy(&iport->iport_lock);
1329 	cv_destroy(&iport->iport_worker_cv);
1330 	sema_destroy(&iport->iport_rls_sema);
1331 	mutex_destroy(&iport->iport_worker_lock);
1332 	ddi_taskq_destroy(iport->iport_worker_taskq);
1333 	if (iport->iport_rp_tb) {
1334 		kmem_free(iport->iport_rp_tb, rportid_table_size *
1335 		    sizeof (fct_i_remote_port_t *));
1336 	}
1337 
1338 	if (iport->iport_kstat_portstat) {
1339 		kstat_delete(iport->iport_kstat_portstat);
1340 	}
1341 
1342 	fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH);
1343 	return (FCT_SUCCESS);
1344 
1345 fct_deregport_fail1:;
1346 	/* Restart the worker */
1347 	atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
1348 	(void) ddi_taskq_dispatch(iport->iport_worker_taskq,
1349 	    fct_port_worker, port, DDI_SLEEP);
1350 	/* Wait for taskq to start */
1351 	while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
1352 		delay(1);
1353 	}
1354 	return (FCT_FAILURE);
1355 }
1356 
1357 /* ARGSUSED */
1358 void
1359 fct_handle_event(fct_local_port_t *port, int event_id, uint32_t event_flags,
1360 		caddr_t arg)
1361 {
1362 	char			info[FCT_INFO_LEN];
1363 	fct_i_event_t		*e;
1364 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1365 	    port->port_fct_private;
1366 
1367 	e = kmem_zalloc(sizeof (fct_i_event_t), KM_NOSLEEP);
1368 
1369 	if (e == NULL) {
1370 		/*
1371 		 * XXX Throw HBA fatal error event
1372 		 */
1373 		(void) snprintf(info, sizeof (info),
1374 		    "fct_handle_event: iport-%p, allocation "
1375 		    "of fct_i_event failed", (void *)iport);
1376 		(void) fct_port_shutdown(iport->iport_port,
1377 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1378 		return;
1379 	}
1380 	/* Just queue the event */
1381 	e->event_type = event_id;
1382 	mutex_enter(&iport->iport_worker_lock);
1383 	if (iport->iport_event_head == NULL) {
1384 		iport->iport_event_head = iport->iport_event_tail = e;
1385 	} else {
1386 		iport->iport_event_tail->event_next = e;
1387 		iport->iport_event_tail = e;
1388 	}
1389 	if (IS_WORKER_SLEEPING(iport))
1390 		cv_signal(&iport->iport_worker_cv);
1391 	mutex_exit(&iport->iport_worker_lock);
1392 }
1393 
1394 /*
1395  * Called with iport_lock held as reader.
1396  */
1397 fct_i_remote_port_t *
1398 fct_portid_to_portptr(fct_i_local_port_t *iport, uint32_t portid)
1399 {
1400 	fct_i_remote_port_t	*irp;
1401 
1402 	irp = iport->iport_rp_tb[FCT_PORTID_HASH_FUNC(portid)];
1403 	for (; irp != NULL; irp = irp->irp_next) {
1404 		if (irp->irp_portid == portid)
1405 			return (irp);
1406 	}
1407 
1408 	return (NULL);
1409 
1410 }
1411 
1412 /*
1413  * Called with irp_lock held as writer.
1414  */
1415 void
1416 fct_queue_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1417 {
1418 	int hash_key =
1419 	    FCT_PORTID_HASH_FUNC(irp->irp_portid);
1420 
1421 	irp->irp_next = iport->iport_rp_tb[hash_key];
1422 	iport->iport_rp_tb[hash_key] = irp;
1423 	iport->iport_nrps++;
1424 }
1425 
1426 /*
1427  * Called with irp_lock and iport_lock held as writer.
1428  */
1429 void
1430 fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1431 {
1432 	fct_i_remote_port_t	*irp_next = NULL;
1433 	fct_i_remote_port_t	*irp_last = NULL;
1434 	int hash_key			  =
1435 	    FCT_PORTID_HASH_FUNC(irp->irp_portid);
1436 
1437 	irp_next = iport->iport_rp_tb[hash_key];
1438 	irp_last = NULL;
1439 	while (irp_next != NULL) {
1440 		if (irp == irp_next) {
1441 			if (irp->irp_flags & IRP_PLOGI_DONE) {
1442 				atomic_add_32(&iport->iport_nrps_login, -1);
1443 			}
1444 			atomic_and_32(&irp->irp_flags,
1445 			    ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1446 			break;
1447 		}
1448 		irp_last = irp_next;
1449 		irp_next = irp_next->irp_next;
1450 	}
1451 
1452 	if (irp_next) {
1453 		if (irp_last == NULL) {
1454 			iport->iport_rp_tb[hash_key] =
1455 			    irp->irp_next;
1456 		} else {
1457 			irp_last->irp_next = irp->irp_next;
1458 		}
1459 		irp->irp_next = NULL;
1460 		iport->iport_nrps--;
1461 	}
1462 }
1463 
1464 int
1465 fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit)
1466 {
1467 	int logging_out = 0;
1468 
1469 	rw_enter(&irp->irp_lock, RW_WRITER);
1470 	if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1471 		logging_out = 0;
1472 		goto ilo_done;
1473 	}
1474 	if ((irp->irp_els_list == NULL) && (irp->irp_deregister_timer)) {
1475 		if (force_implicit && irp->irp_nonfcp_xchg_count) {
1476 			logging_out = 0;
1477 		} else {
1478 			logging_out = 1;
1479 		}
1480 		goto ilo_done;
1481 	}
1482 	if (irp->irp_els_list) {
1483 		fct_i_cmd_t *icmd;
1484 		/* Last session affecting ELS should be a LOGO */
1485 		for (icmd = irp->irp_els_list; icmd; icmd = icmd->icmd_next) {
1486 			uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0];
1487 			if (op == ELS_OP_LOGO) {
1488 				if (force_implicit) {
1489 					if (icmd->icmd_flags & ICMD_IMPLICIT)
1490 						logging_out = 1;
1491 					else
1492 						logging_out = 0;
1493 				} else {
1494 					logging_out = 1;
1495 				}
1496 			} else if ((op == ELS_OP_PLOGI) ||
1497 			    (op == ELS_OP_PRLI) ||
1498 			    (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
1499 				logging_out = 0;
1500 			}
1501 		}
1502 	}
1503 ilo_done:;
1504 	rw_exit(&irp->irp_lock);
1505 
1506 	return (logging_out);
1507 }
1508 
1509 /*
1510  * The force_implicit flag enforces the implicit semantics which may be
1511  * needed if a received logout got stuck e.g. a response to a received
1512  * LOGO never came back from the FCA.
1513  */
1514 int
1515 fct_implicitly_logo_all(fct_i_local_port_t *iport, int force_implicit)
1516 {
1517 	fct_i_remote_port_t	*irp = NULL;
1518 	fct_cmd_t		*cmd = NULL;
1519 	int			 i   = 0;
1520 	int			nports = 0;
1521 
1522 	if (!iport->iport_nrps) {
1523 		return (nports);
1524 	}
1525 
1526 	rw_enter(&iport->iport_lock, RW_WRITER);
1527 	for (i = 0; i < rportid_table_size; i++) {
1528 		irp = iport->iport_rp_tb[i];
1529 		while (irp) {
1530 			if ((!(irp->irp_flags & IRP_PLOGI_DONE)) &&
1531 			    (fct_is_irp_logging_out(irp, force_implicit))) {
1532 				irp = irp->irp_next;
1533 				continue;
1534 			}
1535 
1536 			cmd = fct_create_solels(iport->iport_port, irp->irp_rp,
1537 			    1, ELS_OP_LOGO, 0, fct_logo_cb);
1538 			if (cmd == NULL) {
1539 				stmf_trace(iport->iport_alias,
1540 				    "fct_implictly_logo_all: cmd null");
1541 				rw_exit(&iport->iport_lock);
1542 
1543 				return (nports);
1544 			}
1545 
1546 			fct_post_implicit_logo(cmd);
1547 			nports++;
1548 			irp = irp->irp_next;
1549 		}
1550 	}
1551 	rw_exit(&iport->iport_lock);
1552 
1553 	return (nports);
1554 }
1555 
1556 void
1557 fct_rehash(fct_i_local_port_t *iport)
1558 {
1559 	fct_i_remote_port_t **iport_rp_tb_tmp;
1560 	fct_i_remote_port_t **iport_rp_tb_new;
1561 	fct_i_remote_port_t *irp;
1562 	fct_i_remote_port_t *irp_next;
1563 	int i;
1564 
1565 	iport_rp_tb_new = kmem_zalloc(rportid_table_size *
1566 	    sizeof (fct_i_remote_port_t *), KM_SLEEP);
1567 	rw_enter(&iport->iport_lock, RW_WRITER);
1568 	/* reconstruct the hash table */
1569 	iport_rp_tb_tmp = iport->iport_rp_tb;
1570 	iport->iport_rp_tb = iport_rp_tb_new;
1571 	iport->iport_nrps = 0;
1572 	for (i = 0; i < rportid_table_size; i++) {
1573 		irp = iport_rp_tb_tmp[i];
1574 		while (irp) {
1575 			irp_next = irp->irp_next;
1576 			fct_queue_rp(iport, irp);
1577 			irp = irp_next;
1578 		}
1579 	}
1580 	rw_exit(&iport->iport_lock);
1581 	kmem_free(iport_rp_tb_tmp, rportid_table_size *
1582 	    sizeof (fct_i_remote_port_t *));
1583 
1584 }
1585 
1586 uint8_t
1587 fct_local_port_cleanup_done(fct_i_local_port_t *iport)
1588 {
1589 	fct_i_remote_port_t *irp;
1590 	int i;
1591 
1592 	if (iport->iport_nrps_login)
1593 		return (0);
1594 	/* loop all rps to check if the cmd have already been drained */
1595 	for (i = 0; i < rportid_table_size; i++) {
1596 		irp = iport->iport_rp_tb[i];
1597 		while (irp) {
1598 			if (irp->irp_fcp_xchg_count ||
1599 			    irp->irp_nonfcp_xchg_count)
1600 				return (0);
1601 			irp = irp->irp_next;
1602 		}
1603 	}
1604 	return (1);
1605 }
1606 
1607 fct_cmd_t *
1608 fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle,
1609 		uint32_t rportid, uint8_t *lun, uint16_t cdb_length,
1610 		uint16_t task_ext)
1611 {
1612 	fct_cmd_t *cmd;
1613 	fct_i_cmd_t *icmd;
1614 	fct_i_local_port_t *iport =
1615 	    (fct_i_local_port_t *)port->port_fct_private;
1616 	fct_i_remote_port_t *irp;
1617 	scsi_task_t *task;
1618 	fct_remote_port_t *rp;
1619 	uint16_t cmd_slot;
1620 
1621 	rw_enter(&iport->iport_lock, RW_READER);
1622 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
1623 		rw_exit(&iport->iport_lock);
1624 		stmf_trace(iport->iport_alias, "cmd alloc called while the port"
1625 		    " was offline");
1626 		return (NULL);
1627 	}
1628 
1629 	if (rp_handle == FCT_HANDLE_NONE) {
1630 		irp = fct_portid_to_portptr(iport, rportid);
1631 		if (irp == NULL) {
1632 			rw_exit(&iport->iport_lock);
1633 			stmf_trace(iport->iport_alias, "cmd received from "
1634 			    "non existent port %x", rportid);
1635 			return (NULL);
1636 		}
1637 	} else {
1638 		if ((rp_handle >= port->port_max_logins) ||
1639 		    ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) {
1640 			rw_exit(&iport->iport_lock);
1641 			stmf_trace(iport->iport_alias, "cmd received from "
1642 			    "invalid port handle %x", rp_handle);
1643 			return (NULL);
1644 		}
1645 	}
1646 	rp = irp->irp_rp;
1647 
1648 	rw_enter(&irp->irp_lock, RW_READER);
1649 	if ((irp->irp_flags & IRP_PRLI_DONE) == 0) {
1650 		rw_exit(&irp->irp_lock);
1651 		rw_exit(&iport->iport_lock);
1652 		stmf_trace(iport->iport_alias, "cmd alloc called while fcp "
1653 		    "login was not done. portid=%x, rp=%p", rp->rp_id, rp);
1654 		return (NULL);
1655 	}
1656 
1657 	mutex_enter(&iport->iport_cached_cmd_lock);
1658 	if ((icmd = iport->iport_cached_cmdlist) != NULL) {
1659 		iport->iport_cached_cmdlist = icmd->icmd_next;
1660 		iport->iport_cached_ncmds--;
1661 		cmd = icmd->icmd_cmd;
1662 	} else {
1663 		icmd = NULL;
1664 	}
1665 	mutex_exit(&iport->iport_cached_cmd_lock);
1666 	if (icmd == NULL) {
1667 		cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1668 		    port->port_fca_fcp_cmd_size, 0);
1669 		if (cmd == NULL) {
1670 			rw_exit(&irp->irp_lock);
1671 			rw_exit(&iport->iport_lock);
1672 			stmf_trace(iport->iport_alias, "Ran out of "
1673 			    "memory, port=%p", port);
1674 			return (NULL);
1675 		}
1676 
1677 		icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1678 		icmd->icmd_next = NULL;
1679 		cmd->cmd_port = port;
1680 		atomic_add_32(&iport->iport_total_alloced_ncmds, 1);
1681 	}
1682 
1683 	/*
1684 	 * The accuracy of iport_max_active_ncmds is not important
1685 	 */
1686 	if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1687 	    iport->iport_max_active_ncmds) {
1688 		iport->iport_max_active_ncmds =
1689 		    iport->iport_total_alloced_ncmds -
1690 		    iport->iport_cached_ncmds;
1691 	}
1692 
1693 	/* Lets get a slot */
1694 	cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1695 	if (cmd_slot == FCT_SLOT_EOL) {
1696 		rw_exit(&irp->irp_lock);
1697 		rw_exit(&iport->iport_lock);
1698 		stmf_trace(iport->iport_alias, "Ran out of xchg resources");
1699 		cmd->cmd_handle = 0;
1700 		fct_cmd_free(cmd);
1701 		return (NULL);
1702 	}
1703 	atomic_add_16(&irp->irp_fcp_xchg_count, 1);
1704 	cmd->cmd_rp = rp;
1705 	icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA;
1706 	rw_exit(&irp->irp_lock);
1707 	rw_exit(&iport->iport_lock);
1708 
1709 	icmd->icmd_start_time = ddi_get_lbolt();
1710 
1711 	cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session,
1712 	    lun, cdb_length, task_ext);
1713 	if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) {
1714 		task->task_port_private = cmd;
1715 		return (cmd);
1716 	}
1717 
1718 	fct_cmd_free(cmd);
1719 
1720 	return (NULL);
1721 }
1722 
1723 void
1724 fct_scsi_task_free(scsi_task_t *task)
1725 {
1726 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1727 
1728 	cmd->cmd_comp_status = task->task_completion_status;
1729 	fct_cmd_free(cmd);
1730 }
1731 
1732 void
1733 fct_post_rcvd_cmd(fct_cmd_t *cmd, stmf_data_buf_t *dbuf)
1734 {
1735 	fct_dbuf_store_t *fds;
1736 
1737 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
1738 		fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1739 		fct_i_local_port_t *iport =
1740 		    (fct_i_local_port_t *)cmd->cmd_port->port_fct_private;
1741 		fct_i_remote_port_t *irp =
1742 		    (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private;
1743 		scsi_task_t *task = (scsi_task_t *)cmd->cmd_specific;
1744 
1745 		uint16_t irp_task = irp->irp_fcp_xchg_count;
1746 		uint32_t load = iport->iport_total_alloced_ncmds -
1747 		    iport->iport_cached_ncmds;
1748 
1749 		DTRACE_FC_4(scsi__command,
1750 		    fct_cmd_t, cmd,
1751 		    fct_i_local_port_t, iport,
1752 		    scsi_task_t, task,
1753 		    fct_i_remote_port_t, irp);
1754 
1755 		if (load >= iport->iport_task_green_limit) {
1756 			if ((load < iport->iport_task_yellow_limit &&
1757 			    irp_task >= 4) ||
1758 			    (load >= iport->iport_task_yellow_limit &&
1759 			    load < iport->iport_task_red_limit &&
1760 			    irp_task >= 1) ||
1761 			    (load >= iport->iport_task_red_limit))
1762 				task->task_additional_flags |=
1763 				    TASK_AF_PORT_LOAD_HIGH;
1764 		}
1765 		/*
1766 		 * If the target driver accepts sglists, fill in task fields.
1767 		 */
1768 		fds = cmd->cmd_port->port_fds;
1769 		if (fds->fds_setup_dbuf != NULL) {
1770 			task->task_additional_flags |= TASK_AF_ACCEPT_LU_DBUF;
1771 			task->task_copy_threshold = fds->fds_copy_threshold;
1772 			task->task_max_xfer_len = fds->fds_max_sgl_xfer_len;
1773 			/*
1774 			 * A single stream load encounters a little extra
1775 			 * latency if large xfers are done in 1 chunk.
1776 			 * Give a hint to the LU that starting the xfer
1777 			 * with a smaller chunk would be better in this case.
1778 			 * For any other load, use maximum chunk size.
1779 			 */
1780 			if (load == 1) {
1781 				/* estimate */
1782 				task->task_1st_xfer_len = 128*1024;
1783 			} else {
1784 				/* zero means no hint */
1785 				task->task_1st_xfer_len = 0;
1786 			}
1787 		}
1788 
1789 		stmf_post_task((scsi_task_t *)cmd->cmd_specific, dbuf);
1790 		atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_TRANSITION);
1791 		return;
1792 	}
1793 	/* We dont need dbuf for other cmds */
1794 	if (dbuf) {
1795 		cmd->cmd_port->port_fds->fds_free_data_buf(
1796 		    cmd->cmd_port->port_fds, dbuf);
1797 		dbuf = NULL;
1798 	}
1799 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1800 		fct_handle_els(cmd);
1801 		return;
1802 	}
1803 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
1804 		fct_handle_rcvd_abts(cmd);
1805 		return;
1806 	}
1807 
1808 	ASSERT(0);
1809 }
1810 
1811 /*
1812  * This function bypasses fct_handle_els()
1813  */
1814 void
1815 fct_post_implicit_logo(fct_cmd_t *cmd)
1816 {
1817 	fct_local_port_t *port = cmd->cmd_port;
1818 	fct_i_local_port_t *iport =
1819 	    (fct_i_local_port_t *)port->port_fct_private;
1820 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1821 	fct_remote_port_t *rp = cmd->cmd_rp;
1822 	fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1823 
1824 	icmd->icmd_start_time = ddi_get_lbolt();
1825 
1826 	rw_enter(&irp->irp_lock, RW_WRITER);
1827 	atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
1828 	atomic_add_16(&irp->irp_nonfcp_xchg_count, 1);
1829 	atomic_add_16(&irp->irp_sa_elses_count, 1);
1830 	/*
1831 	 * An implicit LOGO can also be posted to a irp where a PLOGI might
1832 	 * be in process. That PLOGI will reset this flag and decrement the
1833 	 * iport_nrps_login counter.
1834 	 */
1835 	if (irp->irp_flags & IRP_PLOGI_DONE) {
1836 		atomic_add_32(&iport->iport_nrps_login, -1);
1837 	}
1838 	atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1839 	atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1840 	fct_post_to_discovery_queue(iport, irp, icmd);
1841 	rw_exit(&irp->irp_lock);
1842 }
1843 
1844 /*
1845  * called with iport_lock held, return the slot number
1846  */
1847 uint16_t
1848 fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd)
1849 {
1850 	uint16_t cmd_slot;
1851 	uint32_t old, new;
1852 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1853 
1854 	do {
1855 		old = iport->iport_next_free_slot;
1856 		cmd_slot = old & 0xFFFF;
1857 		if (cmd_slot == FCT_SLOT_EOL)
1858 			return (cmd_slot);
1859 		/*
1860 		 * We use high order 16 bits as a counter which keeps on
1861 		 * incrementing to avoid ABA issues with atomic lists.
1862 		 */
1863 		new = ((old + (0x10000)) & 0xFFFF0000);
1864 		new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1865 	} while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1866 
1867 	atomic_add_16(&iport->iport_nslots_free, -1);
1868 	iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1869 	cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1870 	    (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1871 	    << 24);
1872 	return (cmd_slot);
1873 }
1874 
1875 /*
1876  * If icmd is not NULL, irp_lock must be held
1877  */
1878 void
1879 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1880     fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1881 {
1882 	fct_i_cmd_t	**p;
1883 
1884 	ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1885 	if (icmd) {
1886 		icmd->icmd_next = NULL;
1887 		for (p = &irp->irp_els_list; *p != NULL;
1888 		    p = &((*p)->icmd_next))
1889 			;
1890 
1891 		*p = icmd;
1892 		atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
1893 	}
1894 
1895 	mutex_enter(&iport->iport_worker_lock);
1896 	if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1897 
1898 		/*
1899 		 * CAUTION: do not grab local_port/remote_port locks after
1900 		 * grabbing the worker lock.
1901 		 */
1902 		irp->irp_discovery_next = NULL;
1903 		if (iport->iport_rpwe_tail) {
1904 			iport->iport_rpwe_tail->irp_discovery_next = irp;
1905 			iport->iport_rpwe_tail = irp;
1906 		} else {
1907 			iport->iport_rpwe_head = iport->iport_rpwe_tail = irp;
1908 		}
1909 
1910 		atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE);
1911 	}
1912 
1913 	/*
1914 	 * We need always signal the port worker irrespective of the fact that
1915 	 * irp is already in discovery queue or not.
1916 	 */
1917 	if (IS_WORKER_SLEEPING(iport)) {
1918 		cv_signal(&iport->iport_worker_cv);
1919 	}
1920 	mutex_exit(&iport->iport_worker_lock);
1921 }
1922 
1923 stmf_status_t
1924 fct_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
1925 {
1926 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1927 
1928 	DTRACE_FC_5(xfer__start,
1929 	    fct_cmd_t, cmd,
1930 	    fct_i_local_port_t, cmd->cmd_port->port_fct_private,
1931 	    scsi_task_t, task,
1932 	    fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
1933 	    stmf_data_buf_t, dbuf);
1934 
1935 	return (cmd->cmd_port->port_xfer_scsi_data(cmd, dbuf, ioflags));
1936 }
1937 
1938 void
1939 fct_scsi_data_xfer_done(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
1940 {
1941 	fct_i_cmd_t	*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1942 	uint32_t	old, new;
1943 	uint32_t	iof = 0;
1944 
1945 	DTRACE_FC_5(xfer__done,
1946 	    fct_cmd_t, cmd,
1947 	    fct_i_local_port_t, cmd->cmd_port->port_fct_private,
1948 	    scsi_task_t, ((scsi_task_t *)cmd->cmd_specific),
1949 	    fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
1950 	    stmf_data_buf_t, dbuf);
1951 
1952 	if (ioflags & FCT_IOF_FCA_DONE) {
1953 		do {
1954 			old = new = icmd->icmd_flags;
1955 			if (old & ICMD_BEING_ABORTED) {
1956 				return;
1957 			}
1958 			new &= ~ICMD_KNOWN_TO_FCA;
1959 		} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
1960 		iof = STMF_IOF_LPORT_DONE;
1961 		cmd->cmd_comp_status = dbuf->db_xfer_status;
1962 	}
1963 
1964 	if (icmd->icmd_flags & ICMD_BEING_ABORTED)
1965 		return;
1966 	stmf_data_xfer_done((scsi_task_t *)cmd->cmd_specific, dbuf, iof);
1967 }
1968 
1969 stmf_status_t
1970 fct_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
1971 {
1972 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1973 
1974 	DTRACE_FC_4(scsi__response,
1975 	    fct_cmd_t, cmd,
1976 	    fct_i_local_port_t,
1977 	    (fct_i_local_port_t *)cmd->cmd_port->port_fct_private,
1978 	    scsi_task_t, task,
1979 	    fct_i_remote_port_t,
1980 	    (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private);
1981 
1982 	return (cmd->cmd_port->port_send_cmd_response(cmd, ioflags));
1983 }
1984 
1985 void
1986 fct_send_response_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
1987 {
1988 	fct_i_cmd_t	*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1989 	fct_local_port_t *port = cmd->cmd_port;
1990 	fct_i_local_port_t *iport = (fct_i_local_port_t *)
1991 	    port->port_fct_private;
1992 	uint32_t old, new;
1993 
1994 	if ((ioflags & FCT_IOF_FCA_DONE) == 0) {
1995 		/* Until we support confirmed completions, this is an error */
1996 		fct_queue_cmd_for_termination(cmd, s);
1997 		return;
1998 	}
1999 	do {
2000 		old = new = icmd->icmd_flags;
2001 		if (old & ICMD_BEING_ABORTED) {
2002 			return;
2003 		}
2004 		new &= ~ICMD_KNOWN_TO_FCA;
2005 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2006 
2007 	cmd->cmd_comp_status = s;
2008 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2009 		stmf_send_status_done((scsi_task_t *)cmd->cmd_specific, s,
2010 		    STMF_IOF_LPORT_DONE);
2011 		return;
2012 	}
2013 
2014 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
2015 		fct_cmd_free(cmd);
2016 		return;
2017 	} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
2018 		fct_handle_sol_els_completion(iport, icmd);
2019 	} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
2020 		/* Tell the caller that we are done */
2021 		atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
2022 	} else {
2023 		ASSERT(0);
2024 	}
2025 }
2026 
2027 void
2028 fct_cmd_free(fct_cmd_t *cmd)
2029 {
2030 	char			info[FCT_INFO_LEN];
2031 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2032 	fct_local_port_t	*port = cmd->cmd_port;
2033 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
2034 	    port->port_fct_private;
2035 	fct_i_remote_port_t	*irp = NULL;
2036 	int			do_abts_acc = 0;
2037 	uint32_t		old, new;
2038 
2039 	ASSERT(!mutex_owned(&iport->iport_worker_lock));
2040 	/* Give the slot back */
2041 	if (CMD_HANDLE_VALID(cmd->cmd_handle)) {
2042 		uint16_t n = CMD_HANDLE_SLOT_INDEX(cmd->cmd_handle);
2043 		fct_cmd_slot_t *slot;
2044 
2045 		/*
2046 		 * If anything went wrong, grab the lock as writer. This is
2047 		 * probably unnecessary.
2048 		 */
2049 		if ((cmd->cmd_comp_status != FCT_SUCCESS) ||
2050 		    (icmd->icmd_flags & ICMD_ABTS_RECEIVED)) {
2051 			rw_enter(&iport->iport_lock, RW_WRITER);
2052 		} else {
2053 			rw_enter(&iport->iport_lock, RW_READER);
2054 		}
2055 
2056 		if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) &&
2057 		    (cmd->cmd_link != NULL)) {
2058 			do_abts_acc = 1;
2059 		}
2060 
2061 		/* XXX Validate slot before freeing */
2062 
2063 		slot = &iport->iport_cmd_slots[n];
2064 		slot->slot_uniq_cntr++;
2065 		slot->slot_cmd = NULL;
2066 		do {
2067 			old = iport->iport_next_free_slot;
2068 			slot->slot_next = old & 0xFFFF;
2069 			new = (old + 0x10000) & 0xFFFF0000;
2070 			new |= slot->slot_no;
2071 		} while (atomic_cas_32(&iport->iport_next_free_slot,
2072 		    old, new) != old);
2073 		cmd->cmd_handle = 0;
2074 		atomic_add_16(&iport->iport_nslots_free, 1);
2075 		if (cmd->cmd_rp) {
2076 			irp = (fct_i_remote_port_t *)
2077 			    cmd->cmd_rp->rp_fct_private;
2078 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2079 				atomic_add_16(&irp->irp_fcp_xchg_count, -1);
2080 			else
2081 				atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
2082 		}
2083 		rw_exit(&iport->iport_lock);
2084 	} else if ((icmd->icmd_flags & ICMD_IMPLICIT) &&
2085 	    (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) {
2086 		/* for implicit cmd, no cmd slot is used */
2087 		if (cmd->cmd_rp) {
2088 			irp = (fct_i_remote_port_t *)
2089 			    cmd->cmd_rp->rp_fct_private;
2090 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2091 				atomic_add_16(&irp->irp_fcp_xchg_count, -1);
2092 			else
2093 				atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
2094 		}
2095 	}
2096 
2097 	if (do_abts_acc) {
2098 		fct_cmd_t *lcmd = cmd->cmd_link;
2099 		fct_fill_abts_acc(lcmd);
2100 		if (port->port_send_cmd_response(lcmd,
2101 		    FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2102 			/*
2103 			 * XXX Throw HBA fatal error event
2104 			 * Later shutdown svc will terminate the ABTS in the end
2105 			 */
2106 			(void) snprintf(info, sizeof (info),
2107 			    "fct_cmd_free: iport-%p, ABTS_ACC"
2108 			    " port_send_cmd_response failed", (void *)iport);
2109 			(void) fct_port_shutdown(iport->iport_port,
2110 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2111 			return;
2112 		} else {
2113 			fct_cmd_free(lcmd);
2114 			cmd->cmd_link = NULL;
2115 		}
2116 	}
2117 
2118 	/* Free the cmd */
2119 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2120 		if (iport->iport_cached_ncmds < max_cached_ncmds) {
2121 			icmd->icmd_flags = 0;
2122 			mutex_enter(&iport->iport_cached_cmd_lock);
2123 			icmd->icmd_next = iport->iport_cached_cmdlist;
2124 			iport->iport_cached_cmdlist = icmd;
2125 			iport->iport_cached_ncmds++;
2126 			mutex_exit(&iport->iport_cached_cmd_lock);
2127 		} else {
2128 			atomic_add_32(&iport->iport_total_alloced_ncmds, -1);
2129 			fct_free(cmd);
2130 		}
2131 	} else {
2132 		fct_free(cmd);
2133 	}
2134 }
2135 
2136 /* ARGSUSED */
2137 stmf_status_t
2138 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2139 							uint32_t flags)
2140 {
2141 	stmf_status_t ret = STMF_SUCCESS;
2142 	scsi_task_t *task;
2143 	fct_cmd_t *cmd;
2144 	fct_i_cmd_t *icmd;
2145 	fct_local_port_t *port;
2146 	uint32_t old, new;
2147 
2148 	ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK);
2149 
2150 	task = (scsi_task_t *)arg;
2151 	cmd = (fct_cmd_t *)task->task_port_private;
2152 	icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2153 	port = (fct_local_port_t *)lport->lport_port_private;
2154 
2155 	do {
2156 		old = new = icmd->icmd_flags;
2157 		if ((old & ICMD_KNOWN_TO_FCA) == 0)
2158 			return (STMF_NOT_FOUND);
2159 		ASSERT((old & ICMD_FCA_ABORT_CALLED) == 0);
2160 		new |= ICMD_BEING_ABORTED | ICMD_FCA_ABORT_CALLED;
2161 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2162 	ret = port->port_abort_cmd(port, cmd, 0);
2163 	if ((ret == FCT_NOT_FOUND) || (ret == FCT_ABORT_SUCCESS)) {
2164 		atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2165 	} else if (ret == FCT_BUSY) {
2166 		atomic_and_32(&icmd->icmd_flags, ~ICMD_FCA_ABORT_CALLED);
2167 	}
2168 
2169 	return (ret);
2170 }
2171 
2172 void
2173 fct_ctl(struct stmf_local_port *lport, int cmd, void *arg)
2174 {
2175 	fct_local_port_t *port;
2176 	fct_i_local_port_t *iport;
2177 	stmf_change_status_t st;
2178 	stmf_change_status_t *pst;
2179 
2180 	ASSERT((cmd == STMF_CMD_LPORT_ONLINE) ||
2181 	    (cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
2182 	    (cmd == STMF_CMD_LPORT_OFFLINE) ||
2183 	    (cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE) ||
2184 	    (cmd == FCT_CMD_PORT_ONLINE_COMPLETE) ||
2185 	    (cmd == FCT_CMD_PORT_OFFLINE_COMPLETE));
2186 
2187 	port = (fct_local_port_t *)lport->lport_port_private;
2188 	pst = (stmf_change_status_t *)arg;
2189 	st.st_completion_status = STMF_SUCCESS;
2190 	st.st_additional_info = NULL;
2191 
2192 	iport = (fct_i_local_port_t *)port->port_fct_private;
2193 	/*
2194 	 * We are mostly a passthrough, except during offline.
2195 	 */
2196 	switch (cmd) {
2197 	case STMF_CMD_LPORT_ONLINE:
2198 		if (iport->iport_state == FCT_STATE_ONLINE)
2199 			st.st_completion_status = STMF_ALREADY;
2200 		else if (iport->iport_state != FCT_STATE_OFFLINE)
2201 			st.st_completion_status = STMF_INVALID_ARG;
2202 		if (st.st_completion_status != STMF_SUCCESS) {
2203 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport,
2204 			    &st);
2205 			break;
2206 		}
2207 		iport->iport_state_not_acked = 1;
2208 		iport->iport_state = FCT_STATE_ONLINING;
2209 		port->port_ctl(port, FCT_CMD_PORT_ONLINE, arg);
2210 		break;
2211 	case FCT_CMD_PORT_ONLINE_COMPLETE:
2212 		ASSERT(iport->iport_state == FCT_STATE_ONLINING);
2213 		if (pst->st_completion_status != FCT_SUCCESS) {
2214 			iport->iport_state = FCT_STATE_OFFLINE;
2215 			iport->iport_state_not_acked = 0;
2216 		} else {
2217 			iport->iport_state = FCT_STATE_ONLINE;
2218 		}
2219 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, arg);
2220 		break;
2221 	case STMF_ACK_LPORT_ONLINE_COMPLETE:
2222 		ASSERT(iport->iport_state == FCT_STATE_ONLINE);
2223 		iport->iport_state_not_acked = 0;
2224 		port->port_ctl(port, FCT_ACK_PORT_ONLINE_COMPLETE, arg);
2225 		break;
2226 
2227 	case STMF_CMD_LPORT_OFFLINE:
2228 		if (iport->iport_state == FCT_STATE_OFFLINE)
2229 			st.st_completion_status = STMF_ALREADY;
2230 		else if (iport->iport_state != FCT_STATE_ONLINE)
2231 			st.st_completion_status = STMF_INVALID_ARG;
2232 		if (st.st_completion_status != STMF_SUCCESS) {
2233 			(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
2234 			    &st);
2235 			break;
2236 		}
2237 		iport->iport_state_not_acked = 1;
2238 		iport->iport_state = FCT_STATE_OFFLINING;
2239 		port->port_ctl(port, FCT_CMD_PORT_OFFLINE, arg);
2240 		break;
2241 	case FCT_CMD_PORT_OFFLINE_COMPLETE:
2242 		ASSERT(iport->iport_state == FCT_STATE_OFFLINING);
2243 		if (pst->st_completion_status != FCT_SUCCESS) {
2244 			iport->iport_state = FCT_STATE_ONLINE;
2245 			iport->iport_state_not_acked = 0;
2246 			(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
2247 			    pst);
2248 			break;
2249 		}
2250 
2251 		/*
2252 		 * If FCA's offline was successful, we dont tell stmf yet.
2253 		 * Becasue now we have to do the cleanup before we go upto
2254 		 * stmf. That cleanup is done by the worker thread.
2255 		 */
2256 
2257 		/* FCA is offline, post a link down, its harmless anyway */
2258 		fct_handle_event(port, FCT_EVENT_LINK_DOWN, 0, 0);
2259 
2260 		/* Trigger port offline processing by the worker */
2261 		iport->iport_offline_prstate = FCT_OPR_START;
2262 		break;
2263 	case STMF_ACK_LPORT_OFFLINE_COMPLETE:
2264 		ASSERT(iport->iport_state == FCT_STATE_OFFLINE);
2265 		iport->iport_state_not_acked = 0;
2266 		port->port_ctl(port, FCT_ACK_PORT_OFFLINE_COMPLETE, arg);
2267 		break;
2268 	}
2269 }
2270 
2271 /* ARGSUSED */
2272 stmf_status_t
2273 fct_info(uint32_t cmd, stmf_local_port_t *lport, void *arg, uint8_t *buf,
2274 						uint32_t *bufsizep)
2275 {
2276 	return (STMF_NOT_SUPPORTED);
2277 }
2278 
2279 /*
2280  * implicit: if it's true, it means it will only be used in fct module, or else
2281  * it will be sent to the link.
2282  */
2283 fct_cmd_t *
2284 fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp, int implicit,
2285     uchar_t elsop, uint32_t wkdid, fct_icmd_cb_t icmdcb)
2286 {
2287 	fct_cmd_t		*cmd	= NULL;
2288 	fct_i_cmd_t		*icmd	= NULL;
2289 	fct_els_t		*els	= NULL;
2290 	fct_i_remote_port_t	*irp	= NULL;
2291 	uint8_t			*p	= NULL;
2292 	uint32_t		 ptid	= 0;
2293 
2294 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
2295 	    port->port_fca_sol_els_private_size, 0);
2296 	if (!cmd) {
2297 		return (NULL);
2298 	}
2299 
2300 	if (rp) {
2301 		irp = RP_TO_IRP(rp);
2302 	} else if (((irp = fct_portid_to_portptr(PORT_TO_IPORT(port),
2303 	    wkdid)) == NULL) && (elsop != ELS_OP_PLOGI)) {
2304 		stmf_trace(PORT_TO_IPORT(port)->iport_alias,
2305 		    "fct_create_solels: Must PLOGI to %x first", wkdid);
2306 		fct_free(cmd);
2307 		return (NULL);
2308 	}
2309 
2310 	cmd->cmd_port	= port;
2311 	cmd->cmd_oxid	= PTR2INT(cmd, uint16_t);
2312 	cmd->cmd_rxid	= 0xFFFF;
2313 	cmd->cmd_handle = 0;
2314 	icmd		= CMD_TO_ICMD(cmd);
2315 	els		= ICMD_TO_ELS(icmd);
2316 	icmd->icmd_cb	= icmdcb;
2317 	if (irp) {
2318 		cmd->cmd_rp	   = irp->irp_rp;
2319 		cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
2320 		cmd->cmd_rportid   = irp->irp_rp->rp_id;
2321 	} else {
2322 		cmd->cmd_rp_handle = FCT_HANDLE_NONE;
2323 		cmd->cmd_rportid   = wkdid;
2324 	}
2325 	cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid;
2326 
2327 	if (implicit) {
2328 		/*
2329 		 * Since we will not send it to FCA, so we only allocate space
2330 		 */
2331 		ASSERT(elsop & (ELS_OP_LOGO | ELS_OP_PLOGI));
2332 		icmd->icmd_flags |= ICMD_IMPLICIT;
2333 		if (elsop == ELS_OP_LOGO) {
2334 			/*
2335 			 * Handling implicit LOGO should dependent on as less
2336 			 * as resources. So a trick here.
2337 			 */
2338 			els->els_req_size = 1;
2339 			els->els_req_payload = cmd->cmd_fca_private;
2340 		} else {
2341 			els->els_req_alloc_size = els->els_req_size = 116;
2342 			els->els_resp_alloc_size = els->els_resp_size = 116;
2343 			els->els_req_payload = (uint8_t *)
2344 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
2345 			els->els_resp_payload = (uint8_t *)
2346 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
2347 		}
2348 	} else {
2349 		/*
2350 		 * Allocate space for its request and response
2351 		 * Fill the request payload according to spec.
2352 		 */
2353 		switch (elsop) {
2354 		case ELS_OP_LOGO:
2355 			els->els_resp_alloc_size = els->els_resp_size = 4;
2356 			els->els_resp_payload = (uint8_t *)kmem_zalloc(
2357 			    els->els_resp_size, KM_SLEEP);
2358 			els->els_req_alloc_size = els->els_req_size = 16;
2359 			els->els_req_payload = (uint8_t *)kmem_zalloc(
2360 			    els->els_req_size, KM_SLEEP);
2361 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2362 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2363 			bcopy(port->port_pwwn, els->els_req_payload + 8, 8);
2364 			break;
2365 
2366 		case ELS_OP_RSCN:
2367 			els->els_resp_alloc_size = els->els_resp_size = 4;
2368 			els->els_resp_payload = (uint8_t *)kmem_zalloc(
2369 			    els->els_resp_size, KM_SLEEP);
2370 			els->els_req_size = els->els_req_alloc_size = 8;
2371 			els->els_req_payload = (uint8_t *)kmem_zalloc(
2372 			    els->els_req_size, KM_SLEEP);
2373 			els->els_req_payload[1] = 0x04;
2374 			els->els_req_payload[3] = 0x08;
2375 			els->els_req_payload[4] |= 0x80;
2376 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2377 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2378 			break;
2379 
2380 		case ELS_OP_PLOGI:
2381 			els->els_resp_alloc_size = els->els_resp_size = 116;
2382 			els->els_resp_payload = (uint8_t *)
2383 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
2384 			els->els_req_alloc_size = els->els_req_size = 116;
2385 			p = els->els_req_payload = (uint8_t *)
2386 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
2387 			bcopy(port->port_pwwn, p + 20, 8);
2388 			bcopy(port->port_nwwn, p + 28, 8);
2389 
2390 			/*
2391 			 * Common service parameters
2392 			 */
2393 			p[0x04] = 0x09;		/* high version */
2394 			p[0x05] = 0x08;		/* low version */
2395 			p[0x06] = 0x00;		/* BB credit: 0x0065 */
2396 			p[0x07] = 0x65;
2397 
2398 			/* CI0: Continuously Increasing Offset - 1 */
2399 			/* RRO: Randomly Relative Offset - 0 */
2400 			/* VVV: Vendor Version Level - 0 */
2401 			/* N-F: N or F Port Payload Sender - 0 (N) */
2402 			/* BBM: BB Credit Management - 0 (Normal) */
2403 			p[0x08] = 0x80;
2404 			p[0x09] = 0x00;
2405 
2406 			/* Max RX size */
2407 			p[0x0A] = 0x08;
2408 			p[0x0B] = 0x00;
2409 
2410 			/* NPTCS: N Port Total Concurrent Sequences - 0x0000 */
2411 			p[0x0C] = 0x00;
2412 			p[0x0D] = 0x00;
2413 
2414 			/* ROIC: Relative Offset By Info - 0xFFFF */
2415 			p[0x0E] = 0xFF;
2416 			p[0x0F] = 0xFF;
2417 
2418 			/* EDTOV: Error Detect Timeout - 0x000007D0 */
2419 			p[0x10] = 0x00;
2420 			p[0x11] = 0x00;
2421 			p[0x12] = 0x07;
2422 			p[0x13] = 0xD0;
2423 
2424 			/*
2425 			 * Class-3 Parameters
2426 			 */
2427 			/* C3-VAL: Class 3 Value - 1 */
2428 			/* C3-XID: X_ID Reassignment - 0 */
2429 			/* C3-IPA: Initial Process Assignment */
2430 			/* C3-AI-DCC: Data compression capable */
2431 			/* C3-AI-DC-HB: Data compression history buffer size */
2432 			/* C3-AI-DCE: Data encrytion capable */
2433 			/* C3-AI-CSC: Clock synchronization capable */
2434 			/* C3-ErrPol: Error pliciy */
2435 			/* C3-CatSeq: Information Cat. Per Sequence */
2436 			/* C3-AR-DCC: */
2437 			/* C3-AR-DC-HB: */
2438 			/* C3-AR-DCE: */
2439 			/* C3-AR-CSC */
2440 			p[0x44] = 0x80;
2441 			p[0x45] = 0x00;
2442 			p[0x46] = 0x00;
2443 			p[0x47] = 0x00;
2444 			p[0x48] = 0x00;
2445 			p[0x49] = 0x00;
2446 
2447 			/* C3-RxSize: Class 3 receive data size */
2448 			p[0x4A] = 0x08;
2449 			p[0x4B] = 0x00;
2450 
2451 			/* C3-ConSeq: Class 3 Concourrent sequences */
2452 			p[0x4C] = 0x00;
2453 			p[0x4D] = 0xFF;
2454 
2455 			/* C3-OSPE: Class 3 open sequence per exchange */
2456 			p[0x50] = 0x00;
2457 			p[0x51] = 0x01;
2458 
2459 			break;
2460 
2461 		case ELS_OP_SCR:
2462 			els->els_resp_alloc_size = els->els_resp_size = 4;
2463 			els->els_resp_payload = (uint8_t *)
2464 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
2465 			els->els_req_alloc_size = els->els_req_size = 8;
2466 			p = els->els_req_payload = (uint8_t *)
2467 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
2468 			p[7] = FC_SCR_FULL_REGISTRATION;
2469 			break;
2470 		case ELS_OP_RLS:
2471 			els->els_resp_alloc_size = els->els_resp_size = 28;
2472 			els->els_resp_payload = (uint8_t *)
2473 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
2474 			els->els_req_alloc_size = els->els_req_size = 8;
2475 			p = els->els_req_payload = (uint8_t *)
2476 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
2477 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2478 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2479 			break;
2480 
2481 		default:
2482 			ASSERT(0);
2483 		}
2484 	}
2485 
2486 	els->els_req_payload[0] = elsop;
2487 	return (cmd);
2488 }
2489 
2490 fct_cmd_t *
2491 fct_create_solct(fct_local_port_t *port, fct_remote_port_t *query_rp,
2492     uint16_t ctop, fct_icmd_cb_t icmdcb)
2493 {
2494 	fct_cmd_t		*cmd	 = NULL;
2495 	fct_i_cmd_t		*icmd	 = NULL;
2496 	fct_sol_ct_t		*ct	 = NULL;
2497 	uint8_t			*p	 = NULL;
2498 	fct_i_remote_port_t	*irp	 = NULL;
2499 	fct_i_local_port_t	*iport	 = NULL;
2500 	char			*nname	 = NULL;
2501 	int			 namelen = 0;
2502 
2503 	/*
2504 	 * Allocate space
2505 	 */
2506 	cmd = fct_alloc(FCT_STRUCT_CMD_SOL_CT,
2507 	    port->port_fca_sol_ct_private_size, 0);
2508 	if (!cmd) {
2509 		return (NULL);
2510 	}
2511 
2512 	/*
2513 	 * We should have PLOGIed to the name server (0xFFFFFC)
2514 	 * Caution: this irp is not query_rp->rp_fct_private.
2515 	 */
2516 	irp = fct_portid_to_portptr((fct_i_local_port_t *)
2517 	    port->port_fct_private, FS_NAME_SERVER);
2518 	if (irp == NULL) {
2519 		stmf_trace(PORT_TO_IPORT(port)->iport_alias,
2520 		    "fct_create_solct: Must PLOGI name server first");
2521 		fct_free(cmd);
2522 		return (NULL);
2523 	}
2524 
2525 	cmd->cmd_port	   = port;
2526 	cmd->cmd_rp	   = irp->irp_rp;
2527 	cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
2528 	cmd->cmd_rportid   = irp->irp_rp->rp_id;
2529 	cmd->cmd_lportid   = (PORT_TO_IPORT(port))->iport_link_info.portid;
2530 	cmd->cmd_oxid	   = PTR2INT(cmd, uint16_t);
2531 	cmd->cmd_rxid	   = 0xFFFF;
2532 	cmd->cmd_handle	   = 0;
2533 	icmd		   = CMD_TO_ICMD(cmd);
2534 	ct		   = ICMD_TO_CT(icmd);
2535 	icmd->icmd_cb	   = icmdcb;
2536 	iport		   = ICMD_TO_IPORT(icmd);
2537 
2538 	switch (ctop) {
2539 	case NS_GSNN_NN:
2540 		/*
2541 		 * Allocate max space for its sybolic name
2542 		 */
2543 		ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
2544 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2545 		    KM_SLEEP);
2546 
2547 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
2548 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2549 		    KM_SLEEP);
2550 
2551 		bcopy(query_rp->rp_nwwn, p + 16, 8);
2552 		break;
2553 
2554 	case NS_RNN_ID:
2555 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2556 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2557 		    KM_SLEEP);
2558 		ct->ct_req_size = ct->ct_req_alloc_size = 28;
2559 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2560 		    KM_SLEEP);
2561 
2562 		/*
2563 		 * Port Identifier
2564 		 */
2565 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2566 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
2567 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
2568 
2569 		/*
2570 		 * Node Name
2571 		 */
2572 		bcopy(port->port_nwwn, p + 20, 8);
2573 		break;
2574 
2575 	case NS_RCS_ID:
2576 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2577 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2578 		    KM_SLEEP);
2579 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
2580 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2581 		    KM_SLEEP);
2582 
2583 		/*
2584 		 * Port Identifier
2585 		 */
2586 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2587 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
2588 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
2589 
2590 		/*
2591 		 * Class of Service
2592 		 */
2593 		*(p + 23) = FC_NS_CLASS3;
2594 		break;
2595 
2596 	case NS_RFT_ID:
2597 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2598 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2599 		    KM_SLEEP);
2600 		ct->ct_req_size = ct->ct_req_alloc_size = 52;
2601 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2602 		    KM_SLEEP);
2603 
2604 		/*
2605 		 * Port Identifier
2606 		 */
2607 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2608 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
2609 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
2610 
2611 		/*
2612 		 * FC-4 Protocol Types
2613 		 */
2614 		*(p + 22) = 0x1;	/* 0x100 */
2615 		break;
2616 
2617 	case NS_RSPN_ID:
2618 		/*
2619 		 * If we get here, port->port_sym_port_name is always not NULL.
2620 		 */
2621 		ASSERT(port->port_sym_port_name);
2622 		namelen = strlen(port->port_sym_port_name);
2623 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2624 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2625 		    KM_SLEEP);
2626 		ct->ct_req_size = ct->ct_req_alloc_size =
2627 		    (21 + namelen + 3) & ~3;
2628 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2629 		    KM_SLEEP);
2630 
2631 		/*
2632 		 * Port Identifier
2633 		 */
2634 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2635 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
2636 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
2637 
2638 		/*
2639 		 * String length
2640 		 */
2641 		p[20] = namelen;
2642 
2643 		/*
2644 		 * Symbolic port name
2645 		 */
2646 		bcopy(port->port_sym_port_name, p + 21, ct->ct_req_size - 21);
2647 		break;
2648 
2649 	case NS_RSNN_NN:
2650 		namelen = port->port_sym_node_name == NULL ?
2651 		    strlen(utsname.nodename) :
2652 		    strlen(port->port_sym_node_name);
2653 		nname = port->port_sym_node_name == NULL ?
2654 		    utsname.nodename : port->port_sym_node_name;
2655 
2656 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2657 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2658 		    KM_SLEEP);
2659 		ct->ct_req_size = ct->ct_req_alloc_size =
2660 		    (25 + namelen + 3) & ~3;
2661 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2662 		    KM_SLEEP);
2663 
2664 		/*
2665 		 * Node name
2666 		 */
2667 		bcopy(port->port_nwwn, p + 16, 8);
2668 
2669 		/*
2670 		 * String length
2671 		 */
2672 		p[24] = namelen;
2673 
2674 		/*
2675 		 * Symbolic node name
2676 		 */
2677 		bcopy(nname, p + 25, ct->ct_req_size - 25);
2678 		break;
2679 
2680 	case NS_GSPN_ID:
2681 		ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
2682 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2683 		    KM_SLEEP);
2684 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
2685 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2686 		    KM_SLEEP);
2687 		/*
2688 		 * Port Identifier
2689 		 */
2690 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
2691 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
2692 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
2693 		break;
2694 
2695 	case NS_GCS_ID:
2696 		ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
2697 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2698 		    KM_SLEEP);
2699 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
2700 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2701 		    KM_SLEEP);
2702 		/*
2703 		 * Port Identifier
2704 		 */
2705 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
2706 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
2707 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
2708 		break;
2709 
2710 	case NS_GFT_ID:
2711 		ct->ct_resp_alloc_size = ct->ct_resp_size = 48;
2712 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2713 		    KM_SLEEP);
2714 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
2715 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2716 		    KM_SLEEP);
2717 		/*
2718 		 * Port Identifier
2719 		 */
2720 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
2721 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
2722 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
2723 		break;
2724 
2725 	case NS_GID_PN:
2726 		ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
2727 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2728 		    KM_SLEEP);
2729 
2730 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
2731 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2732 		    KM_SLEEP);
2733 
2734 		bcopy(query_rp->rp_pwwn, p + 16, 8);
2735 		break;
2736 
2737 	default:
2738 		/* CONSTCOND */
2739 		ASSERT(0);
2740 	}
2741 
2742 	FCT_FILL_CTIU_PREAMPLE(p, ctop);
2743 	return (cmd);
2744 }
2745 
2746 /*
2747  * Cmd can only be solicited CT/ELS. They will be dispatched to the discovery
2748  * queue eventually too.
2749  * We queue solicited cmds here to track solicited cmds and to take full use
2750  * of single thread mechanism.
2751  * But in current implmentation, we don't use  this mechanism on SOL_CT, PLOGI.
2752  * To avoid to interrupt current flow, ICMD_IN_SOLCMD_QUEUE is used here.
2753  */
2754 void
2755 fct_post_to_solcmd_queue(fct_local_port_t *port, fct_cmd_t *cmd)
2756 {
2757 	fct_i_local_port_t	*iport	= (fct_i_local_port_t *)
2758 	    port->port_fct_private;
2759 	fct_i_cmd_t *icmd		= (fct_i_cmd_t *)cmd->cmd_fct_private;
2760 
2761 	mutex_enter(&iport->iport_worker_lock);
2762 	icmd->icmd_solcmd_next = iport->iport_solcmd_queue;
2763 	iport->iport_solcmd_queue = icmd;
2764 	atomic_or_32(&icmd->icmd_flags, ICMD_IN_SOLCMD_QUEUE | ICMD_SOLCMD_NEW);
2765 	if (IS_WORKER_SLEEPING(iport)) {
2766 		cv_signal(&iport->iport_worker_cv);
2767 	}
2768 	mutex_exit(&iport->iport_worker_lock);
2769 }
2770 
2771 /* ARGSUSED */
2772 void
2773 fct_event_handler(stmf_local_port_t *lport, int eventid, void *arg,
2774     uint32_t flags)
2775 {
2776 	fct_local_port_t	*port  = (fct_local_port_t *)
2777 	    lport->lport_port_private;
2778 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
2779 	    port->port_fct_private;
2780 	stmf_scsi_session_t	*ss;
2781 	fct_i_remote_port_t	*irp;
2782 
2783 	switch (eventid) {
2784 	case LPORT_EVENT_INITIAL_LUN_MAPPED:
2785 		ss = (stmf_scsi_session_t *)arg;
2786 		irp = (fct_i_remote_port_t *)ss->ss_port_private;
2787 		stmf_trace(iport->iport_alias,
2788 		    "Initial LUN mapped to session ss-%p, irp-%p", ss, irp);
2789 		break;
2790 
2791 	default:
2792 		stmf_trace(iport->iport_alias,
2793 		    "Unknown event received, %d", eventid);
2794 	}
2795 }
2796 
2797 void
2798 fct_send_cmd_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
2799 {
2800 	/* XXX For now just call send_resp_done() */
2801 	fct_send_response_done(cmd, s, ioflags);
2802 }
2803 
2804 void
2805 fct_cmd_fca_aborted(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
2806 {
2807 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2808 	char			info[FCT_INFO_LEN];
2809 	unsigned long long	st;
2810 
2811 	st = s;	/* To make gcc happy */
2812 	ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED);
2813 	if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
2814 	    ((ioflags & FCT_IOF_FCA_DONE) == 0)) {
2815 		(void) snprintf(info, sizeof (info),
2816 		    "fct_cmd_fca_aborted: cmd-%p, "
2817 		    "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags);
2818 		(void) fct_port_shutdown(cmd->cmd_port,
2819 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2820 		return;
2821 	}
2822 
2823 	atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2824 	/* For non FCP Rest of the work is done by the terminator */
2825 	/* For FCP stuff just call stmf */
2826 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2827 		stmf_task_lport_aborted((scsi_task_t *)cmd->cmd_specific,
2828 		    s, STMF_IOF_LPORT_DONE);
2829 	}
2830 }
2831 
2832 /*
2833  * FCA drivers will use it, when they want to abort some FC transactions
2834  * due to lack of resource.
2835  */
2836 uint16_t
2837 fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid)
2838 {
2839 	fct_i_remote_port_t	*irp;
2840 
2841 	irp = fct_portid_to_portptr(
2842 	    (fct_i_local_port_t *)(port->port_fct_private), rportid);
2843 	if (irp == NULL) {
2844 		return (0xFFFF);
2845 	} else {
2846 		return (irp->irp_rp->rp_handle);
2847 	}
2848 }
2849 
2850 fct_cmd_t *
2851 fct_handle_to_cmd(fct_local_port_t *port, uint32_t fct_handle)
2852 {
2853 	fct_cmd_slot_t *slot;
2854 	uint16_t ndx;
2855 
2856 	if (!CMD_HANDLE_VALID(fct_handle))
2857 		return (NULL);
2858 	if ((ndx = CMD_HANDLE_SLOT_INDEX(fct_handle)) >= port->port_max_xchges)
2859 		return (NULL);
2860 
2861 	slot = &((fct_i_local_port_t *)port->port_fct_private)->iport_cmd_slots[
2862 	    ndx];
2863 
2864 	if ((slot->slot_uniq_cntr | 0x80) != (fct_handle >> 24))
2865 		return (NULL);
2866 	return (slot->slot_cmd->icmd_cmd);
2867 }
2868 
2869 void
2870 fct_queue_scsi_task_for_termination(fct_cmd_t *cmd, fct_status_t s)
2871 {
2872 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2873 
2874 	uint32_t old, new;
2875 
2876 	do {
2877 		old = icmd->icmd_flags;
2878 		if ((old & (ICMD_BEING_ABORTED | ICMD_KNOWN_TO_FCA)) !=
2879 		    ICMD_KNOWN_TO_FCA)
2880 			return;
2881 		new = old | ICMD_BEING_ABORTED;
2882 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2883 	stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific,
2884 	    s, NULL);
2885 }
2886 
2887 void
2888 fct_fill_abts_acc(fct_cmd_t *cmd)
2889 {
2890 	fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
2891 	uint8_t *p;
2892 
2893 	abts->abts_resp_rctl = BLS_OP_BA_ACC;
2894 	p = abts->abts_resp_payload;
2895 	bzero(p, 12);
2896 	*((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid);
2897 	*((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid);
2898 	p[10] = p[11] = 0xff;
2899 }
2900 
2901 void
2902 fct_handle_rcvd_abts(fct_cmd_t *cmd)
2903 {
2904 	char			info[FCT_INFO_LEN];
2905 	fct_local_port_t	*port = cmd->cmd_port;
2906 	fct_i_local_port_t	*iport =
2907 	    (fct_i_local_port_t *)port->port_fct_private;
2908 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2909 	fct_i_remote_port_t	*irp;
2910 	fct_cmd_t		*c = NULL;
2911 	fct_i_cmd_t		*ic = NULL;
2912 	int			found = 0;
2913 	int			i;
2914 
2915 	icmd->icmd_start_time = ddi_get_lbolt();
2916 	icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
2917 
2918 	rw_enter(&iport->iport_lock, RW_WRITER);
2919 	/* Make sure local port is sane */
2920 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2921 		rw_exit(&iport->iport_lock);
2922 		stmf_trace(iport->iport_alias, "ABTS not posted becasue"
2923 		    "port state was %x", iport->iport_link_state);
2924 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2925 		return;
2926 	}
2927 
2928 	if (cmd->cmd_rp_handle == FCT_HANDLE_NONE)
2929 		irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
2930 	else if (cmd->cmd_rp_handle < port->port_max_logins)
2931 		irp = iport->iport_rp_slots[cmd->cmd_rp_handle];
2932 	else
2933 		irp = NULL;
2934 	if (irp == NULL) {
2935 		/* XXX Throw a logout to the initiator */
2936 		rw_exit(&iport->iport_lock);
2937 		stmf_trace(iport->iport_alias, "ABTS received from"
2938 		    " %x without a session", cmd->cmd_rportid);
2939 		fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
2940 		return;
2941 	}
2942 
2943 	DTRACE_FC_3(abts__receive,
2944 	    fct_cmd_t, cmd,
2945 	    fct_local_port_t, port,
2946 	    fct_i_remote_port_t, irp);
2947 
2948 	cmd->cmd_rp = irp->irp_rp;
2949 
2950 	/*
2951 	 * No need to allocate an xchg resource. ABTSes use the same
2952 	 * xchg resource as the cmd they are aborting.
2953 	 */
2954 	rw_enter(&irp->irp_lock, RW_WRITER);
2955 	mutex_enter(&iport->iport_worker_lock);
2956 	/* Lets find the command first */
2957 	for (i = 0; i < port->port_max_xchges; i++) {
2958 		if ((ic = iport->iport_cmd_slots[i].slot_cmd) == NULL)
2959 			continue;
2960 		if ((ic->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
2961 			continue;
2962 		c = ic->icmd_cmd;
2963 		if (!CMD_HANDLE_VALID(c->cmd_handle))
2964 			continue;
2965 		if ((c->cmd_rportid != cmd->cmd_rportid) ||
2966 		    (c->cmd_oxid != cmd->cmd_oxid))
2967 			continue;
2968 		/* Found the command */
2969 		found = 1;
2970 		break;
2971 	}
2972 	if (!found) {
2973 		mutex_exit(&iport->iport_worker_lock);
2974 		rw_exit(&irp->irp_lock);
2975 		rw_exit(&iport->iport_lock);
2976 		/* Dont even bother queueing it. Just respond */
2977 		fct_fill_abts_acc(cmd);
2978 		if (port->port_send_cmd_response(cmd,
2979 		    FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2980 			/*
2981 			 * XXX Throw HBA fatal error event
2982 			 * Later shutdown svc will terminate the ABTS in the end
2983 			 */
2984 			(void) snprintf(info, sizeof (info),
2985 			    "fct_handle_rcvd_abts: iport-%p, "
2986 			    "ABTS_ACC port_send_cmd_response failed",
2987 			    (void *)iport);
2988 			(void) fct_port_shutdown(iport->iport_port,
2989 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2990 		} else {
2991 			fct_cmd_free(cmd);
2992 		}
2993 		return;
2994 	}
2995 
2996 	/* Check if this an abts retry */
2997 	if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) {
2998 		/* Kill this abts. */
2999 		fct_q_for_termination_lock_held(iport, icmd, FCT_ABORTED);
3000 		if (IS_WORKER_SLEEPING(iport))
3001 			cv_signal(&iport->iport_worker_cv);
3002 		mutex_exit(&iport->iport_worker_lock);
3003 		rw_exit(&irp->irp_lock);
3004 		rw_exit(&iport->iport_lock);
3005 		return;
3006 	}
3007 	c->cmd_link = cmd;
3008 	atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED);
3009 	cmd->cmd_link = c;
3010 	mutex_exit(&iport->iport_worker_lock);
3011 	rw_exit(&irp->irp_lock);
3012 	fct_queue_cmd_for_termination(c, FCT_ABTS_RECEIVED);
3013 	rw_exit(&iport->iport_lock);
3014 }
3015 
3016 void
3017 fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s)
3018 {
3019 	fct_local_port_t *port = cmd->cmd_port;
3020 	fct_i_local_port_t *iport = (fct_i_local_port_t *)
3021 	    port->port_fct_private;
3022 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
3023 
3024 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3025 		fct_queue_scsi_task_for_termination(cmd, s);
3026 		return;
3027 	}
3028 	mutex_enter(&iport->iport_worker_lock);
3029 	fct_q_for_termination_lock_held(iport, icmd, s);
3030 	if (IS_WORKER_SLEEPING(iport))
3031 		cv_signal(&iport->iport_worker_cv);
3032 	mutex_exit(&iport->iport_worker_lock);
3033 }
3034 
3035 /*
3036  * This function will not be called for SCSI CMDS
3037  */
3038 void
3039 fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
3040 		fct_status_t s)
3041 {
3042 	uint32_t old, new;
3043 	fct_i_cmd_t **ppicmd;
3044 
3045 	do {
3046 		old = icmd->icmd_flags;
3047 		if (old & ICMD_BEING_ABORTED)
3048 			return;
3049 		new = old | ICMD_BEING_ABORTED;
3050 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3051 
3052 	icmd->icmd_start_time = ddi_get_lbolt();
3053 	icmd->icmd_cmd->cmd_comp_status = s;
3054 
3055 	icmd->icmd_next = NULL;
3056 	for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
3057 	    ppicmd = &((*ppicmd)->icmd_next))
3058 		;
3059 
3060 	*ppicmd = icmd;
3061 }
3062 
3063 /*
3064  * For those cmds, for which we called fca_abort but it has not yet completed,
3065  * reset the FCA_ABORT_CALLED flag, so that abort can be called again.
3066  * This is done after a FCA offline. The reason is that after offline, the
3067  * firmware is not running so abort will never complete. But if we call it
3068  * again, the FCA will detect that it is not offline and it will
3069  * not call the firmware at all. Most likely it will abort in a synchronous
3070  * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
3071  */
3072 void
3073 fct_reset_flag_abort_called(fct_i_local_port_t *iport)
3074 {
3075 	fct_i_cmd_t *icmd;
3076 	uint32_t old, new;
3077 	int i, do_clear;
3078 
3079 	ASSERT(mutex_owned(&iport->iport_worker_lock));
3080 	mutex_exit(&iport->iport_worker_lock);
3081 	rw_enter(&iport->iport_lock, RW_WRITER);
3082 	mutex_enter(&iport->iport_worker_lock);
3083 
3084 	for (i = 0; i < iport->iport_port->port_max_xchges; i++) {
3085 		if (iport->iport_cmd_slots[i].slot_cmd == NULL)
3086 			continue;
3087 
3088 		icmd = iport->iport_cmd_slots[i].slot_cmd;
3089 
3090 		do {
3091 			old = new = icmd->icmd_flags;
3092 			if ((old & (ICMD_KNOWN_TO_FCA |
3093 			    ICMD_FCA_ABORT_CALLED)) == (ICMD_KNOWN_TO_FCA |
3094 			    ICMD_FCA_ABORT_CALLED)) {
3095 				new &= ~ICMD_FCA_ABORT_CALLED;
3096 				do_clear = 1;
3097 			} else {
3098 				do_clear = 0;
3099 				break;
3100 			}
3101 		} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3102 		if (do_clear &&
3103 		    (icmd->icmd_cmd->cmd_type == FCT_CMD_FCP_XCHG)) {
3104 			stmf_abort(STMF_REQUEUE_TASK_ABORT_LPORT,
3105 			    icmd->icmd_cmd->cmd_specific, 0, NULL);
3106 		}
3107 	}
3108 
3109 	rw_exit(&iport->iport_lock);
3110 }
3111 
3112 /*
3113  * Modify the irp_deregister_timer such that the ports start deregistering
3114  * quickly.
3115  */
3116 void
3117 fct_irp_deregister_speedup(fct_i_local_port_t *iport)
3118 {
3119 	fct_i_remote_port_t *irp;
3120 	int i;
3121 
3122 	if (!iport->iport_nrps)
3123 		return;
3124 
3125 	for (i = 0; i < rportid_table_size; i++) {
3126 		irp = iport->iport_rp_tb[i];
3127 		while (irp) {
3128 			irp->irp_deregister_timer = ddi_get_lbolt() - 1;
3129 			irp = irp->irp_next;
3130 		}
3131 	}
3132 }
3133 
3134 disc_action_t
3135 fct_handle_port_offline(fct_i_local_port_t *iport)
3136 {
3137 	if (iport->iport_offline_prstate == FCT_OPR_START) {
3138 		fct_reset_flag_abort_called(iport);
3139 		iport->iport_offline_prstate = FCT_OPR_CMD_CLEANUP_WAIT;
3140 		/* fct_ctl has already submitted a link offline event */
3141 		return (DISC_ACTION_DELAY_RESCAN);
3142 	}
3143 	if (iport->iport_offline_prstate == FCT_OPR_CMD_CLEANUP_WAIT) {
3144 		if (iport->iport_link_state != PORT_STATE_LINK_DOWN)
3145 			return (DISC_ACTION_DELAY_RESCAN);
3146 		/*
3147 		 * All I/Os have been killed at this time. Lets speedup
3148 		 * the port deregister process.
3149 		 */
3150 		mutex_exit(&iport->iport_worker_lock);
3151 		rw_enter(&iport->iport_lock, RW_WRITER);
3152 		fct_irp_deregister_speedup(iport);
3153 		rw_exit(&iport->iport_lock);
3154 		mutex_enter(&iport->iport_worker_lock);
3155 		iport->iport_offline_prstate = FCT_OPR_INT_CLEANUP_WAIT;
3156 		return (DISC_ACTION_RESCAN);
3157 	}
3158 	if (iport->iport_offline_prstate == FCT_OPR_INT_CLEANUP_WAIT) {
3159 		stmf_change_status_t st;
3160 
3161 		if (iport->iport_solcmd_queue) {
3162 			return (DISC_ACTION_DELAY_RESCAN);
3163 		}
3164 
3165 		if (iport->iport_nrps) {
3166 			/*
3167 			 * A port logout may have gone when implicit logo all
3168 			 * was retried. So do the port speedup again here.
3169 			 */
3170 			mutex_exit(&iport->iport_worker_lock);
3171 			rw_enter(&iport->iport_lock, RW_WRITER);
3172 			fct_irp_deregister_speedup(iport);
3173 			rw_exit(&iport->iport_lock);
3174 			mutex_enter(&iport->iport_worker_lock);
3175 			return (DISC_ACTION_DELAY_RESCAN);
3176 		}
3177 
3178 		if (iport->iport_event_head != NULL) {
3179 			return (DISC_ACTION_DELAY_RESCAN);
3180 		}
3181 
3182 		st.st_completion_status = STMF_SUCCESS;
3183 		st.st_additional_info = NULL;
3184 		iport->iport_offline_prstate = FCT_OPR_DONE;
3185 		iport->iport_state = FCT_STATE_OFFLINE;
3186 		mutex_exit(&iport->iport_worker_lock);
3187 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
3188 		    iport->iport_port->port_lport, &st);
3189 		mutex_enter(&iport->iport_worker_lock);
3190 		return (DISC_ACTION_DELAY_RESCAN);
3191 	}
3192 
3193 	/* NOTREACHED */
3194 	return (0);
3195 }
3196 
3197 /*
3198  * See stmf.h for information on rflags. Additional info is just a text
3199  * description of the reason for this call. Additional_info can be NULL.
3200  * Also the caller can declare additional info on the stack. stmf_ctl
3201  * makes a copy of it before returning.
3202  */
3203 fct_status_t
3204 fct_port_initialize(fct_local_port_t *port, uint32_t rflags,
3205 				char *additional_info)
3206 {
3207 	stmf_state_change_info_t st;
3208 
3209 	st.st_rflags = rflags;
3210 	st.st_additional_info = additional_info;
3211 	stmf_trace(NULL, "fct_port_initialize: port-%p, %s", port,
3212 	    additional_info? additional_info : "no more information");
3213 	return (stmf_ctl(STMF_CMD_LPORT_ONLINE, port->port_lport, &st));
3214 }
3215 
3216 fct_status_t
3217 fct_port_shutdown(fct_local_port_t *port, uint32_t rflags,
3218 				char *additional_info)
3219 {
3220 	stmf_state_change_info_t st;
3221 
3222 	st.st_rflags = rflags;
3223 	st.st_additional_info = additional_info;
3224 	stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port,
3225 	    additional_info? additional_info : "no more information");
3226 	return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st));
3227 }
3228 
3229 /*
3230  * Called by worker thread. The aim is to terminate the command
3231  * using whatever means it takes.
3232  * Called with worker lock held.
3233  */
3234 disc_action_t
3235 fct_cmd_terminator(fct_i_local_port_t *iport)
3236 {
3237 	char			info[FCT_INFO_LEN];
3238 	clock_t			endtime;
3239 	fct_i_cmd_t		**ppicmd;
3240 	fct_i_cmd_t		*icmd;
3241 	fct_cmd_t		*cmd;
3242 	fct_local_port_t	*port = iport->iport_port;
3243 	disc_action_t		ret = DISC_ACTION_NO_WORK;
3244 	fct_status_t		abort_ret;
3245 	int			fca_done, fct_done, cmd_implicit = 0;
3246 	int			flags;
3247 	unsigned long long	st;
3248 
3249 	/* Lets Limit each run to 20ms max. */
3250 	endtime = ddi_get_lbolt() + drv_usectohz(20000);
3251 
3252 	/* Start from where we left off last time */
3253 	if (iport->iport_ppicmd_term) {
3254 		ppicmd = iport->iport_ppicmd_term;
3255 		iport->iport_ppicmd_term = NULL;
3256 	} else {
3257 		ppicmd = &iport->iport_abort_queue;
3258 	}
3259 
3260 	/*
3261 	 * Once a command gets on discovery queue, this is the only thread
3262 	 * which can access it. So no need for the lock here.
3263 	 */
3264 	mutex_exit(&iport->iport_worker_lock);
3265 
3266 	while ((icmd = *ppicmd) != NULL) {
3267 		cmd = icmd->icmd_cmd;
3268 
3269 		/* Always remember that cmd->cmd_rp can be NULL */
3270 		if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA |
3271 		    ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) {
3272 			atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3273 			if (CMD_HANDLE_VALID(cmd->cmd_handle))
3274 				flags = 0;
3275 			else
3276 				flags = FCT_IOF_FORCE_FCA_DONE;
3277 			abort_ret = port->port_abort_cmd(port, cmd, flags);
3278 			if ((abort_ret != FCT_SUCCESS) &&
3279 			    (abort_ret != FCT_ABORT_SUCCESS) &&
3280 			    (abort_ret != FCT_NOT_FOUND)) {
3281 				if (flags & FCT_IOF_FORCE_FCA_DONE) {
3282 					/*
3283 					 * XXX trigger port fatal,
3284 					 * Abort the termination, and shutdown
3285 					 * svc will trigger fct_cmd_termination
3286 					 * again.
3287 					 */
3288 					(void) snprintf(info, sizeof (info),
3289 					    "fct_cmd_terminator:"
3290 					    " iport-%p, port_abort_cmd with "
3291 					    "FORCE_FCA_DONE failed",
3292 					    (void *)iport);
3293 					(void) fct_port_shutdown(
3294 					    iport->iport_port,
3295 					    STMF_RFLAG_FATAL_ERROR |
3296 					    STMF_RFLAG_RESET, info);
3297 
3298 					mutex_enter(&iport->iport_worker_lock);
3299 					iport->iport_ppicmd_term = ppicmd;
3300 					return (DISC_ACTION_DELAY_RESCAN);
3301 				}
3302 				atomic_and_32(&icmd->icmd_flags,
3303 				    ~ICMD_FCA_ABORT_CALLED);
3304 			} else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
3305 			    (abort_ret == FCT_ABORT_SUCCESS) ||
3306 			    (abort_ret == FCT_NOT_FOUND)) {
3307 				atomic_and_32(&icmd->icmd_flags,
3308 				    ~ICMD_KNOWN_TO_FCA);
3309 			}
3310 			ret |= DISC_ACTION_DELAY_RESCAN;
3311 		} else if (icmd->icmd_flags & ICMD_IMPLICIT) {
3312 			if (cmd->cmd_type == FCT_CMD_SOL_ELS)
3313 				cmd->cmd_comp_status = FCT_ABORTED;
3314 			atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3315 			cmd_implicit = 1;
3316 		}
3317 		if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
3318 			fca_done = 1;
3319 		else
3320 			fca_done = 0;
3321 		if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0)
3322 			fct_done = 1;
3323 		else
3324 			fct_done = 0;
3325 		if ((fca_done || cmd_implicit) && fct_done) {
3326 			mutex_enter(&iport->iport_worker_lock);
3327 			ASSERT(*ppicmd == icmd);
3328 			*ppicmd = (*ppicmd)->icmd_next;
3329 			mutex_exit(&iport->iport_worker_lock);
3330 			if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) ||
3331 			    (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) {
3332 				/* Free the cmd */
3333 				fct_cmd_free(cmd);
3334 			} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
3335 				fct_handle_sol_els_completion(iport, icmd);
3336 				if (icmd->icmd_flags & ICMD_IMPLICIT) {
3337 					if (IS_LOGO_ELS(icmd)) {
3338 						/* IMPLICIT LOGO is special */
3339 						fct_cmd_free(cmd);
3340 					}
3341 				}
3342 			} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3343 				fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
3344 
3345 				/* Tell the caller that we are done */
3346 				atomic_or_32(&icmd->icmd_flags,
3347 				    ICMD_CMD_COMPLETE);
3348 				if (fct_netbuf_to_value(
3349 				    ct->ct_req_payload + 8, 2) == NS_GID_PN) {
3350 					fct_i_remote_port_t *irp;
3351 
3352 					rw_enter(&iport->iport_lock, RW_READER);
3353 					irp = fct_lookup_irp_by_portwwn(iport,
3354 					    ct->ct_req_payload + 16);
3355 
3356 					if (irp) {
3357 						atomic_and_32(&irp->irp_flags,
3358 						    ~IRP_RSCN_QUEUED);
3359 					}
3360 					rw_exit(&iport->iport_lock);
3361 				}
3362 			} else {
3363 				ASSERT(0);
3364 			}
3365 		} else {
3366 			clock_t	timeout_ticks;
3367 			if (port->port_fca_abort_timeout)
3368 				timeout_ticks = drv_usectohz(
3369 				    port->port_fca_abort_timeout*1000);
3370 			else
3371 				/* 10 seconds by default */
3372 				timeout_ticks = drv_usectohz(10 * 1000000);
3373 			if ((ddi_get_lbolt() >
3374 			    (icmd->icmd_start_time+timeout_ticks)) &&
3375 			    iport->iport_state == FCT_STATE_ONLINE) {
3376 				/* timeout, reset the port */
3377 				char cmd_type[10];
3378 				if (cmd->cmd_type == FCT_CMD_RCVD_ELS ||
3379 				    cmd->cmd_type == FCT_CMD_SOL_ELS) {
3380 					fct_els_t *els = cmd->cmd_specific;
3381 					(void) snprintf(cmd_type,
3382 					    sizeof (cmd_type), "%x.%x",
3383 					    cmd->cmd_type,
3384 					    els->els_req_payload[0]);
3385 				} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3386 					fct_sol_ct_t *ct = cmd->cmd_specific;
3387 					(void) snprintf(cmd_type,
3388 					    sizeof (cmd_type), "%x.%02x%02x",
3389 					    cmd->cmd_type,
3390 					    ct->ct_req_payload[8],
3391 					    ct->ct_req_payload[9]);
3392 				} else {
3393 					cmd_type[0] = 0;
3394 				}
3395 				st = cmd->cmd_comp_status;	/* gcc fix */
3396 				(void) snprintf(info, sizeof (info),
3397 				    "fct_cmd_terminator:"
3398 				    " iport-%p, cmd_type(0x%s),"
3399 				    " reason(%llx)", (void *)iport, cmd_type,
3400 				    st);
3401 				(void) fct_port_shutdown(port,
3402 				    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET,
3403 				    info);
3404 			}
3405 			ppicmd = &((*ppicmd)->icmd_next);
3406 		}
3407 
3408 		if (ddi_get_lbolt() > endtime) {
3409 			mutex_enter(&iport->iport_worker_lock);
3410 			iport->iport_ppicmd_term = ppicmd;
3411 			return (DISC_ACTION_DELAY_RESCAN);
3412 		}
3413 	}
3414 	mutex_enter(&iport->iport_worker_lock);
3415 	if (iport->iport_abort_queue)
3416 		return (DISC_ACTION_DELAY_RESCAN);
3417 	if (ret == DISC_ACTION_NO_WORK)
3418 		return (DISC_ACTION_RESCAN);
3419 	return (ret);
3420 }
3421 
3422 /*
3423  * Send a syslog event for adapter port level events.
3424  */
3425 void
3426 fct_log_local_port_event(fct_local_port_t *port, char *subclass)
3427 {
3428 	nvlist_t *attr_list;
3429 	int port_instance;
3430 
3431 	if (!fct_dip)
3432 		return;
3433 	port_instance = ddi_get_instance(fct_dip);
3434 
3435 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3436 	    KM_SLEEP) != DDI_SUCCESS) {
3437 		goto alloc_failed;
3438 	}
3439 
3440 	if (nvlist_add_uint32(attr_list, "instance", port_instance)
3441 	    != DDI_SUCCESS) {
3442 		goto error;
3443 	}
3444 
3445 	if (nvlist_add_byte_array(attr_list, "port-wwn",
3446 	    port->port_pwwn, 8) != DDI_SUCCESS) {
3447 		goto error;
3448 	}
3449 
3450 	(void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3451 	    subclass, attr_list, NULL, DDI_SLEEP);
3452 
3453 	nvlist_free(attr_list);
3454 	return;
3455 
3456 error:
3457 	nvlist_free(attr_list);
3458 alloc_failed:
3459 	stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3460 	    "Unable to send %s event", subclass);
3461 }
3462 
3463 void
3464 fct_log_remote_port_event(fct_local_port_t *port, char *subclass,
3465     uint8_t *rp_pwwn, uint32_t rp_id)
3466 {
3467 	nvlist_t *attr_list;
3468 	int port_instance;
3469 
3470 	if (!fct_dip)
3471 		return;
3472 	port_instance = ddi_get_instance(fct_dip);
3473 
3474 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3475 	    KM_SLEEP) != DDI_SUCCESS) {
3476 		goto alloc_failed;
3477 	}
3478 
3479 	if (nvlist_add_uint32(attr_list, "instance", port_instance)
3480 	    != DDI_SUCCESS) {
3481 		goto error;
3482 	}
3483 
3484 	if (nvlist_add_byte_array(attr_list, "port-wwn",
3485 	    port->port_pwwn, 8) != DDI_SUCCESS) {
3486 		goto error;
3487 	}
3488 
3489 	if (nvlist_add_byte_array(attr_list, "target-port-wwn",
3490 	    rp_pwwn, 8) != DDI_SUCCESS) {
3491 		goto error;
3492 	}
3493 
3494 	if (nvlist_add_uint32(attr_list, "target-port-id",
3495 	    rp_id) != DDI_SUCCESS) {
3496 		goto error;
3497 	}
3498 
3499 	(void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3500 	    subclass, attr_list, NULL, DDI_SLEEP);
3501 
3502 	nvlist_free(attr_list);
3503 	return;
3504 
3505 error:
3506 	nvlist_free(attr_list);
3507 alloc_failed:
3508 	stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3509 	    "Unable to send %s event", subclass);
3510 }
3511 
3512 uint64_t
3513 fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes)
3514 {
3515 	uint64_t	ret = 0;
3516 	uint8_t		idx = 0;
3517 
3518 	do {
3519 		ret |= (buf[idx] << (8 * (nbytes -idx - 1)));
3520 	} while (++idx < nbytes);
3521 
3522 	return (ret);
3523 }
3524 
3525 void
3526 fct_value_to_netbuf(uint64_t value, uint8_t *buf, uint8_t nbytes)
3527 {
3528 	uint8_t		idx = 0;
3529 
3530 	for (idx = 0; idx < nbytes; idx++) {
3531 		buf[idx] = 0xFF & (value >> (8 * (nbytes - idx - 1)));
3532 	}
3533 }
3534 
3535 /*
3536  * from_ptr: ptr to uchar_t array of size WWN_SIZE
3537  * to_ptr: char ptr to string of size WWN_SIZE*2+1
3538  */
3539 void
3540 fct_wwn_to_str(char *to_ptr, const uint8_t *from_ptr)
3541 {
3542 	ASSERT(to_ptr != NULL && from_ptr != NULL);
3543 
3544 	(void) sprintf(to_ptr, "%02x%02x%02x%02x%02x%02x%02x%02x",
3545 	    from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
3546 	    from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
3547 }
3548 
3549 static int
3550 fct_update_stats(kstat_t *ks, int rw)
3551 {
3552 	fct_i_local_port_t *iport;
3553 	fct_port_stat_t *port_kstat;
3554 	fct_port_link_status_t stat;
3555 	uint32_t	buf_size = sizeof (stat);
3556 	int		ret;
3557 
3558 	if (rw == KSTAT_WRITE)
3559 		return (EACCES);
3560 
3561 	iport = (fct_i_local_port_t *)ks->ks_private;
3562 	port_kstat = (fct_port_stat_t *)ks->ks_data;
3563 
3564 	if (iport->iport_port->port_info == NULL) {
3565 		return (EIO);
3566 	}
3567 	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
3568 	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
3569 	if (ret != STMF_SUCCESS) {
3570 		return (EIO);
3571 	}
3572 
3573 	port_kstat->link_failure_cnt.value.ui32 =
3574 	    stat.LinkFailureCount;
3575 	port_kstat->loss_of_sync_cnt.value.ui32 =
3576 	    stat.LossOfSyncCount;
3577 	port_kstat->loss_of_signals_cnt.value.ui32 =
3578 	    stat.LossOfSignalsCount;
3579 	port_kstat->prim_seq_protocol_err_cnt.value.ui32 =
3580 	    stat.PrimitiveSeqProtocolErrorCount;
3581 	port_kstat->invalid_tx_word_cnt.value.ui32 =
3582 	    stat.InvalidTransmissionWordCount;
3583 	port_kstat->invalid_crc_cnt.value.ui32 =
3584 	    stat.InvalidCRCCount;
3585 
3586 	return (0);
3587 }
3588 
3589 void
3590 fct_init_kstats(fct_i_local_port_t *iport)
3591 {
3592 	kstat_t *ks;
3593 	fct_port_stat_t *port_kstat;
3594 	char	name[256];
3595 
3596 	if (iport->iport_alias)
3597 		(void) sprintf(name, "iport_%s", iport->iport_alias);
3598 	else
3599 		(void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport);
3600 	ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata",
3601 	    KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t),
3602 	    0);
3603 
3604 	if (ks == NULL) {
3605 		return;
3606 	}
3607 	port_kstat = (fct_port_stat_t *)ks->ks_data;
3608 
3609 	iport->iport_kstat_portstat = ks;
3610 	kstat_named_init(&port_kstat->link_failure_cnt,
3611 	    "Link_failure_cnt", KSTAT_DATA_UINT32);
3612 	kstat_named_init(&port_kstat->loss_of_sync_cnt,
3613 	    "Loss_of_sync_cnt", KSTAT_DATA_UINT32);
3614 	kstat_named_init(&port_kstat->loss_of_signals_cnt,
3615 	    "Loss_of_signals_cnt", KSTAT_DATA_UINT32);
3616 	kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt,
3617 	    "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32);
3618 	kstat_named_init(&port_kstat->invalid_tx_word_cnt,
3619 	    "Invalid_tx_word_cnt", KSTAT_DATA_UINT32);
3620 	kstat_named_init(&port_kstat->invalid_crc_cnt,
3621 	    "Invalid_crc_cnt", KSTAT_DATA_UINT32);
3622 	ks->ks_update = fct_update_stats;
3623 	ks->ks_private = (void *)iport;
3624 	kstat_install(ks);
3625 
3626 }
3627