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