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