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