xref: /onnv-gate/usr/src/uts/common/io/fibre-channel/ulp/fcip.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM /*
27*7836SJohn.Forte@Sun.COM  * SunOS 5.x Multithreaded STREAMS DLPI FCIP Module
28*7836SJohn.Forte@Sun.COM  * This is a pseudo driver module to handle encapsulation of IP and ARP
29*7836SJohn.Forte@Sun.COM  * datagrams over FibreChannel interfaces. FCIP is a cloneable STREAMS
30*7836SJohn.Forte@Sun.COM  * driver module which interfaces with IP/ARP using DLPI. This module
31*7836SJohn.Forte@Sun.COM  * is a Style-2 DLS provider.
32*7836SJohn.Forte@Sun.COM  *
33*7836SJohn.Forte@Sun.COM  * The implementation of this module is based on RFC 2625 which gives
34*7836SJohn.Forte@Sun.COM  * details on the encapsulation of IP/ARP data over FibreChannel.
35*7836SJohn.Forte@Sun.COM  * The fcip module needs to resolve an IP address to a port address before
36*7836SJohn.Forte@Sun.COM  * sending data to a destination port. A FC device port has 2 addresses
37*7836SJohn.Forte@Sun.COM  * associated with it: A 8 byte World Wide unique Port Name and a 3 byte
38*7836SJohn.Forte@Sun.COM  * volatile Port number or Port_ID.
39*7836SJohn.Forte@Sun.COM  *
40*7836SJohn.Forte@Sun.COM  * The mapping between a IP address and the World Wide Port Name is handled
41*7836SJohn.Forte@Sun.COM  * by the ARP layer since the IP over FC draft requires the MAC address to
42*7836SJohn.Forte@Sun.COM  * be the least significant six bytes of the WorldWide Port Names. The
43*7836SJohn.Forte@Sun.COM  * fcip module however needs to identify the destination port uniquely when
44*7836SJohn.Forte@Sun.COM  * the destination FC device has multiple FC ports.
45*7836SJohn.Forte@Sun.COM  *
46*7836SJohn.Forte@Sun.COM  * The FC layer mapping between the World Wide Port Name and the Port_ID
47*7836SJohn.Forte@Sun.COM  * will be handled through the use of a fabric name server or through the
48*7836SJohn.Forte@Sun.COM  * use of the FARP ELS command as described in the draft. Since the Port_IDs
49*7836SJohn.Forte@Sun.COM  * are volatile, the mapping between the World Wide Port Name and Port_IDs
50*7836SJohn.Forte@Sun.COM  * must be maintained and validated before use each time a datagram
51*7836SJohn.Forte@Sun.COM  * needs to be sent to the destination ports. The FC transport module
52*7836SJohn.Forte@Sun.COM  * informs the fcip module of all changes to states of ports on the
53*7836SJohn.Forte@Sun.COM  * fabric through registered callbacks. This enables the fcip module
54*7836SJohn.Forte@Sun.COM  * to maintain the WW_PN to Port_ID mappings current.
55*7836SJohn.Forte@Sun.COM  *
56*7836SJohn.Forte@Sun.COM  * For details on how this module interfaces with the FibreChannel Transport
57*7836SJohn.Forte@Sun.COM  * modules, refer to PSARC/1997/385. Chapter 3 of the FibreChannel Transport
58*7836SJohn.Forte@Sun.COM  * Programming guide details the APIs between ULPs and the Transport.
59*7836SJohn.Forte@Sun.COM  *
60*7836SJohn.Forte@Sun.COM  * Now for some Caveats:
61*7836SJohn.Forte@Sun.COM  *
62*7836SJohn.Forte@Sun.COM  * RFC 2625 requires that a FibreChannel Port name (the Port WWN) have
63*7836SJohn.Forte@Sun.COM  * the NAA bits set to '0001' indicating a IEEE 48bit address which
64*7836SJohn.Forte@Sun.COM  * corresponds to a ULA (Universal LAN MAC address). But with FibreChannel
65*7836SJohn.Forte@Sun.COM  * adapters containing 2 or more ports, IEEE naming cannot identify the
66*7836SJohn.Forte@Sun.COM  * ports on an adapter uniquely so we will in the first implementation
67*7836SJohn.Forte@Sun.COM  * be operating only on Port 0 of each adapter.
68*7836SJohn.Forte@Sun.COM  */
69*7836SJohn.Forte@Sun.COM 
70*7836SJohn.Forte@Sun.COM #include	<sys/types.h>
71*7836SJohn.Forte@Sun.COM #include	<sys/errno.h>
72*7836SJohn.Forte@Sun.COM #include	<sys/debug.h>
73*7836SJohn.Forte@Sun.COM #include	<sys/time.h>
74*7836SJohn.Forte@Sun.COM #include	<sys/sysmacros.h>
75*7836SJohn.Forte@Sun.COM #include	<sys/systm.h>
76*7836SJohn.Forte@Sun.COM #include	<sys/user.h>
77*7836SJohn.Forte@Sun.COM #include	<sys/stropts.h>
78*7836SJohn.Forte@Sun.COM #include	<sys/stream.h>
79*7836SJohn.Forte@Sun.COM #include	<sys/strlog.h>
80*7836SJohn.Forte@Sun.COM #include	<sys/strsubr.h>
81*7836SJohn.Forte@Sun.COM #include	<sys/cmn_err.h>
82*7836SJohn.Forte@Sun.COM #include	<sys/cpu.h>
83*7836SJohn.Forte@Sun.COM #include	<sys/kmem.h>
84*7836SJohn.Forte@Sun.COM #include	<sys/conf.h>
85*7836SJohn.Forte@Sun.COM #include	<sys/ddi.h>
86*7836SJohn.Forte@Sun.COM #include	<sys/sunddi.h>
87*7836SJohn.Forte@Sun.COM #include	<sys/ksynch.h>
88*7836SJohn.Forte@Sun.COM #include	<sys/stat.h>
89*7836SJohn.Forte@Sun.COM #include	<sys/kstat.h>
90*7836SJohn.Forte@Sun.COM #include	<sys/vtrace.h>
91*7836SJohn.Forte@Sun.COM #include	<sys/strsun.h>
92*7836SJohn.Forte@Sun.COM #include	<sys/varargs.h>
93*7836SJohn.Forte@Sun.COM #include	<sys/modctl.h>
94*7836SJohn.Forte@Sun.COM #include 	<sys/thread.h>
95*7836SJohn.Forte@Sun.COM #include 	<sys/var.h>
96*7836SJohn.Forte@Sun.COM #include 	<sys/proc.h>
97*7836SJohn.Forte@Sun.COM #include	<inet/common.h>
98*7836SJohn.Forte@Sun.COM #include	<netinet/ip6.h>
99*7836SJohn.Forte@Sun.COM #include	<inet/ip.h>
100*7836SJohn.Forte@Sun.COM #include	<inet/arp.h>
101*7836SJohn.Forte@Sun.COM #include	<inet/mi.h>
102*7836SJohn.Forte@Sun.COM #include	<inet/nd.h>
103*7836SJohn.Forte@Sun.COM #include	<sys/dlpi.h>
104*7836SJohn.Forte@Sun.COM #include	<sys/ethernet.h>
105*7836SJohn.Forte@Sun.COM #include	<sys/file.h>
106*7836SJohn.Forte@Sun.COM #include	<sys/syslog.h>
107*7836SJohn.Forte@Sun.COM #include	<sys/disp.h>
108*7836SJohn.Forte@Sun.COM #include	<sys/taskq.h>
109*7836SJohn.Forte@Sun.COM 
110*7836SJohn.Forte@Sun.COM /*
111*7836SJohn.Forte@Sun.COM  * Leadville includes
112*7836SJohn.Forte@Sun.COM  */
113*7836SJohn.Forte@Sun.COM 
114*7836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/fc.h>
115*7836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/impl/fc_ulpif.h>
116*7836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/ulp/fcip.h>
117*7836SJohn.Forte@Sun.COM 
118*7836SJohn.Forte@Sun.COM /*
119*7836SJohn.Forte@Sun.COM  * TNF Probe/trace facility include
120*7836SJohn.Forte@Sun.COM  */
121*7836SJohn.Forte@Sun.COM #if defined(lint) || defined(FCIP_TNF_ENABLED)
122*7836SJohn.Forte@Sun.COM #include <sys/tnf_probe.h>
123*7836SJohn.Forte@Sun.COM #endif
124*7836SJohn.Forte@Sun.COM 
125*7836SJohn.Forte@Sun.COM #define	FCIP_ESBALLOC
126*7836SJohn.Forte@Sun.COM 
127*7836SJohn.Forte@Sun.COM /*
128*7836SJohn.Forte@Sun.COM  * Function prototypes
129*7836SJohn.Forte@Sun.COM  */
130*7836SJohn.Forte@Sun.COM 
131*7836SJohn.Forte@Sun.COM /* standard loadable modules entry points */
132*7836SJohn.Forte@Sun.COM static int	fcip_attach(dev_info_t *, ddi_attach_cmd_t);
133*7836SJohn.Forte@Sun.COM static int 	fcip_detach(dev_info_t *, ddi_detach_cmd_t);
134*7836SJohn.Forte@Sun.COM static void 	fcip_dodetach(struct fcipstr *slp);
135*7836SJohn.Forte@Sun.COM static int fcip_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
136*7836SJohn.Forte@Sun.COM     void *arg, void **result);
137*7836SJohn.Forte@Sun.COM 
138*7836SJohn.Forte@Sun.COM 
139*7836SJohn.Forte@Sun.COM /* streams specific */
140*7836SJohn.Forte@Sun.COM static void fcip_setipq(struct fcip *fptr);
141*7836SJohn.Forte@Sun.COM static int fcip_wput(queue_t *, mblk_t *);
142*7836SJohn.Forte@Sun.COM static int fcip_wsrv(queue_t *);
143*7836SJohn.Forte@Sun.COM static void fcip_proto(queue_t *, mblk_t *);
144*7836SJohn.Forte@Sun.COM static void fcip_ioctl(queue_t *, mblk_t *);
145*7836SJohn.Forte@Sun.COM static int fcip_open(queue_t *wq, dev_t *devp, int flag,
146*7836SJohn.Forte@Sun.COM 		int sflag, cred_t *credp);
147*7836SJohn.Forte@Sun.COM static int fcip_close(queue_t *rq, int flag, int otyp, cred_t *credp);
148*7836SJohn.Forte@Sun.COM static int fcip_start(queue_t *wq, mblk_t *mp, struct fcip *fptr,
149*7836SJohn.Forte@Sun.COM     struct fcip_dest *fdestp, int flags);
150*7836SJohn.Forte@Sun.COM static void fcip_sendup(struct fcip *fptr, mblk_t *mp,
151*7836SJohn.Forte@Sun.COM     struct fcipstr *(*acceptfunc)());
152*7836SJohn.Forte@Sun.COM static struct fcipstr *fcip_accept(struct fcipstr *slp, struct fcip *fptr,
153*7836SJohn.Forte@Sun.COM     int type, la_wwn_t *dhostp);
154*7836SJohn.Forte@Sun.COM static mblk_t *fcip_addudind(struct fcip *fptr, mblk_t *mp,
155*7836SJohn.Forte@Sun.COM     fcph_network_hdr_t *nhdr, int type);
156*7836SJohn.Forte@Sun.COM static int fcip_setup_mac_addr(struct fcip *fptr);
157*7836SJohn.Forte@Sun.COM static void fcip_kstat_init(struct fcip *fptr);
158*7836SJohn.Forte@Sun.COM static int fcip_stat_update(kstat_t *, int);
159*7836SJohn.Forte@Sun.COM 
160*7836SJohn.Forte@Sun.COM 
161*7836SJohn.Forte@Sun.COM /* dlpi specific */
162*7836SJohn.Forte@Sun.COM static void fcip_spareq(queue_t *wq, mblk_t *mp);
163*7836SJohn.Forte@Sun.COM static void fcip_pareq(queue_t *wq, mblk_t *mp);
164*7836SJohn.Forte@Sun.COM static void fcip_ubreq(queue_t *wq, mblk_t *mp);
165*7836SJohn.Forte@Sun.COM static void fcip_breq(queue_t *wq, mblk_t *mp);
166*7836SJohn.Forte@Sun.COM static void fcip_dreq(queue_t *wq, mblk_t *mp);
167*7836SJohn.Forte@Sun.COM static void fcip_areq(queue_t *wq, mblk_t *mp);
168*7836SJohn.Forte@Sun.COM static void fcip_udreq(queue_t *wq, mblk_t *mp);
169*7836SJohn.Forte@Sun.COM static void fcip_ireq(queue_t *wq, mblk_t *mp);
170*7836SJohn.Forte@Sun.COM static void fcip_dl_ioc_hdr_info(queue_t *wq, mblk_t *mp);
171*7836SJohn.Forte@Sun.COM 
172*7836SJohn.Forte@Sun.COM 
173*7836SJohn.Forte@Sun.COM /* solaris sundry, DR/CPR etc */
174*7836SJohn.Forte@Sun.COM static int fcip_cache_constructor(void *buf, void *arg, int size);
175*7836SJohn.Forte@Sun.COM static void fcip_cache_destructor(void *buf, void *size);
176*7836SJohn.Forte@Sun.COM static int fcip_handle_suspend(fcip_port_info_t *fport, fc_detach_cmd_t cmd);
177*7836SJohn.Forte@Sun.COM static int fcip_handle_resume(fcip_port_info_t *fport,
178*7836SJohn.Forte@Sun.COM     fc_ulp_port_info_t *port_info, fc_attach_cmd_t cmd);
179*7836SJohn.Forte@Sun.COM static fcip_port_info_t *fcip_softstate_free(fcip_port_info_t *fport);
180*7836SJohn.Forte@Sun.COM static int fcip_port_attach_handler(struct fcip *fptr);
181*7836SJohn.Forte@Sun.COM 
182*7836SJohn.Forte@Sun.COM 
183*7836SJohn.Forte@Sun.COM /*
184*7836SJohn.Forte@Sun.COM  * ulp - transport interface function prototypes
185*7836SJohn.Forte@Sun.COM  */
186*7836SJohn.Forte@Sun.COM static int fcip_port_attach(opaque_t ulp_handle, fc_ulp_port_info_t *,
187*7836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, uint32_t sid);
188*7836SJohn.Forte@Sun.COM static int fcip_port_detach(opaque_t ulp_handle, fc_ulp_port_info_t *,
189*7836SJohn.Forte@Sun.COM     fc_detach_cmd_t cmd);
190*7836SJohn.Forte@Sun.COM static int fcip_port_ioctl(opaque_t ulp_handle,  opaque_t port_handle,
191*7836SJohn.Forte@Sun.COM     dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval,
192*7836SJohn.Forte@Sun.COM     uint32_t claimed);
193*7836SJohn.Forte@Sun.COM static void fcip_statec_cb(opaque_t ulp_handle, opaque_t phandle,
194*7836SJohn.Forte@Sun.COM     uint32_t port_state, uint32_t port_top, fc_portmap_t changelist[],
195*7836SJohn.Forte@Sun.COM     uint32_t listlen, uint32_t sid);
196*7836SJohn.Forte@Sun.COM static int fcip_els_cb(opaque_t ulp_handle, opaque_t phandle,
197*7836SJohn.Forte@Sun.COM     fc_unsol_buf_t *buf, uint32_t claimed);
198*7836SJohn.Forte@Sun.COM static int fcip_data_cb(opaque_t ulp_handle, opaque_t phandle,
199*7836SJohn.Forte@Sun.COM     fc_unsol_buf_t *payload, uint32_t claimed);
200*7836SJohn.Forte@Sun.COM 
201*7836SJohn.Forte@Sun.COM 
202*7836SJohn.Forte@Sun.COM /* Routing table specific */
203*7836SJohn.Forte@Sun.COM static void fcip_handle_topology(struct fcip *fptr);
204*7836SJohn.Forte@Sun.COM static int fcip_init_port(struct fcip *fptr);
205*7836SJohn.Forte@Sun.COM struct fcip_routing_table *fcip_lookup_rtable(struct fcip *fptr,
206*7836SJohn.Forte@Sun.COM     la_wwn_t *pwwn, int matchflag);
207*7836SJohn.Forte@Sun.COM static void fcip_rt_update(struct fcip *fptr, fc_portmap_t *devlist,
208*7836SJohn.Forte@Sun.COM     uint32_t listlen);
209*7836SJohn.Forte@Sun.COM static void fcip_rt_flush(struct fcip *fptr);
210*7836SJohn.Forte@Sun.COM static void fcip_rte_remove_deferred(void *arg);
211*7836SJohn.Forte@Sun.COM static int fcip_do_plogi(struct fcip *fptr, struct fcip_routing_table *frp);
212*7836SJohn.Forte@Sun.COM 
213*7836SJohn.Forte@Sun.COM 
214*7836SJohn.Forte@Sun.COM /* dest table specific */
215*7836SJohn.Forte@Sun.COM static struct fcip_dest *fcip_get_dest(struct fcip *fptr,
216*7836SJohn.Forte@Sun.COM     la_wwn_t *dlphys);
217*7836SJohn.Forte@Sun.COM static struct fcip_dest *fcip_add_dest(struct fcip *fptr,
218*7836SJohn.Forte@Sun.COM     struct fcip_routing_table *frp);
219*7836SJohn.Forte@Sun.COM static int fcip_dest_add_broadcast_entry(struct fcip *fptr, int new_flag);
220*7836SJohn.Forte@Sun.COM static uint32_t fcip_get_broadcast_did(struct fcip *fptr);
221*7836SJohn.Forte@Sun.COM static void fcip_cleanup_dest(struct fcip *fptr);
222*7836SJohn.Forte@Sun.COM 
223*7836SJohn.Forte@Sun.COM 
224*7836SJohn.Forte@Sun.COM /* helper functions */
225*7836SJohn.Forte@Sun.COM static fcip_port_info_t *fcip_get_port(opaque_t phandle);
226*7836SJohn.Forte@Sun.COM static int fcip_wwn_compare(la_wwn_t *wwn1, la_wwn_t *wwn2, int flag);
227*7836SJohn.Forte@Sun.COM static void fcip_ether_to_str(struct ether_addr *e, caddr_t s);
228*7836SJohn.Forte@Sun.COM static int fcip_port_get_num_pkts(struct fcip *fptr);
229*7836SJohn.Forte@Sun.COM static int fcip_check_port_busy(struct fcip *fptr);
230*7836SJohn.Forte@Sun.COM static void fcip_check_remove_minor_node(void);
231*7836SJohn.Forte@Sun.COM static int fcip_set_wwn(la_wwn_t *pwwn);
232*7836SJohn.Forte@Sun.COM static int fcip_plogi_in_progress(struct fcip *fptr);
233*7836SJohn.Forte@Sun.COM static int fcip_check_port_exists(struct fcip *fptr);
234*7836SJohn.Forte@Sun.COM static int fcip_is_supported_fc_topology(int fc_topology);
235*7836SJohn.Forte@Sun.COM 
236*7836SJohn.Forte@Sun.COM 
237*7836SJohn.Forte@Sun.COM /* pkt specific */
238*7836SJohn.Forte@Sun.COM static fcip_pkt_t *fcip_pkt_alloc(struct fcip *fptr, mblk_t *bp,
239*7836SJohn.Forte@Sun.COM     int flags, int datalen);
240*7836SJohn.Forte@Sun.COM static void fcip_pkt_free(struct fcip_pkt *fcip_pkt, int flags);
241*7836SJohn.Forte@Sun.COM static fcip_pkt_t *fcip_ipkt_alloc(struct fcip *fptr, int cmdlen,
242*7836SJohn.Forte@Sun.COM     int resplen, opaque_t pd, int flags);
243*7836SJohn.Forte@Sun.COM static void fcip_ipkt_free(fcip_pkt_t *fcip_pkt);
244*7836SJohn.Forte@Sun.COM static void fcip_ipkt_callback(fc_packet_t *fc_pkt);
245*7836SJohn.Forte@Sun.COM static void fcip_free_pkt_dma(fcip_pkt_t *fcip_pkt);
246*7836SJohn.Forte@Sun.COM static void fcip_pkt_callback(fc_packet_t *fc_pkt);
247*7836SJohn.Forte@Sun.COM static void fcip_init_unicast_pkt(fcip_pkt_t *fcip_pkt, fc_portid_t sid,
248*7836SJohn.Forte@Sun.COM     fc_portid_t did, void (*comp) ());
249*7836SJohn.Forte@Sun.COM static int fcip_transport(fcip_pkt_t *fcip_pkt);
250*7836SJohn.Forte@Sun.COM static void fcip_pkt_timeout(void *arg);
251*7836SJohn.Forte@Sun.COM static void fcip_timeout(void *arg);
252*7836SJohn.Forte@Sun.COM static void fcip_fdestp_enqueue_pkt(struct fcip_dest *fdestp,
253*7836SJohn.Forte@Sun.COM     fcip_pkt_t *fcip_pkt);
254*7836SJohn.Forte@Sun.COM static int fcip_fdestp_dequeue_pkt(struct fcip_dest *fdestp,
255*7836SJohn.Forte@Sun.COM     fcip_pkt_t *fcip_pkt);
256*7836SJohn.Forte@Sun.COM static int fcip_sendup_constructor(void *buf, void *arg, int flags);
257*7836SJohn.Forte@Sun.COM static void fcip_sendup_thr(void *arg);
258*7836SJohn.Forte@Sun.COM static int fcip_sendup_alloc_enque(struct fcip *ftpr, mblk_t *mp,
259*7836SJohn.Forte@Sun.COM     struct fcipstr *(*f)());
260*7836SJohn.Forte@Sun.COM 
261*7836SJohn.Forte@Sun.COM /*
262*7836SJohn.Forte@Sun.COM  * zero copy inbound data handling
263*7836SJohn.Forte@Sun.COM  */
264*7836SJohn.Forte@Sun.COM #ifdef FCIP_ESBALLOC
265*7836SJohn.Forte@Sun.COM static void fcip_ubfree(char *arg);
266*7836SJohn.Forte@Sun.COM #endif /* FCIP_ESBALLOC */
267*7836SJohn.Forte@Sun.COM 
268*7836SJohn.Forte@Sun.COM #if !defined(FCIP_ESBALLOC)
269*7836SJohn.Forte@Sun.COM static void *fcip_allocb(size_t size, uint_t pri);
270*7836SJohn.Forte@Sun.COM #endif
271*7836SJohn.Forte@Sun.COM 
272*7836SJohn.Forte@Sun.COM 
273*7836SJohn.Forte@Sun.COM /* FCIP FARP support functions */
274*7836SJohn.Forte@Sun.COM static struct fcip_dest *fcip_do_farp(struct fcip *fptr, la_wwn_t *pwwn,
275*7836SJohn.Forte@Sun.COM     char *ip_addr, size_t ip_addr_len, int flags);
276*7836SJohn.Forte@Sun.COM static void fcip_init_broadcast_pkt(fcip_pkt_t *fcip_pkt, void (*comp) (),
277*7836SJohn.Forte@Sun.COM     int is_els);
278*7836SJohn.Forte@Sun.COM static int fcip_handle_farp_request(struct fcip *fptr, la_els_farp_t *fcmd);
279*7836SJohn.Forte@Sun.COM static int fcip_handle_farp_response(struct fcip *fptr, la_els_farp_t *fcmd);
280*7836SJohn.Forte@Sun.COM static void fcip_cache_arp_broadcast(struct fcip *ftpr, fc_unsol_buf_t *buf);
281*7836SJohn.Forte@Sun.COM static void fcip_port_ns(void *arg);
282*7836SJohn.Forte@Sun.COM 
283*7836SJohn.Forte@Sun.COM #ifdef DEBUG
284*7836SJohn.Forte@Sun.COM 
285*7836SJohn.Forte@Sun.COM #include <sys/debug.h>
286*7836SJohn.Forte@Sun.COM 
287*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DEFAULT	0x1
288*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_ATTACH	0x2
289*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_INIT		0x4
290*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DETACH	0x8
291*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DLPI		0x10
292*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_ELS		0x20
293*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DOWNSTREAM	0x40
294*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_UPSTREAM	0x80
295*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_MISC		0x100
296*7836SJohn.Forte@Sun.COM 
297*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_STARTUP	(FCIP_DEBUG_ATTACH|FCIP_DEBUG_INIT)
298*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DATAOUT	(FCIP_DEBUG_DLPI|FCIP_DEBUG_DOWNSTREAM)
299*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG_DATAIN	(FCIP_DEBUG_ELS|FCIP_DEBUG_UPSTREAM)
300*7836SJohn.Forte@Sun.COM 
301*7836SJohn.Forte@Sun.COM static int fcip_debug = FCIP_DEBUG_DEFAULT;
302*7836SJohn.Forte@Sun.COM 
303*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG(level, args)	\
304*7836SJohn.Forte@Sun.COM 	if (fcip_debug & (level))	cmn_err args;
305*7836SJohn.Forte@Sun.COM 
306*7836SJohn.Forte@Sun.COM #else	/* DEBUG */
307*7836SJohn.Forte@Sun.COM 
308*7836SJohn.Forte@Sun.COM #define	FCIP_DEBUG(level, args)		/* do nothing */
309*7836SJohn.Forte@Sun.COM 
310*7836SJohn.Forte@Sun.COM #endif	/* DEBUG */
311*7836SJohn.Forte@Sun.COM 
312*7836SJohn.Forte@Sun.COM #define	KIOIP	KSTAT_INTR_PTR(fcip->fcip_intrstats)
313*7836SJohn.Forte@Sun.COM 
314*7836SJohn.Forte@Sun.COM /*
315*7836SJohn.Forte@Sun.COM  * Endian independent ethernet to WWN copy
316*7836SJohn.Forte@Sun.COM  */
317*7836SJohn.Forte@Sun.COM #define	ether_to_wwn(E, W)	\
318*7836SJohn.Forte@Sun.COM 	bzero((void *)(W), sizeof (la_wwn_t)); \
319*7836SJohn.Forte@Sun.COM 	bcopy((void *)(E), (void *)&((W)->raw_wwn[2]), ETHERADDRL); \
320*7836SJohn.Forte@Sun.COM 	(W)->raw_wwn[0] |= 0x10
321*7836SJohn.Forte@Sun.COM 
322*7836SJohn.Forte@Sun.COM /*
323*7836SJohn.Forte@Sun.COM  * wwn_to_ether : Endian independent, copies a WWN to struct ether_addr.
324*7836SJohn.Forte@Sun.COM  * The args to the macro are pointers to WWN and ether_addr structures
325*7836SJohn.Forte@Sun.COM  */
326*7836SJohn.Forte@Sun.COM #define	wwn_to_ether(W, E)	\
327*7836SJohn.Forte@Sun.COM 	bcopy((void *)&((W)->raw_wwn[2]), (void *)E, ETHERADDRL)
328*7836SJohn.Forte@Sun.COM 
329*7836SJohn.Forte@Sun.COM /*
330*7836SJohn.Forte@Sun.COM  * The module_info structure contains identification and limit values.
331*7836SJohn.Forte@Sun.COM  * All queues associated with a certain driver share the same module_info
332*7836SJohn.Forte@Sun.COM  * structures. This structure defines the characteristics of that driver/
333*7836SJohn.Forte@Sun.COM  * module's queues. The module name must be unique. The max and min packet
334*7836SJohn.Forte@Sun.COM  * sizes limit the no. of characters in M_DATA messages. The Hi and Lo
335*7836SJohn.Forte@Sun.COM  * water marks are for flow control when a module has a service procedure.
336*7836SJohn.Forte@Sun.COM  */
337*7836SJohn.Forte@Sun.COM static struct module_info	fcipminfo = {
338*7836SJohn.Forte@Sun.COM 	FCIPIDNUM,	/* mi_idnum : Module ID num */
339*7836SJohn.Forte@Sun.COM 	FCIPNAME, 	/* mi_idname: Module Name */
340*7836SJohn.Forte@Sun.COM 	FCIPMINPSZ,	/* mi_minpsz: Min packet size */
341*7836SJohn.Forte@Sun.COM 	FCIPMAXPSZ,	/* mi_maxpsz: Max packet size */
342*7836SJohn.Forte@Sun.COM 	FCIPHIWAT,	/* mi_hiwat : High water mark */
343*7836SJohn.Forte@Sun.COM 	FCIPLOWAT	/* mi_lowat : Low water mark */
344*7836SJohn.Forte@Sun.COM };
345*7836SJohn.Forte@Sun.COM 
346*7836SJohn.Forte@Sun.COM /*
347*7836SJohn.Forte@Sun.COM  * The qinit structres contain the module put, service. open and close
348*7836SJohn.Forte@Sun.COM  * procedure pointers. All modules and drivers with the same streamtab
349*7836SJohn.Forte@Sun.COM  * file (i.e same fmodsw or cdevsw entry points) point to the same
350*7836SJohn.Forte@Sun.COM  * upstream (read) and downstream (write) qinit structs.
351*7836SJohn.Forte@Sun.COM  */
352*7836SJohn.Forte@Sun.COM static struct qinit	fcip_rinit = {
353*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_putp */
354*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_srvp */
355*7836SJohn.Forte@Sun.COM 	fcip_open,	/* qi_qopen */
356*7836SJohn.Forte@Sun.COM 	fcip_close,	/* qi_qclose */
357*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_qadmin */
358*7836SJohn.Forte@Sun.COM 	&fcipminfo,	/* qi_minfo */
359*7836SJohn.Forte@Sun.COM 	NULL		/* qi_mstat */
360*7836SJohn.Forte@Sun.COM };
361*7836SJohn.Forte@Sun.COM 
362*7836SJohn.Forte@Sun.COM static struct qinit	fcip_winit = {
363*7836SJohn.Forte@Sun.COM 	fcip_wput,	/* qi_putp */
364*7836SJohn.Forte@Sun.COM 	fcip_wsrv,	/* qi_srvp */
365*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_qopen */
366*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_qclose */
367*7836SJohn.Forte@Sun.COM 	NULL,		/* qi_qadmin */
368*7836SJohn.Forte@Sun.COM 	&fcipminfo,	/* qi_minfo */
369*7836SJohn.Forte@Sun.COM 	NULL		/* qi_mstat */
370*7836SJohn.Forte@Sun.COM };
371*7836SJohn.Forte@Sun.COM 
372*7836SJohn.Forte@Sun.COM /*
373*7836SJohn.Forte@Sun.COM  * streamtab contains pointers to the read and write qinit structures
374*7836SJohn.Forte@Sun.COM  */
375*7836SJohn.Forte@Sun.COM 
376*7836SJohn.Forte@Sun.COM static struct streamtab fcip_info = {
377*7836SJohn.Forte@Sun.COM 	&fcip_rinit,	/* st_rdinit */
378*7836SJohn.Forte@Sun.COM 	&fcip_winit,	/* st_wrinit */
379*7836SJohn.Forte@Sun.COM 	NULL,		/* st_muxrinit */
380*7836SJohn.Forte@Sun.COM 	NULL,		/* st_muxwrinit */
381*7836SJohn.Forte@Sun.COM };
382*7836SJohn.Forte@Sun.COM 
383*7836SJohn.Forte@Sun.COM static struct cb_ops  fcip_cb_ops = {
384*7836SJohn.Forte@Sun.COM 	nodev,				/* open */
385*7836SJohn.Forte@Sun.COM 	nodev,				/* close */
386*7836SJohn.Forte@Sun.COM 	nodev,				/* strategy */
387*7836SJohn.Forte@Sun.COM 	nodev,				/* print */
388*7836SJohn.Forte@Sun.COM 	nodev,				/* dump */
389*7836SJohn.Forte@Sun.COM 	nodev,				/* read */
390*7836SJohn.Forte@Sun.COM 	nodev,				/* write */
391*7836SJohn.Forte@Sun.COM 	nodev,				/* ioctl */
392*7836SJohn.Forte@Sun.COM 	nodev,				/* devmap */
393*7836SJohn.Forte@Sun.COM 	nodev,				/* mmap */
394*7836SJohn.Forte@Sun.COM 	nodev,				/* segmap */
395*7836SJohn.Forte@Sun.COM 	nochpoll,			/* poll */
396*7836SJohn.Forte@Sun.COM 	ddi_prop_op,			/* cb_prop_op */
397*7836SJohn.Forte@Sun.COM 	&fcip_info,			/* streamtab  */
398*7836SJohn.Forte@Sun.COM 	D_MP | D_HOTPLUG,		/* Driver compatibility flag */
399*7836SJohn.Forte@Sun.COM 	CB_REV,				/* rev */
400*7836SJohn.Forte@Sun.COM 	nodev,				/* int (*cb_aread)() */
401*7836SJohn.Forte@Sun.COM 	nodev				/* int (*cb_awrite)() */
402*7836SJohn.Forte@Sun.COM };
403*7836SJohn.Forte@Sun.COM 
404*7836SJohn.Forte@Sun.COM /*
405*7836SJohn.Forte@Sun.COM  * autoconfiguration routines.
406*7836SJohn.Forte@Sun.COM  */
407*7836SJohn.Forte@Sun.COM static struct dev_ops fcip_ops = {
408*7836SJohn.Forte@Sun.COM 	DEVO_REV,		/* devo_rev, */
409*7836SJohn.Forte@Sun.COM 	0,			/* refcnt  */
410*7836SJohn.Forte@Sun.COM 	fcip_getinfo,		/* info */
411*7836SJohn.Forte@Sun.COM 	nulldev,		/* identify */
412*7836SJohn.Forte@Sun.COM 	nulldev,		/* probe */
413*7836SJohn.Forte@Sun.COM 	fcip_attach,		/* attach */
414*7836SJohn.Forte@Sun.COM 	fcip_detach,		/* detach */
415*7836SJohn.Forte@Sun.COM 	nodev,			/* RESET */
416*7836SJohn.Forte@Sun.COM 	&fcip_cb_ops,		/* driver operations */
417*7836SJohn.Forte@Sun.COM 	NULL,			/* bus operations */
418*7836SJohn.Forte@Sun.COM 	ddi_power		/* power management */
419*7836SJohn.Forte@Sun.COM };
420*7836SJohn.Forte@Sun.COM 
421*7836SJohn.Forte@Sun.COM #define	FCIP_VERSION	"1.61"
422*7836SJohn.Forte@Sun.COM #define	FCIP_NAME	"SunFC FCIP v" FCIP_VERSION
423*7836SJohn.Forte@Sun.COM 
424*7836SJohn.Forte@Sun.COM #define	PORT_DRIVER	"fp"
425*7836SJohn.Forte@Sun.COM 
426*7836SJohn.Forte@Sun.COM #define	GETSTRUCT(struct, number)	\
427*7836SJohn.Forte@Sun.COM 	((struct *)kmem_zalloc((size_t)(sizeof (struct) * (number)), \
428*7836SJohn.Forte@Sun.COM 		KM_SLEEP))
429*7836SJohn.Forte@Sun.COM 
430*7836SJohn.Forte@Sun.COM static struct modldrv modldrv = {
431*7836SJohn.Forte@Sun.COM 	&mod_driverops,			/* Type of module - driver */
432*7836SJohn.Forte@Sun.COM 	FCIP_NAME,			/* Name of module */
433*7836SJohn.Forte@Sun.COM 	&fcip_ops,			/* driver ops */
434*7836SJohn.Forte@Sun.COM };
435*7836SJohn.Forte@Sun.COM 
436*7836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
437*7836SJohn.Forte@Sun.COM 	MODREV_1, (void *)&modldrv, NULL
438*7836SJohn.Forte@Sun.COM };
439*7836SJohn.Forte@Sun.COM 
440*7836SJohn.Forte@Sun.COM 
441*7836SJohn.Forte@Sun.COM /*
442*7836SJohn.Forte@Sun.COM  * Now for some global statics
443*7836SJohn.Forte@Sun.COM  */
444*7836SJohn.Forte@Sun.COM static uint32_t	fcip_ub_nbufs = FCIP_UB_NBUFS;
445*7836SJohn.Forte@Sun.COM static uint32_t fcip_ub_size = FCIP_UB_SIZE;
446*7836SJohn.Forte@Sun.COM static int fcip_pkt_ttl_ticks = FCIP_PKT_TTL;
447*7836SJohn.Forte@Sun.COM static int fcip_tick_incr = 1;
448*7836SJohn.Forte@Sun.COM static int fcip_wait_cmds = FCIP_WAIT_CMDS;
449*7836SJohn.Forte@Sun.COM static int fcip_num_attaching = 0;
450*7836SJohn.Forte@Sun.COM static int fcip_port_attach_pending = 0;
451*7836SJohn.Forte@Sun.COM static int fcip_create_nodes_on_demand = 1;	/* keep it similar to fcp */
452*7836SJohn.Forte@Sun.COM static int fcip_cache_on_arp_broadcast = 0;
453*7836SJohn.Forte@Sun.COM static int fcip_farp_supported = 0;
454*7836SJohn.Forte@Sun.COM static int fcip_minor_node_created = 0;
455*7836SJohn.Forte@Sun.COM 
456*7836SJohn.Forte@Sun.COM /*
457*7836SJohn.Forte@Sun.COM  * Supported FCAs
458*7836SJohn.Forte@Sun.COM  */
459*7836SJohn.Forte@Sun.COM #define	QLC_PORT_1_ID_BITS		0x100
460*7836SJohn.Forte@Sun.COM #define	QLC_PORT_2_ID_BITS		0x101
461*7836SJohn.Forte@Sun.COM #define	QLC_PORT_NAA			0x2
462*7836SJohn.Forte@Sun.COM #define	QLC_MODULE_NAME			"qlc"
463*7836SJohn.Forte@Sun.COM #define	IS_QLC_PORT(port_dip)		\
464*7836SJohn.Forte@Sun.COM 			(strcmp(ddi_driver_name(ddi_get_parent((port_dip))),\
465*7836SJohn.Forte@Sun.COM 			QLC_MODULE_NAME) == 0)
466*7836SJohn.Forte@Sun.COM 
467*7836SJohn.Forte@Sun.COM 
468*7836SJohn.Forte@Sun.COM /*
469*7836SJohn.Forte@Sun.COM  * fcip softstate structures head.
470*7836SJohn.Forte@Sun.COM  */
471*7836SJohn.Forte@Sun.COM 
472*7836SJohn.Forte@Sun.COM static void *fcip_softp = NULL;
473*7836SJohn.Forte@Sun.COM 
474*7836SJohn.Forte@Sun.COM /*
475*7836SJohn.Forte@Sun.COM  * linked list of active (inuse) driver streams
476*7836SJohn.Forte@Sun.COM  */
477*7836SJohn.Forte@Sun.COM 
478*7836SJohn.Forte@Sun.COM static int fcip_num_instances = 0;
479*7836SJohn.Forte@Sun.COM static dev_info_t *fcip_module_dip = (dev_info_t *)0;
480*7836SJohn.Forte@Sun.COM 
481*7836SJohn.Forte@Sun.COM 
482*7836SJohn.Forte@Sun.COM /*
483*7836SJohn.Forte@Sun.COM  * Ethernet broadcast address: Broadcast addressing in IP over fibre
484*7836SJohn.Forte@Sun.COM  * channel should be the IEEE ULA (also the low 6 bytes of the Port WWN).
485*7836SJohn.Forte@Sun.COM  *
486*7836SJohn.Forte@Sun.COM  * The broadcast addressing varies for differing topologies a node may be in:
487*7836SJohn.Forte@Sun.COM  *	- On a private loop the ARP broadcast is a class 3 sequence sent
488*7836SJohn.Forte@Sun.COM  *	  using OPNfr (Open Broadcast Replicate primitive) followed by
489*7836SJohn.Forte@Sun.COM  *	  the ARP frame to D_ID 0xFFFFFF
490*7836SJohn.Forte@Sun.COM  *
491*7836SJohn.Forte@Sun.COM  *	- On a public Loop the broadcast sequence is sent to AL_PA 0x00
492*7836SJohn.Forte@Sun.COM  *	  (no OPNfr primitive).
493*7836SJohn.Forte@Sun.COM  *
494*7836SJohn.Forte@Sun.COM  *	- For direct attach and point to point topologies we just send
495*7836SJohn.Forte@Sun.COM  *	  the frame to D_ID 0xFFFFFF
496*7836SJohn.Forte@Sun.COM  *
497*7836SJohn.Forte@Sun.COM  * For public loop the handling would probably be different - for now
498*7836SJohn.Forte@Sun.COM  * I'll just declare this struct - It can be deleted if not necessary.
499*7836SJohn.Forte@Sun.COM  *
500*7836SJohn.Forte@Sun.COM  */
501*7836SJohn.Forte@Sun.COM 
502*7836SJohn.Forte@Sun.COM 
503*7836SJohn.Forte@Sun.COM /*
504*7836SJohn.Forte@Sun.COM  * DL_INFO_ACK template for the fcip module. The dl_info_ack_t structure is
505*7836SJohn.Forte@Sun.COM  * returned as a part of an  DL_INFO_ACK message which is a M_PCPROTO message
506*7836SJohn.Forte@Sun.COM  * returned in response to a DL_INFO_REQ message sent to us from a DLS user
507*7836SJohn.Forte@Sun.COM  * Let us fake an ether header as much as possible.
508*7836SJohn.Forte@Sun.COM  *
509*7836SJohn.Forte@Sun.COM  * dl_addr_length is the Provider's DLSAP addr which is SAP addr +
510*7836SJohn.Forte@Sun.COM  *                Physical addr of the provider. We set this to
511*7836SJohn.Forte@Sun.COM  *                ushort_t + sizeof (la_wwn_t) for Fibre Channel ports.
512*7836SJohn.Forte@Sun.COM  * dl_mac_type    Lets just use DL_ETHER - we can try using DL_IPFC, a new
513*7836SJohn.Forte@Sun.COM  *		  dlpi.h define later.
514*7836SJohn.Forte@Sun.COM  * dl_sap_length  -2 indicating the SAP address follows the Physical addr
515*7836SJohn.Forte@Sun.COM  *		  component in the DLSAP addr.
516*7836SJohn.Forte@Sun.COM  * dl_service_mode: DLCLDS - connectionless data link service.
517*7836SJohn.Forte@Sun.COM  *
518*7836SJohn.Forte@Sun.COM  */
519*7836SJohn.Forte@Sun.COM 
520*7836SJohn.Forte@Sun.COM static dl_info_ack_t fcip_infoack = {
521*7836SJohn.Forte@Sun.COM 	DL_INFO_ACK,				/* dl_primitive */
522*7836SJohn.Forte@Sun.COM 	FCIPMTU,				/* dl_max_sdu */
523*7836SJohn.Forte@Sun.COM 	0,					/* dl_min_sdu */
524*7836SJohn.Forte@Sun.COM 	FCIPADDRL,				/* dl_addr_length */
525*7836SJohn.Forte@Sun.COM 	DL_ETHER,				/* dl_mac_type */
526*7836SJohn.Forte@Sun.COM 	0,					/* dl_reserved */
527*7836SJohn.Forte@Sun.COM 	0,					/* dl_current_state */
528*7836SJohn.Forte@Sun.COM 	-2,					/* dl_sap_length */
529*7836SJohn.Forte@Sun.COM 	DL_CLDLS,				/* dl_service_mode */
530*7836SJohn.Forte@Sun.COM 	0,					/* dl_qos_length */
531*7836SJohn.Forte@Sun.COM 	0,					/* dl_qos_offset */
532*7836SJohn.Forte@Sun.COM 	0,					/* dl_range_length */
533*7836SJohn.Forte@Sun.COM 	0,					/* dl_range_offset */
534*7836SJohn.Forte@Sun.COM 	DL_STYLE2,				/* dl_provider_style */
535*7836SJohn.Forte@Sun.COM 	sizeof (dl_info_ack_t),			/* dl_addr_offset */
536*7836SJohn.Forte@Sun.COM 	DL_VERSION_2,				/* dl_version */
537*7836SJohn.Forte@Sun.COM 	ETHERADDRL,				/* dl_brdcst_addr_length */
538*7836SJohn.Forte@Sun.COM 	sizeof (dl_info_ack_t) + FCIPADDRL,	/* dl_brdcst_addr_offset */
539*7836SJohn.Forte@Sun.COM 	0					/* dl_growth */
540*7836SJohn.Forte@Sun.COM };
541*7836SJohn.Forte@Sun.COM 
542*7836SJohn.Forte@Sun.COM /*
543*7836SJohn.Forte@Sun.COM  * FCIP broadcast address definition.
544*7836SJohn.Forte@Sun.COM  */
545*7836SJohn.Forte@Sun.COM static	struct ether_addr	fcipnhbroadcastaddr = {
546*7836SJohn.Forte@Sun.COM 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
547*7836SJohn.Forte@Sun.COM };
548*7836SJohn.Forte@Sun.COM 
549*7836SJohn.Forte@Sun.COM /*
550*7836SJohn.Forte@Sun.COM  * RFC2625 requires the broadcast ARP address in the ARP data payload to
551*7836SJohn.Forte@Sun.COM  * be set to 0x00 00 00 00 00 00 for ARP broadcast packets
552*7836SJohn.Forte@Sun.COM  */
553*7836SJohn.Forte@Sun.COM static	struct ether_addr	fcip_arpbroadcast_addr = {
554*7836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
555*7836SJohn.Forte@Sun.COM };
556*7836SJohn.Forte@Sun.COM 
557*7836SJohn.Forte@Sun.COM 
558*7836SJohn.Forte@Sun.COM #define	ether_bcopy(src, dest)	bcopy((src), (dest), ETHERADDRL);
559*7836SJohn.Forte@Sun.COM 
560*7836SJohn.Forte@Sun.COM /*
561*7836SJohn.Forte@Sun.COM  * global kernel locks
562*7836SJohn.Forte@Sun.COM  */
563*7836SJohn.Forte@Sun.COM static kcondvar_t	fcip_global_cv;
564*7836SJohn.Forte@Sun.COM static kmutex_t		fcip_global_mutex;
565*7836SJohn.Forte@Sun.COM 
566*7836SJohn.Forte@Sun.COM /*
567*7836SJohn.Forte@Sun.COM  * fctl external defines
568*7836SJohn.Forte@Sun.COM  */
569*7836SJohn.Forte@Sun.COM extern int fc_ulp_add(fc_ulp_modinfo_t *);
570*7836SJohn.Forte@Sun.COM 
571*7836SJohn.Forte@Sun.COM /*
572*7836SJohn.Forte@Sun.COM  * fctl data structures
573*7836SJohn.Forte@Sun.COM  */
574*7836SJohn.Forte@Sun.COM 
575*7836SJohn.Forte@Sun.COM #define	FCIP_REV	0x07
576*7836SJohn.Forte@Sun.COM 
577*7836SJohn.Forte@Sun.COM /* linked list of port info structures */
578*7836SJohn.Forte@Sun.COM static fcip_port_info_t *fcip_port_head = NULL;
579*7836SJohn.Forte@Sun.COM 
580*7836SJohn.Forte@Sun.COM /* linked list of fcip structures */
581*7836SJohn.Forte@Sun.COM static struct fcipstr	*fcipstrup = NULL;
582*7836SJohn.Forte@Sun.COM static krwlock_t	fcipstruplock;
583*7836SJohn.Forte@Sun.COM 
584*7836SJohn.Forte@Sun.COM 
585*7836SJohn.Forte@Sun.COM /*
586*7836SJohn.Forte@Sun.COM  * Module information structure. This structure gives the FC Transport modules
587*7836SJohn.Forte@Sun.COM  * information about an ULP that registers with it.
588*7836SJohn.Forte@Sun.COM  */
589*7836SJohn.Forte@Sun.COM static fc_ulp_modinfo_t	fcip_modinfo = {
590*7836SJohn.Forte@Sun.COM 	0,			/* for xref checks? */
591*7836SJohn.Forte@Sun.COM 	FCTL_ULP_MODREV_4,	/* FCIP revision */
592*7836SJohn.Forte@Sun.COM 	FC_TYPE_IS8802_SNAP,	/* type 5 for SNAP encapsulated datagrams */
593*7836SJohn.Forte@Sun.COM 	FCIP_NAME,		/* module name as in the modldrv struct */
594*7836SJohn.Forte@Sun.COM 	0x0,			/* get all statec callbacks for now */
595*7836SJohn.Forte@Sun.COM 	fcip_port_attach,	/* port attach callback */
596*7836SJohn.Forte@Sun.COM 	fcip_port_detach,	/* port detach callback */
597*7836SJohn.Forte@Sun.COM 	fcip_port_ioctl,	/* port ioctl callback */
598*7836SJohn.Forte@Sun.COM 	fcip_els_cb,		/* els callback */
599*7836SJohn.Forte@Sun.COM 	fcip_data_cb,		/* data callback */
600*7836SJohn.Forte@Sun.COM 	fcip_statec_cb		/* state change callback */
601*7836SJohn.Forte@Sun.COM };
602*7836SJohn.Forte@Sun.COM 
603*7836SJohn.Forte@Sun.COM 
604*7836SJohn.Forte@Sun.COM /*
605*7836SJohn.Forte@Sun.COM  * Solaris 9 and up, the /kernel/drv/fp.conf file will have the following entry
606*7836SJohn.Forte@Sun.COM  *
607*7836SJohn.Forte@Sun.COM  * ddi-forceattach=1;
608*7836SJohn.Forte@Sun.COM  *
609*7836SJohn.Forte@Sun.COM  * This will ensure that fp is loaded at bootup. No additional checks are needed
610*7836SJohn.Forte@Sun.COM  */
611*7836SJohn.Forte@Sun.COM int
_init(void)612*7836SJohn.Forte@Sun.COM _init(void)
613*7836SJohn.Forte@Sun.COM {
614*7836SJohn.Forte@Sun.COM 	int	rval;
615*7836SJohn.Forte@Sun.COM 
616*7836SJohn.Forte@Sun.COM 	FCIP_TNF_LOAD();
617*7836SJohn.Forte@Sun.COM 
618*7836SJohn.Forte@Sun.COM 	/*
619*7836SJohn.Forte@Sun.COM 	 * Initialize the mutexs used by port attach and other callbacks.
620*7836SJohn.Forte@Sun.COM 	 * The transport can call back into our port_attach_callback
621*7836SJohn.Forte@Sun.COM 	 * routine even before _init() completes and bad things can happen.
622*7836SJohn.Forte@Sun.COM 	 */
623*7836SJohn.Forte@Sun.COM 	mutex_init(&fcip_global_mutex, NULL, MUTEX_DRIVER, NULL);
624*7836SJohn.Forte@Sun.COM 	cv_init(&fcip_global_cv, NULL, CV_DRIVER, NULL);
625*7836SJohn.Forte@Sun.COM 	rw_init(&fcipstruplock, NULL, RW_DRIVER, NULL);
626*7836SJohn.Forte@Sun.COM 
627*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
628*7836SJohn.Forte@Sun.COM 	fcip_port_attach_pending = 1;
629*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
630*7836SJohn.Forte@Sun.COM 
631*7836SJohn.Forte@Sun.COM 	/*
632*7836SJohn.Forte@Sun.COM 	 * Now attempt to register fcip with the transport.
633*7836SJohn.Forte@Sun.COM 	 * If fc_ulp_add fails, fcip module will not be loaded.
634*7836SJohn.Forte@Sun.COM 	 */
635*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_add(&fcip_modinfo);
636*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
637*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fcip_global_mutex);
638*7836SJohn.Forte@Sun.COM 		cv_destroy(&fcip_global_cv);
639*7836SJohn.Forte@Sun.COM 		rw_destroy(&fcipstruplock);
640*7836SJohn.Forte@Sun.COM 		switch (rval) {
641*7836SJohn.Forte@Sun.COM 		case FC_ULP_SAMEMODULE:
642*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
643*7836SJohn.Forte@Sun.COM 			    "!fcip: module is already registered with"
644*7836SJohn.Forte@Sun.COM 			    " transport"));
645*7836SJohn.Forte@Sun.COM 			rval = EEXIST;
646*7836SJohn.Forte@Sun.COM 			break;
647*7836SJohn.Forte@Sun.COM 		case FC_ULP_SAMETYPE:
648*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
649*7836SJohn.Forte@Sun.COM 			    "!fcip: Another module of the same ULP type 0x%x"
650*7836SJohn.Forte@Sun.COM 			    " is already registered with the transport",
651*7836SJohn.Forte@Sun.COM 			    fcip_modinfo.ulp_type));
652*7836SJohn.Forte@Sun.COM 			rval = EEXIST;
653*7836SJohn.Forte@Sun.COM 			break;
654*7836SJohn.Forte@Sun.COM 		case FC_BADULP:
655*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
656*7836SJohn.Forte@Sun.COM 			    "!fcip: Current fcip version 0x%x does not match"
657*7836SJohn.Forte@Sun.COM 			    " fctl version",
658*7836SJohn.Forte@Sun.COM 			    fcip_modinfo.ulp_rev));
659*7836SJohn.Forte@Sun.COM 			rval = ENODEV;
660*7836SJohn.Forte@Sun.COM 			break;
661*7836SJohn.Forte@Sun.COM 		default:
662*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
663*7836SJohn.Forte@Sun.COM 			    "!fcip: fc_ulp_add failed with status 0x%x", rval));
664*7836SJohn.Forte@Sun.COM 			rval = ENODEV;
665*7836SJohn.Forte@Sun.COM 			break;
666*7836SJohn.Forte@Sun.COM 		}
667*7836SJohn.Forte@Sun.COM 		FCIP_TNF_UNLOAD(&modlinkage);
668*7836SJohn.Forte@Sun.COM 		return (rval);
669*7836SJohn.Forte@Sun.COM 	}
670*7836SJohn.Forte@Sun.COM 
671*7836SJohn.Forte@Sun.COM 	if ((rval = ddi_soft_state_init(&fcip_softp, sizeof (struct fcip),
672*7836SJohn.Forte@Sun.COM 			FCIP_NUM_INSTANCES)) != 0) {
673*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fcip_global_mutex);
674*7836SJohn.Forte@Sun.COM 		cv_destroy(&fcip_global_cv);
675*7836SJohn.Forte@Sun.COM 		rw_destroy(&fcipstruplock);
676*7836SJohn.Forte@Sun.COM 		(void) fc_ulp_remove(&fcip_modinfo);
677*7836SJohn.Forte@Sun.COM 		FCIP_TNF_UNLOAD(&modlinkage);
678*7836SJohn.Forte@Sun.COM 		return (rval);
679*7836SJohn.Forte@Sun.COM 	}
680*7836SJohn.Forte@Sun.COM 
681*7836SJohn.Forte@Sun.COM 	if ((rval = mod_install(&modlinkage)) != 0) {
682*7836SJohn.Forte@Sun.COM 		FCIP_TNF_UNLOAD(&modlinkage);
683*7836SJohn.Forte@Sun.COM 		(void) fc_ulp_remove(&fcip_modinfo);
684*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fcip_global_mutex);
685*7836SJohn.Forte@Sun.COM 		cv_destroy(&fcip_global_cv);
686*7836SJohn.Forte@Sun.COM 		rw_destroy(&fcipstruplock);
687*7836SJohn.Forte@Sun.COM 		ddi_soft_state_fini(&fcip_softp);
688*7836SJohn.Forte@Sun.COM 	}
689*7836SJohn.Forte@Sun.COM 	return (rval);
690*7836SJohn.Forte@Sun.COM }
691*7836SJohn.Forte@Sun.COM 
692*7836SJohn.Forte@Sun.COM /*
693*7836SJohn.Forte@Sun.COM  * Unload the port driver if this was the only ULP loaded and then
694*7836SJohn.Forte@Sun.COM  * deregister with the transport.
695*7836SJohn.Forte@Sun.COM  */
696*7836SJohn.Forte@Sun.COM int
_fini(void)697*7836SJohn.Forte@Sun.COM _fini(void)
698*7836SJohn.Forte@Sun.COM {
699*7836SJohn.Forte@Sun.COM 	int	rval;
700*7836SJohn.Forte@Sun.COM 	int	rval1;
701*7836SJohn.Forte@Sun.COM 
702*7836SJohn.Forte@Sun.COM 	/*
703*7836SJohn.Forte@Sun.COM 	 * Do not permit the module to be unloaded before a port
704*7836SJohn.Forte@Sun.COM 	 * attach callback has happened.
705*7836SJohn.Forte@Sun.COM 	 */
706*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
707*7836SJohn.Forte@Sun.COM 	if (fcip_num_attaching || fcip_port_attach_pending) {
708*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
709*7836SJohn.Forte@Sun.COM 		return (EBUSY);
710*7836SJohn.Forte@Sun.COM 	}
711*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
712*7836SJohn.Forte@Sun.COM 
713*7836SJohn.Forte@Sun.COM 	if ((rval = mod_remove(&modlinkage)) != 0) {
714*7836SJohn.Forte@Sun.COM 		return (rval);
715*7836SJohn.Forte@Sun.COM 	}
716*7836SJohn.Forte@Sun.COM 
717*7836SJohn.Forte@Sun.COM 	/*
718*7836SJohn.Forte@Sun.COM 	 * unregister with the transport layer
719*7836SJohn.Forte@Sun.COM 	 */
720*7836SJohn.Forte@Sun.COM 	rval1 = fc_ulp_remove(&fcip_modinfo);
721*7836SJohn.Forte@Sun.COM 
722*7836SJohn.Forte@Sun.COM 	/*
723*7836SJohn.Forte@Sun.COM 	 * If the ULP was not registered with the transport, init should
724*7836SJohn.Forte@Sun.COM 	 * have failed. If transport has no knowledge of our existence
725*7836SJohn.Forte@Sun.COM 	 * we should simply bail out and succeed
726*7836SJohn.Forte@Sun.COM 	 */
727*7836SJohn.Forte@Sun.COM #ifdef DEBUG
728*7836SJohn.Forte@Sun.COM 	if (rval1 == FC_BADULP) {
729*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
730*7836SJohn.Forte@Sun.COM 		"fcip: ULP was never registered with the transport"));
731*7836SJohn.Forte@Sun.COM 		rval = ENODEV;
732*7836SJohn.Forte@Sun.COM 	} else if (rval1 == FC_BADTYPE) {
733*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DEFAULT, (CE_WARN,
734*7836SJohn.Forte@Sun.COM 			"fcip: No ULP of this type 0x%x was registered with "
735*7836SJohn.Forte@Sun.COM 			"transport", fcip_modinfo.ulp_type));
736*7836SJohn.Forte@Sun.COM 		rval = ENODEV;
737*7836SJohn.Forte@Sun.COM 	}
738*7836SJohn.Forte@Sun.COM #endif /* DEBUG */
739*7836SJohn.Forte@Sun.COM 
740*7836SJohn.Forte@Sun.COM 	mutex_destroy(&fcip_global_mutex);
741*7836SJohn.Forte@Sun.COM 	rw_destroy(&fcipstruplock);
742*7836SJohn.Forte@Sun.COM 	cv_destroy(&fcip_global_cv);
743*7836SJohn.Forte@Sun.COM 	ddi_soft_state_fini(&fcip_softp);
744*7836SJohn.Forte@Sun.COM 
745*7836SJohn.Forte@Sun.COM 	FCIP_TNF_UNLOAD(&modlinkage);
746*7836SJohn.Forte@Sun.COM 
747*7836SJohn.Forte@Sun.COM 	return (rval);
748*7836SJohn.Forte@Sun.COM }
749*7836SJohn.Forte@Sun.COM 
750*7836SJohn.Forte@Sun.COM /*
751*7836SJohn.Forte@Sun.COM  * Info about this loadable module
752*7836SJohn.Forte@Sun.COM  */
753*7836SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfop)754*7836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
755*7836SJohn.Forte@Sun.COM {
756*7836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
757*7836SJohn.Forte@Sun.COM }
758*7836SJohn.Forte@Sun.COM 
759*7836SJohn.Forte@Sun.COM /*
760*7836SJohn.Forte@Sun.COM  * The port attach callback is invoked by the port driver when a FCA
761*7836SJohn.Forte@Sun.COM  * port comes online and binds with the transport layer. The transport
762*7836SJohn.Forte@Sun.COM  * then callsback into all ULP modules registered with it. The Port attach
763*7836SJohn.Forte@Sun.COM  * call back will also provide the ULP module with the Port's WWN and S_ID
764*7836SJohn.Forte@Sun.COM  */
765*7836SJohn.Forte@Sun.COM /* ARGSUSED */
766*7836SJohn.Forte@Sun.COM static int
fcip_port_attach(opaque_t ulp_handle,fc_ulp_port_info_t * port_info,fc_attach_cmd_t cmd,uint32_t sid)767*7836SJohn.Forte@Sun.COM fcip_port_attach(opaque_t ulp_handle, fc_ulp_port_info_t *port_info,
768*7836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, uint32_t sid)
769*7836SJohn.Forte@Sun.COM {
770*7836SJohn.Forte@Sun.COM 	int 			rval = FC_FAILURE;
771*7836SJohn.Forte@Sun.COM 	int 			instance;
772*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
773*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = NULL;
774*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*cur_fport;
775*7836SJohn.Forte@Sun.COM 	fc_portid_t		src_id;
776*7836SJohn.Forte@Sun.COM 
777*7836SJohn.Forte@Sun.COM 	switch (cmd) {
778*7836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH: {
779*7836SJohn.Forte@Sun.COM 		la_wwn_t	*ww_pn = NULL;
780*7836SJohn.Forte@Sun.COM 		/*
781*7836SJohn.Forte@Sun.COM 		 * It was determined that, as per spec, the lower 48 bits of
782*7836SJohn.Forte@Sun.COM 		 * the port-WWN will always be unique. This will make the MAC
783*7836SJohn.Forte@Sun.COM 		 * address (i.e the lower 48 bits of the WWN), that IP/ARP
784*7836SJohn.Forte@Sun.COM 		 * depend on, unique too. Hence we should be able to remove the
785*7836SJohn.Forte@Sun.COM 		 * restriction of attaching to only one of the ports of
786*7836SJohn.Forte@Sun.COM 		 * multi port FCAs.
787*7836SJohn.Forte@Sun.COM 		 *
788*7836SJohn.Forte@Sun.COM 		 * Earlier, fcip used to attach only to qlc module and fail
789*7836SJohn.Forte@Sun.COM 		 * silently for attach failures resulting from unknown FCAs or
790*7836SJohn.Forte@Sun.COM 		 * unsupported FCA ports. Now, we'll do no such checks.
791*7836SJohn.Forte@Sun.COM 		 */
792*7836SJohn.Forte@Sun.COM 		ww_pn = &port_info->port_pwwn;
793*7836SJohn.Forte@Sun.COM 
794*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_2((fcip_port_attach, "fcip io", /* CSTYLED */,
795*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "port id bits",
796*7836SJohn.Forte@Sun.COM 			tnf_opaque, nport_id, ww_pn->w.nport_id));
797*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_NOTE,
798*7836SJohn.Forte@Sun.COM 		    "port id bits: 0x%x", ww_pn->w.nport_id));
799*7836SJohn.Forte@Sun.COM 		/*
800*7836SJohn.Forte@Sun.COM 		 * A port has come online
801*7836SJohn.Forte@Sun.COM 		 */
802*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
803*7836SJohn.Forte@Sun.COM 		fcip_num_instances++;
804*7836SJohn.Forte@Sun.COM 		fcip_num_attaching++;
805*7836SJohn.Forte@Sun.COM 
806*7836SJohn.Forte@Sun.COM 		if (fcip_port_head == NULL) {
807*7836SJohn.Forte@Sun.COM 			/* OK to sleep here ? */
808*7836SJohn.Forte@Sun.COM 			fport = kmem_zalloc(sizeof (fcip_port_info_t),
809*7836SJohn.Forte@Sun.COM 						KM_NOSLEEP);
810*7836SJohn.Forte@Sun.COM 			if (fport == NULL) {
811*7836SJohn.Forte@Sun.COM 				fcip_num_instances--;
812*7836SJohn.Forte@Sun.COM 				fcip_num_attaching--;
813*7836SJohn.Forte@Sun.COM 				ASSERT(fcip_num_attaching >= 0);
814*7836SJohn.Forte@Sun.COM 				mutex_exit(&fcip_global_mutex);
815*7836SJohn.Forte@Sun.COM 				rval = FC_FAILURE;
816*7836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN, "!fcip(%d): port attach "
817*7836SJohn.Forte@Sun.COM 				    "failed: alloc failed",
818*7836SJohn.Forte@Sun.COM 				    ddi_get_instance(port_info->port_dip));
819*7836SJohn.Forte@Sun.COM 				goto done;
820*7836SJohn.Forte@Sun.COM 			}
821*7836SJohn.Forte@Sun.COM 			fcip_port_head = fport;
822*7836SJohn.Forte@Sun.COM 		} else {
823*7836SJohn.Forte@Sun.COM 			/*
824*7836SJohn.Forte@Sun.COM 			 * traverse the port list and also check for
825*7836SJohn.Forte@Sun.COM 			 * duplicate port attaches - Nothing wrong in being
826*7836SJohn.Forte@Sun.COM 			 * paranoid Heh Heh.
827*7836SJohn.Forte@Sun.COM 			 */
828*7836SJohn.Forte@Sun.COM 			cur_fport = fcip_port_head;
829*7836SJohn.Forte@Sun.COM 			while (cur_fport != NULL) {
830*7836SJohn.Forte@Sun.COM 				if (cur_fport->fcipp_handle ==
831*7836SJohn.Forte@Sun.COM 				    port_info->port_handle) {
832*7836SJohn.Forte@Sun.COM 					fcip_num_instances--;
833*7836SJohn.Forte@Sun.COM 					fcip_num_attaching--;
834*7836SJohn.Forte@Sun.COM 					ASSERT(fcip_num_attaching >= 0);
835*7836SJohn.Forte@Sun.COM 					mutex_exit(&fcip_global_mutex);
836*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_WARN,
837*7836SJohn.Forte@Sun.COM 					    "!fcip(%d): port already "
838*7836SJohn.Forte@Sun.COM 					    "attached!!", ddi_get_instance(
839*7836SJohn.Forte@Sun.COM 					    port_info->port_dip)));
840*7836SJohn.Forte@Sun.COM 					rval = FC_FAILURE;
841*7836SJohn.Forte@Sun.COM 					goto done;
842*7836SJohn.Forte@Sun.COM 				}
843*7836SJohn.Forte@Sun.COM 				cur_fport = cur_fport->fcipp_next;
844*7836SJohn.Forte@Sun.COM 			}
845*7836SJohn.Forte@Sun.COM 			fport = kmem_zalloc(sizeof (fcip_port_info_t),
846*7836SJohn.Forte@Sun.COM 						KM_NOSLEEP);
847*7836SJohn.Forte@Sun.COM 			if (fport == NULL) {
848*7836SJohn.Forte@Sun.COM 				rval = FC_FAILURE;
849*7836SJohn.Forte@Sun.COM 				fcip_num_instances--;
850*7836SJohn.Forte@Sun.COM 				fcip_num_attaching--;
851*7836SJohn.Forte@Sun.COM 				ASSERT(fcip_num_attaching >= 0);
852*7836SJohn.Forte@Sun.COM 				mutex_exit(&fcip_global_mutex);
853*7836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN, "!fcip(%d): port attach "
854*7836SJohn.Forte@Sun.COM 				    "failed: alloc failed",
855*7836SJohn.Forte@Sun.COM 				    ddi_get_instance(port_info->port_dip));
856*7836SJohn.Forte@Sun.COM 				goto done;
857*7836SJohn.Forte@Sun.COM 			}
858*7836SJohn.Forte@Sun.COM 			fport->fcipp_next = fcip_port_head;
859*7836SJohn.Forte@Sun.COM 			fcip_port_head = fport;
860*7836SJohn.Forte@Sun.COM 		}
861*7836SJohn.Forte@Sun.COM 
862*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
863*7836SJohn.Forte@Sun.COM 
864*7836SJohn.Forte@Sun.COM 		/*
865*7836SJohn.Forte@Sun.COM 		 * now fill in the details about the port itself
866*7836SJohn.Forte@Sun.COM 		 */
867*7836SJohn.Forte@Sun.COM 		fport->fcipp_linkage = *port_info->port_linkage;
868*7836SJohn.Forte@Sun.COM 		fport->fcipp_handle = port_info->port_handle;
869*7836SJohn.Forte@Sun.COM 		fport->fcipp_dip = port_info->port_dip;
870*7836SJohn.Forte@Sun.COM 		fport->fcipp_topology = port_info->port_flags;
871*7836SJohn.Forte@Sun.COM 		fport->fcipp_pstate = port_info->port_state;
872*7836SJohn.Forte@Sun.COM 		fport->fcipp_naa = port_info->port_pwwn.w.naa_id;
873*7836SJohn.Forte@Sun.COM 		bcopy(&port_info->port_pwwn, &fport->fcipp_pwwn,
874*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
875*7836SJohn.Forte@Sun.COM 		bcopy(&port_info->port_nwwn, &fport->fcipp_nwwn,
876*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
877*7836SJohn.Forte@Sun.COM 		fport->fcipp_fca_pkt_size = port_info->port_fca_pkt_size;
878*7836SJohn.Forte@Sun.COM 		fport->fcipp_cmd_dma_attr = *port_info->port_cmd_dma_attr;
879*7836SJohn.Forte@Sun.COM 		fport->fcipp_resp_dma_attr = *port_info->port_resp_dma_attr;
880*7836SJohn.Forte@Sun.COM 		fport->fcipp_fca_acc_attr = *port_info->port_acc_attr;
881*7836SJohn.Forte@Sun.COM 		src_id.port_id = sid;
882*7836SJohn.Forte@Sun.COM 		src_id.priv_lilp_posit = 0;
883*7836SJohn.Forte@Sun.COM 		fport->fcipp_sid = src_id;
884*7836SJohn.Forte@Sun.COM 
885*7836SJohn.Forte@Sun.COM 		/*
886*7836SJohn.Forte@Sun.COM 		 * allocate soft state for this instance
887*7836SJohn.Forte@Sun.COM 		 */
888*7836SJohn.Forte@Sun.COM 		instance = ddi_get_instance(fport->fcipp_dip);
889*7836SJohn.Forte@Sun.COM 		if (ddi_soft_state_zalloc(fcip_softp,
890*7836SJohn.Forte@Sun.COM 		    instance) != DDI_SUCCESS) {
891*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
892*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "!fcip(%d): port attach failed: "
893*7836SJohn.Forte@Sun.COM 			    "soft state alloc failed", instance);
894*7836SJohn.Forte@Sun.COM 			goto failure;
895*7836SJohn.Forte@Sun.COM 		}
896*7836SJohn.Forte@Sun.COM 
897*7836SJohn.Forte@Sun.COM 		fptr = ddi_get_soft_state(fcip_softp, instance);
898*7836SJohn.Forte@Sun.COM 
899*7836SJohn.Forte@Sun.COM 		if (fptr == NULL) {
900*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
901*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "!fcip(%d): port attach failed: "
902*7836SJohn.Forte@Sun.COM 			    "failure to get soft state", instance);
903*7836SJohn.Forte@Sun.COM 			goto failure;
904*7836SJohn.Forte@Sun.COM 		}
905*7836SJohn.Forte@Sun.COM 
906*7836SJohn.Forte@Sun.COM 		/*
907*7836SJohn.Forte@Sun.COM 		 * initialize all mutexes and locks required for this module
908*7836SJohn.Forte@Sun.COM 		 */
909*7836SJohn.Forte@Sun.COM 		mutex_init(&fptr->fcip_mutex, NULL, MUTEX_DRIVER, NULL);
910*7836SJohn.Forte@Sun.COM 		mutex_init(&fptr->fcip_ub_mutex, NULL, MUTEX_DRIVER, NULL);
911*7836SJohn.Forte@Sun.COM 		mutex_init(&fptr->fcip_rt_mutex, NULL, MUTEX_DRIVER, NULL);
912*7836SJohn.Forte@Sun.COM 		mutex_init(&fptr->fcip_dest_mutex, NULL, MUTEX_DRIVER, NULL);
913*7836SJohn.Forte@Sun.COM 		mutex_init(&fptr->fcip_sendup_mutex, NULL, MUTEX_DRIVER, NULL);
914*7836SJohn.Forte@Sun.COM 		cv_init(&fptr->fcip_farp_cv, NULL, CV_DRIVER, NULL);
915*7836SJohn.Forte@Sun.COM 		cv_init(&fptr->fcip_sendup_cv, NULL, CV_DRIVER, NULL);
916*7836SJohn.Forte@Sun.COM 		cv_init(&fptr->fcip_ub_cv, NULL, CV_DRIVER, NULL);
917*7836SJohn.Forte@Sun.COM 
918*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
919*7836SJohn.Forte@Sun.COM 
920*7836SJohn.Forte@Sun.COM 		fptr->fcip_dip = fport->fcipp_dip;	/* parent's dip */
921*7836SJohn.Forte@Sun.COM 		fptr->fcip_instance = instance;
922*7836SJohn.Forte@Sun.COM 		fptr->fcip_ub_upstream = 0;
923*7836SJohn.Forte@Sun.COM 
924*7836SJohn.Forte@Sun.COM 		if (FC_PORT_STATE_MASK(port_info->port_state) ==
925*7836SJohn.Forte@Sun.COM 		    FC_STATE_ONLINE) {
926*7836SJohn.Forte@Sun.COM 			fptr->fcip_port_state = FCIP_PORT_ONLINE;
927*7836SJohn.Forte@Sun.COM 			if (fptr->fcip_flags & FCIP_LINK_DOWN) {
928*7836SJohn.Forte@Sun.COM 				fptr->fcip_flags &= ~FCIP_LINK_DOWN;
929*7836SJohn.Forte@Sun.COM 			}
930*7836SJohn.Forte@Sun.COM 		} else {
931*7836SJohn.Forte@Sun.COM 			fptr->fcip_port_state = FCIP_PORT_OFFLINE;
932*7836SJohn.Forte@Sun.COM 		}
933*7836SJohn.Forte@Sun.COM 
934*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags |= FCIP_ATTACHING;
935*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_info = fport;
936*7836SJohn.Forte@Sun.COM 
937*7836SJohn.Forte@Sun.COM 		/*
938*7836SJohn.Forte@Sun.COM 		 * Extract our MAC addr from our port's WWN. The lower 48
939*7836SJohn.Forte@Sun.COM 		 * bits will be our MAC address
940*7836SJohn.Forte@Sun.COM 		 */
941*7836SJohn.Forte@Sun.COM 		wwn_to_ether(&fport->fcipp_nwwn, &fptr->fcip_macaddr);
942*7836SJohn.Forte@Sun.COM 
943*7836SJohn.Forte@Sun.COM 		fport->fcipp_fcip = fptr;
944*7836SJohn.Forte@Sun.COM 
945*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH,
946*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "fcipdest : 0x%lx, rtable : 0x%lx",
947*7836SJohn.Forte@Sun.COM 		    (long)(sizeof (fptr->fcip_dest)),
948*7836SJohn.Forte@Sun.COM 		    (long)(sizeof (fptr->fcip_rtable))));
949*7836SJohn.Forte@Sun.COM 
950*7836SJohn.Forte@Sun.COM 		bzero(fptr->fcip_dest, sizeof (fptr->fcip_dest));
951*7836SJohn.Forte@Sun.COM 		bzero(fptr->fcip_rtable, sizeof (fptr->fcip_rtable));
952*7836SJohn.Forte@Sun.COM 
953*7836SJohn.Forte@Sun.COM 		/*
954*7836SJohn.Forte@Sun.COM 		 * create a taskq to handle sundry jobs for the driver
955*7836SJohn.Forte@Sun.COM 		 * This way we can have jobs run in parallel
956*7836SJohn.Forte@Sun.COM 		 */
957*7836SJohn.Forte@Sun.COM 		fptr->fcip_tq = taskq_create("fcip_tasks",
958*7836SJohn.Forte@Sun.COM 		    FCIP_NUM_THREADS, MINCLSYSPRI, FCIP_MIN_TASKS,
959*7836SJohn.Forte@Sun.COM 		    FCIP_MAX_TASKS, TASKQ_PREPOPULATE);
960*7836SJohn.Forte@Sun.COM 
961*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
962*7836SJohn.Forte@Sun.COM 
963*7836SJohn.Forte@Sun.COM 		/*
964*7836SJohn.Forte@Sun.COM 		 * create a separate thread to handle all unsolicited
965*7836SJohn.Forte@Sun.COM 		 * callback handling. This is because unsolicited_callback
966*7836SJohn.Forte@Sun.COM 		 * can happen from an interrupt context and the upstream
967*7836SJohn.Forte@Sun.COM 		 * modules can put new messages right back in the same
968*7836SJohn.Forte@Sun.COM 		 * thread context. This usually works fine, but sometimes
969*7836SJohn.Forte@Sun.COM 		 * we may have to block to obtain the dest struct entries
970*7836SJohn.Forte@Sun.COM 		 * for some remote ports.
971*7836SJohn.Forte@Sun.COM 		 */
972*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_sendup_mutex);
973*7836SJohn.Forte@Sun.COM 		if (thread_create(NULL, DEFAULTSTKSZ,
974*7836SJohn.Forte@Sun.COM 		    (void (*)())fcip_sendup_thr, (caddr_t)fptr, 0, &p0,
975*7836SJohn.Forte@Sun.COM 		    TS_RUN, minclsyspri) == NULL) {
976*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_sendup_mutex);
977*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN,
978*7836SJohn.Forte@Sun.COM 			    "!unable to create fcip sendup thread for "
979*7836SJohn.Forte@Sun.COM 			    " instance: 0x%x", instance);
980*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
981*7836SJohn.Forte@Sun.COM 			goto done;
982*7836SJohn.Forte@Sun.COM 		}
983*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_thr_initted = 1;
984*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_head = fptr->fcip_sendup_tail = NULL;
985*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_sendup_mutex);
986*7836SJohn.Forte@Sun.COM 
987*7836SJohn.Forte@Sun.COM 
988*7836SJohn.Forte@Sun.COM 		/* Let the attach handler do the rest */
989*7836SJohn.Forte@Sun.COM 		if (fcip_port_attach_handler(fptr) != FC_SUCCESS) {
990*7836SJohn.Forte@Sun.COM 			/*
991*7836SJohn.Forte@Sun.COM 			 * We have already cleaned up so return
992*7836SJohn.Forte@Sun.COM 			 */
993*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
994*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "!fcip(%d): port attach failed",
995*7836SJohn.Forte@Sun.COM 			    instance);
996*7836SJohn.Forte@Sun.COM 			goto done;
997*7836SJohn.Forte@Sun.COM 		}
998*7836SJohn.Forte@Sun.COM 
999*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_CONT,
1000*7836SJohn.Forte@Sun.COM 		    "!fcip attach for port instance (0x%x) successful",
1001*7836SJohn.Forte@Sun.COM 		    instance));
1002*7836SJohn.Forte@Sun.COM 
1003*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
1004*7836SJohn.Forte@Sun.COM 		goto done;
1005*7836SJohn.Forte@Sun.COM 	}
1006*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
1007*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
1008*7836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
1009*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1010*7836SJohn.Forte@Sun.COM 		fport = fcip_port_head;
1011*7836SJohn.Forte@Sun.COM 		while (fport != NULL) {
1012*7836SJohn.Forte@Sun.COM 			if (fport->fcipp_handle == port_info->port_handle) {
1013*7836SJohn.Forte@Sun.COM 				break;
1014*7836SJohn.Forte@Sun.COM 			}
1015*7836SJohn.Forte@Sun.COM 			fport = fport->fcipp_next;
1016*7836SJohn.Forte@Sun.COM 		}
1017*7836SJohn.Forte@Sun.COM 		if (fport == NULL) {
1018*7836SJohn.Forte@Sun.COM 			rval = FC_SUCCESS;
1019*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1020*7836SJohn.Forte@Sun.COM 			goto done;
1021*7836SJohn.Forte@Sun.COM 		}
1022*7836SJohn.Forte@Sun.COM 		rval = fcip_handle_resume(fport, port_info, cmd);
1023*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1024*7836SJohn.Forte@Sun.COM 		goto done;
1025*7836SJohn.Forte@Sun.COM 
1026*7836SJohn.Forte@Sun.COM 	default:
1027*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_2((fcip_port_attach, "fcip io", /* CSTYLED */,
1028*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "unknown command type",
1029*7836SJohn.Forte@Sun.COM 			tnf_uint, cmd, cmd));
1030*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_WARN,
1031*7836SJohn.Forte@Sun.COM 		    "unknown cmd type 0x%x in port_attach", cmd));
1032*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
1033*7836SJohn.Forte@Sun.COM 		goto done;
1034*7836SJohn.Forte@Sun.COM 	}
1035*7836SJohn.Forte@Sun.COM 
1036*7836SJohn.Forte@Sun.COM failure:
1037*7836SJohn.Forte@Sun.COM 	if (fport) {
1038*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1039*7836SJohn.Forte@Sun.COM 		fcip_num_attaching--;
1040*7836SJohn.Forte@Sun.COM 		ASSERT(fcip_num_attaching >= 0);
1041*7836SJohn.Forte@Sun.COM 		(void) fcip_softstate_free(fport);
1042*7836SJohn.Forte@Sun.COM 		fcip_port_attach_pending = 0;
1043*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1044*7836SJohn.Forte@Sun.COM 	}
1045*7836SJohn.Forte@Sun.COM 	return (rval);
1046*7836SJohn.Forte@Sun.COM 
1047*7836SJohn.Forte@Sun.COM done:
1048*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
1049*7836SJohn.Forte@Sun.COM 	fcip_port_attach_pending = 0;
1050*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
1051*7836SJohn.Forte@Sun.COM 	return (rval);
1052*7836SJohn.Forte@Sun.COM }
1053*7836SJohn.Forte@Sun.COM 
1054*7836SJohn.Forte@Sun.COM /*
1055*7836SJohn.Forte@Sun.COM  * fcip_port_attach_handler : Completes the port attach operation after
1056*7836SJohn.Forte@Sun.COM  * the ulp_port_attach routine has completed its ground work. The job
1057*7836SJohn.Forte@Sun.COM  * of this function among other things is to obtain and handle topology
1058*7836SJohn.Forte@Sun.COM  * specifics, initialize a port, setup broadcast address entries in
1059*7836SJohn.Forte@Sun.COM  * the fcip tables etc. This routine cleans up behind itself on failures.
1060*7836SJohn.Forte@Sun.COM  * Returns FC_SUCCESS or FC_FAILURE.
1061*7836SJohn.Forte@Sun.COM  */
1062*7836SJohn.Forte@Sun.COM static int
fcip_port_attach_handler(struct fcip * fptr)1063*7836SJohn.Forte@Sun.COM fcip_port_attach_handler(struct fcip *fptr)
1064*7836SJohn.Forte@Sun.COM {
1065*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport = fptr->fcip_port_info;
1066*7836SJohn.Forte@Sun.COM 	int				rval = FC_FAILURE;
1067*7836SJohn.Forte@Sun.COM 
1068*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
1069*7836SJohn.Forte@Sun.COM 
1070*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
1071*7836SJohn.Forte@Sun.COM 
1072*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_NOTE,
1073*7836SJohn.Forte@Sun.COM 	    "fcip module dip: %p instance: %d",
1074*7836SJohn.Forte@Sun.COM 	    (void *)fcip_module_dip, ddi_get_instance(fptr->fcip_dip)));
1075*7836SJohn.Forte@Sun.COM 
1076*7836SJohn.Forte@Sun.COM 	if (fcip_module_dip == NULL) {
1077*7836SJohn.Forte@Sun.COM 		clock_t		fcip_lbolt;
1078*7836SJohn.Forte@Sun.COM 
1079*7836SJohn.Forte@Sun.COM 		fcip_lbolt = ddi_get_lbolt();
1080*7836SJohn.Forte@Sun.COM 		/*
1081*7836SJohn.Forte@Sun.COM 		 * we need to use the fcip devinfo for creating
1082*7836SJohn.Forte@Sun.COM 		 * the clone device node, but the fcip attach
1083*7836SJohn.Forte@Sun.COM 		 * (from its conf file entry claiming to be a
1084*7836SJohn.Forte@Sun.COM 		 * child of pseudo) may not have happened yet.
1085*7836SJohn.Forte@Sun.COM 		 * wait here for 10 seconds and fail port attach
1086*7836SJohn.Forte@Sun.COM 		 * if the fcip devinfo is not attached yet
1087*7836SJohn.Forte@Sun.COM 		 */
1088*7836SJohn.Forte@Sun.COM 		fcip_lbolt += drv_usectohz(FCIP_INIT_DELAY);
1089*7836SJohn.Forte@Sun.COM 
1090*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH,
1091*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "cv_timedwait lbolt %lx", fcip_lbolt));
1092*7836SJohn.Forte@Sun.COM 
1093*7836SJohn.Forte@Sun.COM 		(void) cv_timedwait(&fcip_global_cv, &fcip_global_mutex,
1094*7836SJohn.Forte@Sun.COM 		    fcip_lbolt);
1095*7836SJohn.Forte@Sun.COM 
1096*7836SJohn.Forte@Sun.COM 		if (fcip_module_dip == NULL) {
1097*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1098*7836SJohn.Forte@Sun.COM 
1099*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_WARN,
1100*7836SJohn.Forte@Sun.COM 				"fcip attach did not happen"));
1101*7836SJohn.Forte@Sun.COM 			goto port_attach_cleanup;
1102*7836SJohn.Forte@Sun.COM 		}
1103*7836SJohn.Forte@Sun.COM 	}
1104*7836SJohn.Forte@Sun.COM 
1105*7836SJohn.Forte@Sun.COM 	if ((!fcip_minor_node_created) &&
1106*7836SJohn.Forte@Sun.COM 	    fcip_is_supported_fc_topology(fport->fcipp_topology)) {
1107*7836SJohn.Forte@Sun.COM 		/*
1108*7836SJohn.Forte@Sun.COM 		 * Checking for same topologies which are considered valid
1109*7836SJohn.Forte@Sun.COM 		 * by fcip_handle_topology(). Dont create a minor node if
1110*7836SJohn.Forte@Sun.COM 		 * nothing is hanging off the FC port.
1111*7836SJohn.Forte@Sun.COM 		 */
1112*7836SJohn.Forte@Sun.COM 		if (ddi_create_minor_node(fcip_module_dip, "fcip", S_IFCHR,
1113*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(fptr->fcip_dip), DDI_PSEUDO,
1114*7836SJohn.Forte@Sun.COM 		    CLONE_DEV) == DDI_FAILURE) {
1115*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1116*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_WARN,
1117*7836SJohn.Forte@Sun.COM 			    "failed to create minor node for fcip(%d)",
1118*7836SJohn.Forte@Sun.COM 			    ddi_get_instance(fptr->fcip_dip)));
1119*7836SJohn.Forte@Sun.COM 			goto port_attach_cleanup;
1120*7836SJohn.Forte@Sun.COM 		}
1121*7836SJohn.Forte@Sun.COM 		fcip_minor_node_created++;
1122*7836SJohn.Forte@Sun.COM 	}
1123*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
1124*7836SJohn.Forte@Sun.COM 
1125*7836SJohn.Forte@Sun.COM 	/*
1126*7836SJohn.Forte@Sun.COM 	 * initialize port for traffic
1127*7836SJohn.Forte@Sun.COM 	 */
1128*7836SJohn.Forte@Sun.COM 	if (fcip_init_port(fptr) != FC_SUCCESS) {
1129*7836SJohn.Forte@Sun.COM 		/* fcip_init_port has already cleaned up its stuff */
1130*7836SJohn.Forte@Sun.COM 
1131*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1132*7836SJohn.Forte@Sun.COM 
1133*7836SJohn.Forte@Sun.COM 		if ((fcip_num_instances == 1) &&
1134*7836SJohn.Forte@Sun.COM 		    (fcip_minor_node_created == 1)) {
1135*7836SJohn.Forte@Sun.COM 			/* Remove minor node iff this is the last instance */
1136*7836SJohn.Forte@Sun.COM 			ddi_remove_minor_node(fcip_module_dip, NULL);
1137*7836SJohn.Forte@Sun.COM 		}
1138*7836SJohn.Forte@Sun.COM 
1139*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1140*7836SJohn.Forte@Sun.COM 
1141*7836SJohn.Forte@Sun.COM 		goto port_attach_cleanup;
1142*7836SJohn.Forte@Sun.COM 	}
1143*7836SJohn.Forte@Sun.COM 
1144*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
1145*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~FCIP_ATTACHING;
1146*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags |= FCIP_INITED;
1147*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_ticks = 0;
1148*7836SJohn.Forte@Sun.COM 
1149*7836SJohn.Forte@Sun.COM 	/*
1150*7836SJohn.Forte@Sun.COM 	 * start the timeout threads
1151*7836SJohn.Forte@Sun.COM 	 */
1152*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_id = timeout(fcip_timeout, fptr,
1153*7836SJohn.Forte@Sun.COM 	    drv_usectohz(1000000));
1154*7836SJohn.Forte@Sun.COM 
1155*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
1156*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
1157*7836SJohn.Forte@Sun.COM 	fcip_num_attaching--;
1158*7836SJohn.Forte@Sun.COM 	ASSERT(fcip_num_attaching >= 0);
1159*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
1160*7836SJohn.Forte@Sun.COM 	rval = FC_SUCCESS;
1161*7836SJohn.Forte@Sun.COM 	return (rval);
1162*7836SJohn.Forte@Sun.COM 
1163*7836SJohn.Forte@Sun.COM port_attach_cleanup:
1164*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
1165*7836SJohn.Forte@Sun.COM 	(void) fcip_softstate_free(fport);
1166*7836SJohn.Forte@Sun.COM 	fcip_num_attaching--;
1167*7836SJohn.Forte@Sun.COM 	ASSERT(fcip_num_attaching >= 0);
1168*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
1169*7836SJohn.Forte@Sun.COM 	rval = FC_FAILURE;
1170*7836SJohn.Forte@Sun.COM 	return (rval);
1171*7836SJohn.Forte@Sun.COM }
1172*7836SJohn.Forte@Sun.COM 
1173*7836SJohn.Forte@Sun.COM 
1174*7836SJohn.Forte@Sun.COM /*
1175*7836SJohn.Forte@Sun.COM  * Handler for DDI_RESUME operations. Port must be ready to restart IP
1176*7836SJohn.Forte@Sun.COM  * traffic on resume
1177*7836SJohn.Forte@Sun.COM  */
1178*7836SJohn.Forte@Sun.COM static int
fcip_handle_resume(fcip_port_info_t * fport,fc_ulp_port_info_t * port_info,fc_attach_cmd_t cmd)1179*7836SJohn.Forte@Sun.COM fcip_handle_resume(fcip_port_info_t *fport, fc_ulp_port_info_t *port_info,
1180*7836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd)
1181*7836SJohn.Forte@Sun.COM {
1182*7836SJohn.Forte@Sun.COM 	int 		rval = FC_SUCCESS;
1183*7836SJohn.Forte@Sun.COM 	struct fcip	*fptr = fport->fcipp_fcip;
1184*7836SJohn.Forte@Sun.COM 	struct fcipstr	*tslp;
1185*7836SJohn.Forte@Sun.COM 	int		index;
1186*7836SJohn.Forte@Sun.COM 
1187*7836SJohn.Forte@Sun.COM 
1188*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
1189*7836SJohn.Forte@Sun.COM 
1190*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
1191*7836SJohn.Forte@Sun.COM 
1192*7836SJohn.Forte@Sun.COM 	if (cmd == FC_CMD_POWER_UP) {
1193*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags &= ~(FCIP_POWER_DOWN);
1194*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_flags & FCIP_SUSPENDED) {
1195*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
1196*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
1197*7836SJohn.Forte@Sun.COM 		}
1198*7836SJohn.Forte@Sun.COM 	} else if (cmd == FC_CMD_RESUME) {
1199*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags &= ~(FCIP_SUSPENDED);
1200*7836SJohn.Forte@Sun.COM 	} else {
1201*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
1202*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
1203*7836SJohn.Forte@Sun.COM 	}
1204*7836SJohn.Forte@Sun.COM 
1205*7836SJohn.Forte@Sun.COM 	/*
1206*7836SJohn.Forte@Sun.COM 	 * set the current port state and topology
1207*7836SJohn.Forte@Sun.COM 	 */
1208*7836SJohn.Forte@Sun.COM 	fport->fcipp_topology = port_info->port_flags;
1209*7836SJohn.Forte@Sun.COM 	fport->fcipp_pstate = port_info->port_state;
1210*7836SJohn.Forte@Sun.COM 
1211*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_READER);
1212*7836SJohn.Forte@Sun.COM 	for (tslp = fcipstrup; tslp; tslp = tslp->sl_nextp) {
1213*7836SJohn.Forte@Sun.COM 		if (tslp->sl_fcip == fptr) {
1214*7836SJohn.Forte@Sun.COM 			break;
1215*7836SJohn.Forte@Sun.COM 		}
1216*7836SJohn.Forte@Sun.COM 	}
1217*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
1218*7836SJohn.Forte@Sun.COM 
1219*7836SJohn.Forte@Sun.COM 	/*
1220*7836SJohn.Forte@Sun.COM 	 * No active streams on this port
1221*7836SJohn.Forte@Sun.COM 	 */
1222*7836SJohn.Forte@Sun.COM 	if (tslp == NULL) {
1223*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
1224*7836SJohn.Forte@Sun.COM 		goto done;
1225*7836SJohn.Forte@Sun.COM 	}
1226*7836SJohn.Forte@Sun.COM 
1227*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
1228*7836SJohn.Forte@Sun.COM 	for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
1229*7836SJohn.Forte@Sun.COM 		struct fcip_routing_table 	*frp;
1230*7836SJohn.Forte@Sun.COM 
1231*7836SJohn.Forte@Sun.COM 		frp = fptr->fcip_rtable[index];
1232*7836SJohn.Forte@Sun.COM 		while (frp) {
1233*7836SJohn.Forte@Sun.COM 			uint32_t		did;
1234*7836SJohn.Forte@Sun.COM 			/*
1235*7836SJohn.Forte@Sun.COM 			 * Mark the broadcast RTE available again. It
1236*7836SJohn.Forte@Sun.COM 			 * was marked SUSPENDED during SUSPEND.
1237*7836SJohn.Forte@Sun.COM 			 */
1238*7836SJohn.Forte@Sun.COM 			did = fcip_get_broadcast_did(fptr);
1239*7836SJohn.Forte@Sun.COM 			if (frp->fcipr_d_id.port_id == did) {
1240*7836SJohn.Forte@Sun.COM 				frp->fcipr_state = 0;
1241*7836SJohn.Forte@Sun.COM 				index = FCIP_RT_HASH_ELEMS;
1242*7836SJohn.Forte@Sun.COM 				break;
1243*7836SJohn.Forte@Sun.COM 			}
1244*7836SJohn.Forte@Sun.COM 			frp = frp->fcipr_next;
1245*7836SJohn.Forte@Sun.COM 		}
1246*7836SJohn.Forte@Sun.COM 	}
1247*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
1248*7836SJohn.Forte@Sun.COM 
1249*7836SJohn.Forte@Sun.COM 	/*
1250*7836SJohn.Forte@Sun.COM 	 * fcip_handle_topology will update the port entries in the
1251*7836SJohn.Forte@Sun.COM 	 * routing table.
1252*7836SJohn.Forte@Sun.COM 	 * fcip_handle_topology also takes care of resetting the
1253*7836SJohn.Forte@Sun.COM 	 * fcipr_state field in the routing table structure. The entries
1254*7836SJohn.Forte@Sun.COM 	 * were set to RT_INVALID during suspend.
1255*7836SJohn.Forte@Sun.COM 	 */
1256*7836SJohn.Forte@Sun.COM 	fcip_handle_topology(fptr);
1257*7836SJohn.Forte@Sun.COM 
1258*7836SJohn.Forte@Sun.COM done:
1259*7836SJohn.Forte@Sun.COM 	/*
1260*7836SJohn.Forte@Sun.COM 	 * Restart the timeout thread
1261*7836SJohn.Forte@Sun.COM 	 */
1262*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_id = timeout(fcip_timeout, fptr,
1263*7836SJohn.Forte@Sun.COM 	    drv_usectohz(1000000));
1264*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
1265*7836SJohn.Forte@Sun.COM 	return (rval);
1266*7836SJohn.Forte@Sun.COM }
1267*7836SJohn.Forte@Sun.COM 
1268*7836SJohn.Forte@Sun.COM 
1269*7836SJohn.Forte@Sun.COM /*
1270*7836SJohn.Forte@Sun.COM  * Insert a destination port entry into the routing table for
1271*7836SJohn.Forte@Sun.COM  * this port
1272*7836SJohn.Forte@Sun.COM  */
1273*7836SJohn.Forte@Sun.COM static void
fcip_rt_update(struct fcip * fptr,fc_portmap_t * devlist,uint32_t listlen)1274*7836SJohn.Forte@Sun.COM fcip_rt_update(struct fcip *fptr, fc_portmap_t *devlist, uint32_t listlen)
1275*7836SJohn.Forte@Sun.COM {
1276*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table	*frp;
1277*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport = fptr->fcip_port_info;
1278*7836SJohn.Forte@Sun.COM 	int				hash_bucket, i;
1279*7836SJohn.Forte@Sun.COM 	fc_portmap_t			*pmap;
1280*7836SJohn.Forte@Sun.COM 	char				wwn_buf[20];
1281*7836SJohn.Forte@Sun.COM 
1282*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_rt_update, "fcip io", /* CSTYLED */,
1283*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter",
1284*7836SJohn.Forte@Sun.COM 		tnf_int, listlen, listlen));
1285*7836SJohn.Forte@Sun.COM 
1286*7836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&fptr->fcip_mutex));
1287*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
1288*7836SJohn.Forte@Sun.COM 
1289*7836SJohn.Forte@Sun.COM 	for (i = 0; i < listlen; i++) {
1290*7836SJohn.Forte@Sun.COM 		pmap = &(devlist[i]);
1291*7836SJohn.Forte@Sun.COM 
1292*7836SJohn.Forte@Sun.COM 		frp = fcip_lookup_rtable(fptr, &(pmap->map_pwwn),
1293*7836SJohn.Forte@Sun.COM 		    FCIP_COMPARE_PWWN);
1294*7836SJohn.Forte@Sun.COM 		/*
1295*7836SJohn.Forte@Sun.COM 		 * If an entry for a port in the devlist exists in the
1296*7836SJohn.Forte@Sun.COM 		 * in the per port routing table, make sure the data
1297*7836SJohn.Forte@Sun.COM 		 * is current. We need to do this irrespective of the
1298*7836SJohn.Forte@Sun.COM 		 * underlying port topology.
1299*7836SJohn.Forte@Sun.COM 		 */
1300*7836SJohn.Forte@Sun.COM 		switch (pmap->map_type) {
1301*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
1302*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_NOCHANGE:
1303*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
1304*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_USER_LOGIN:
1305*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
1306*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_CHANGED:
1307*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
1308*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_NEW:
1309*7836SJohn.Forte@Sun.COM 			if (frp == NULL) {
1310*7836SJohn.Forte@Sun.COM 				goto add_new_entry;
1311*7836SJohn.Forte@Sun.COM 			} else if (frp) {
1312*7836SJohn.Forte@Sun.COM 				goto update_entry;
1313*7836SJohn.Forte@Sun.COM 			} else {
1314*7836SJohn.Forte@Sun.COM 				continue;
1315*7836SJohn.Forte@Sun.COM 			}
1316*7836SJohn.Forte@Sun.COM 
1317*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_OLD:
1318*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
1319*7836SJohn.Forte@Sun.COM 		case PORT_DEVICE_USER_LOGOUT:
1320*7836SJohn.Forte@Sun.COM 			/*
1321*7836SJohn.Forte@Sun.COM 			 * Mark entry for removal from Routing Table if
1322*7836SJohn.Forte@Sun.COM 			 * one exists. Let the timeout thread actually
1323*7836SJohn.Forte@Sun.COM 			 * remove the entry after we've given up hopes
1324*7836SJohn.Forte@Sun.COM 			 * of the port ever showing up.
1325*7836SJohn.Forte@Sun.COM 			 */
1326*7836SJohn.Forte@Sun.COM 			if (frp) {
1327*7836SJohn.Forte@Sun.COM 				uint32_t		did;
1328*7836SJohn.Forte@Sun.COM 
1329*7836SJohn.Forte@Sun.COM 				/*
1330*7836SJohn.Forte@Sun.COM 				 * Mark the routing table as invalid to bail
1331*7836SJohn.Forte@Sun.COM 				 * the packets early that are in transit
1332*7836SJohn.Forte@Sun.COM 				 */
1333*7836SJohn.Forte@Sun.COM 				did = fptr->fcip_broadcast_did;
1334*7836SJohn.Forte@Sun.COM 				if (frp->fcipr_d_id.port_id != did) {
1335*7836SJohn.Forte@Sun.COM 					frp->fcipr_pd = NULL;
1336*7836SJohn.Forte@Sun.COM 					frp->fcipr_state = FCIP_RT_INVALID;
1337*7836SJohn.Forte@Sun.COM 					frp->fcipr_invalid_timeout =
1338*7836SJohn.Forte@Sun.COM 					    fptr->fcip_timeout_ticks +
1339*7836SJohn.Forte@Sun.COM 					    FCIP_RTE_TIMEOUT;
1340*7836SJohn.Forte@Sun.COM 				}
1341*7836SJohn.Forte@Sun.COM 			}
1342*7836SJohn.Forte@Sun.COM 			continue;
1343*7836SJohn.Forte@Sun.COM 
1344*7836SJohn.Forte@Sun.COM 		default:
1345*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_WARN,
1346*7836SJohn.Forte@Sun.COM 			    "unknown map flags in rt_update"));
1347*7836SJohn.Forte@Sun.COM 			continue;
1348*7836SJohn.Forte@Sun.COM 		}
1349*7836SJohn.Forte@Sun.COM add_new_entry:
1350*7836SJohn.Forte@Sun.COM 		ASSERT(frp == NULL);
1351*7836SJohn.Forte@Sun.COM 		hash_bucket = FCIP_RT_HASH(pmap->map_pwwn.raw_wwn);
1352*7836SJohn.Forte@Sun.COM 
1353*7836SJohn.Forte@Sun.COM 		ASSERT(hash_bucket < FCIP_RT_HASH_ELEMS);
1354*7836SJohn.Forte@Sun.COM 
1355*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_2((fcip_rt_update, "cfip io", /* CSTYLED */,
1356*7836SJohn.Forte@Sun.COM 			tnf_string, msg,
1357*7836SJohn.Forte@Sun.COM 			"add new entry",
1358*7836SJohn.Forte@Sun.COM 			tnf_int, hashbucket, hash_bucket));
1359*7836SJohn.Forte@Sun.COM 
1360*7836SJohn.Forte@Sun.COM 		frp = (struct fcip_routing_table *)
1361*7836SJohn.Forte@Sun.COM 		    kmem_zalloc(sizeof (struct fcip_routing_table), KM_SLEEP);
1362*7836SJohn.Forte@Sun.COM 		/* insert at beginning of hash bucket */
1363*7836SJohn.Forte@Sun.COM 		frp->fcipr_next = fptr->fcip_rtable[hash_bucket];
1364*7836SJohn.Forte@Sun.COM 		fptr->fcip_rtable[hash_bucket] = frp;
1365*7836SJohn.Forte@Sun.COM 		fc_wwn_to_str(&pmap->map_pwwn, wwn_buf);
1366*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH, (CE_NOTE,
1367*7836SJohn.Forte@Sun.COM 		    "added entry for pwwn %s and d_id 0x%x",
1368*7836SJohn.Forte@Sun.COM 		    wwn_buf, pmap->map_did.port_id));
1369*7836SJohn.Forte@Sun.COM update_entry:
1370*7836SJohn.Forte@Sun.COM 		bcopy((void *)&pmap->map_pwwn,
1371*7836SJohn.Forte@Sun.COM 		    (void *)&frp->fcipr_pwwn, sizeof (la_wwn_t));
1372*7836SJohn.Forte@Sun.COM 		bcopy((void *)&pmap->map_nwwn, (void *)&frp->fcipr_nwwn,
1373*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
1374*7836SJohn.Forte@Sun.COM 		frp->fcipr_d_id = pmap->map_did;
1375*7836SJohn.Forte@Sun.COM 		frp->fcipr_state = pmap->map_state;
1376*7836SJohn.Forte@Sun.COM 		frp->fcipr_pd = pmap->map_pd;
1377*7836SJohn.Forte@Sun.COM 
1378*7836SJohn.Forte@Sun.COM 		/*
1379*7836SJohn.Forte@Sun.COM 		 * If there is no pd for a destination port that is not
1380*7836SJohn.Forte@Sun.COM 		 * a broadcast entry, the port is pretty much unusable - so
1381*7836SJohn.Forte@Sun.COM 		 * mark the port for removal so we can try adding back the
1382*7836SJohn.Forte@Sun.COM 		 * entry again.
1383*7836SJohn.Forte@Sun.COM 		 */
1384*7836SJohn.Forte@Sun.COM 		if ((frp->fcipr_pd == NULL) &&
1385*7836SJohn.Forte@Sun.COM 		    (frp->fcipr_d_id.port_id != fptr->fcip_broadcast_did)) {
1386*7836SJohn.Forte@Sun.COM 			frp->fcipr_state = PORT_DEVICE_INVALID;
1387*7836SJohn.Forte@Sun.COM 			frp->fcipr_invalid_timeout = fptr->fcip_timeout_ticks +
1388*7836SJohn.Forte@Sun.COM 			    (FCIP_RTE_TIMEOUT / 2);
1389*7836SJohn.Forte@Sun.COM 		}
1390*7836SJohn.Forte@Sun.COM 		frp->fcipr_fca_dev =
1391*7836SJohn.Forte@Sun.COM 		    fc_ulp_get_fca_device(fport->fcipp_handle, pmap->map_did);
1392*7836SJohn.Forte@Sun.COM 
1393*7836SJohn.Forte@Sun.COM 		/*
1394*7836SJohn.Forte@Sun.COM 		 * login to the remote port. Don't worry about
1395*7836SJohn.Forte@Sun.COM 		 * plogi failures for now
1396*7836SJohn.Forte@Sun.COM 		 */
1397*7836SJohn.Forte@Sun.COM 		if (pmap->map_pd != NULL) {
1398*7836SJohn.Forte@Sun.COM 			(void) fcip_do_plogi(fptr, frp);
1399*7836SJohn.Forte@Sun.COM 		} else if (FC_TOP_EXTERNAL(fport->fcipp_topology)) {
1400*7836SJohn.Forte@Sun.COM 			fc_wwn_to_str(&frp->fcipr_pwwn, wwn_buf);
1401*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_MISC, (CE_NOTE,
1402*7836SJohn.Forte@Sun.COM 			    "logging into pwwn %s, d_id 0x%x",
1403*7836SJohn.Forte@Sun.COM 			    wwn_buf, frp->fcipr_d_id.port_id));
1404*7836SJohn.Forte@Sun.COM 			(void) fcip_do_plogi(fptr, frp);
1405*7836SJohn.Forte@Sun.COM 		}
1406*7836SJohn.Forte@Sun.COM 
1407*7836SJohn.Forte@Sun.COM 		FCIP_TNF_BYTE_ARRAY(fcip_rt_update, "fcip io", "detail",
1408*7836SJohn.Forte@Sun.COM 			"new wwn in rt", pwwn,
1409*7836SJohn.Forte@Sun.COM 			&frp->fcipr_pwwn, sizeof (la_wwn_t));
1410*7836SJohn.Forte@Sun.COM 	}
1411*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
1412*7836SJohn.Forte@Sun.COM }
1413*7836SJohn.Forte@Sun.COM 
1414*7836SJohn.Forte@Sun.COM 
1415*7836SJohn.Forte@Sun.COM /*
1416*7836SJohn.Forte@Sun.COM  * return a matching routing table entry for a given fcip instance
1417*7836SJohn.Forte@Sun.COM  */
1418*7836SJohn.Forte@Sun.COM struct fcip_routing_table *
fcip_lookup_rtable(struct fcip * fptr,la_wwn_t * wwn,int matchflag)1419*7836SJohn.Forte@Sun.COM fcip_lookup_rtable(struct fcip *fptr, la_wwn_t *wwn, int matchflag)
1420*7836SJohn.Forte@Sun.COM {
1421*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table	*frp = NULL;
1422*7836SJohn.Forte@Sun.COM 	int				hash_bucket;
1423*7836SJohn.Forte@Sun.COM 
1424*7836SJohn.Forte@Sun.COM 
1425*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_lookup_rtable, "fcip io", /* CSTYLED */,
1426*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
1427*7836SJohn.Forte@Sun.COM 	FCIP_TNF_BYTE_ARRAY(fcip_lookup_rtable, "fcip io", "detail",
1428*7836SJohn.Forte@Sun.COM 		"rtable lookup for", wwn,
1429*7836SJohn.Forte@Sun.COM 		&wwn->raw_wwn, sizeof (la_wwn_t));
1430*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_lookup_rtable, "fcip io", /* CSTYLED */,
1431*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "match by",
1432*7836SJohn.Forte@Sun.COM 		tnf_int, matchflag, matchflag));
1433*7836SJohn.Forte@Sun.COM 
1434*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_rt_mutex));
1435*7836SJohn.Forte@Sun.COM 
1436*7836SJohn.Forte@Sun.COM 	hash_bucket = FCIP_RT_HASH(wwn->raw_wwn);
1437*7836SJohn.Forte@Sun.COM 	frp = fptr->fcip_rtable[hash_bucket];
1438*7836SJohn.Forte@Sun.COM 	while (frp != NULL) {
1439*7836SJohn.Forte@Sun.COM 
1440*7836SJohn.Forte@Sun.COM 		FCIP_TNF_BYTE_ARRAY(fcip_lookup_rtable, "fcip io", "detail",
1441*7836SJohn.Forte@Sun.COM 			"rtable entry", nwwn,
1442*7836SJohn.Forte@Sun.COM 			&(frp->fcipr_nwwn.raw_wwn), sizeof (la_wwn_t));
1443*7836SJohn.Forte@Sun.COM 
1444*7836SJohn.Forte@Sun.COM 		if (fcip_wwn_compare(&frp->fcipr_pwwn, wwn, matchflag) == 0) {
1445*7836SJohn.Forte@Sun.COM 			break;
1446*7836SJohn.Forte@Sun.COM 		}
1447*7836SJohn.Forte@Sun.COM 
1448*7836SJohn.Forte@Sun.COM 		frp = frp->fcipr_next;
1449*7836SJohn.Forte@Sun.COM 	}
1450*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_lookup_rtable, "fcip io", /* CSTYLED */,
1451*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "lookup result",
1452*7836SJohn.Forte@Sun.COM 		tnf_opaque, frp, frp));
1453*7836SJohn.Forte@Sun.COM 	return (frp);
1454*7836SJohn.Forte@Sun.COM }
1455*7836SJohn.Forte@Sun.COM 
1456*7836SJohn.Forte@Sun.COM /*
1457*7836SJohn.Forte@Sun.COM  * Attach of fcip under pseudo. The actual setup of the interface
1458*7836SJohn.Forte@Sun.COM  * actually happens in fcip_port_attach on a callback from the
1459*7836SJohn.Forte@Sun.COM  * transport. The port_attach callback however can proceed only
1460*7836SJohn.Forte@Sun.COM  * after the devinfo for fcip has been created under pseudo
1461*7836SJohn.Forte@Sun.COM  */
1462*7836SJohn.Forte@Sun.COM static int
fcip_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1463*7836SJohn.Forte@Sun.COM fcip_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1464*7836SJohn.Forte@Sun.COM {
1465*7836SJohn.Forte@Sun.COM 	switch ((int)cmd) {
1466*7836SJohn.Forte@Sun.COM 
1467*7836SJohn.Forte@Sun.COM 	case DDI_ATTACH: {
1468*7836SJohn.Forte@Sun.COM 		ASSERT(fcip_module_dip == NULL);
1469*7836SJohn.Forte@Sun.COM 		fcip_module_dip = dip;
1470*7836SJohn.Forte@Sun.COM 
1471*7836SJohn.Forte@Sun.COM 		/*
1472*7836SJohn.Forte@Sun.COM 		 * this call originates as a result of fcip's conf
1473*7836SJohn.Forte@Sun.COM 		 * file entry and will result in a fcip instance being
1474*7836SJohn.Forte@Sun.COM 		 * a child of pseudo. We should ensure here that the port
1475*7836SJohn.Forte@Sun.COM 		 * driver (fp) has been loaded and initted since we would
1476*7836SJohn.Forte@Sun.COM 		 * never get a port attach callback without fp being loaded.
1477*7836SJohn.Forte@Sun.COM 		 * If we are unable to succesfully load and initalize fp -
1478*7836SJohn.Forte@Sun.COM 		 * just fail this attach.
1479*7836SJohn.Forte@Sun.COM 		 */
1480*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1481*7836SJohn.Forte@Sun.COM 
1482*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH,
1483*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "global cv - signaling"));
1484*7836SJohn.Forte@Sun.COM 
1485*7836SJohn.Forte@Sun.COM 		cv_signal(&fcip_global_cv);
1486*7836SJohn.Forte@Sun.COM 
1487*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ATTACH,
1488*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "global cv - signaled"));
1489*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1490*7836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1491*7836SJohn.Forte@Sun.COM 	}
1492*7836SJohn.Forte@Sun.COM 	case DDI_RESUME:
1493*7836SJohn.Forte@Sun.COM 		/*
1494*7836SJohn.Forte@Sun.COM 		 * Resume appears trickier
1495*7836SJohn.Forte@Sun.COM 		 */
1496*7836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1497*7836SJohn.Forte@Sun.COM 	default:
1498*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
1499*7836SJohn.Forte@Sun.COM 	}
1500*7836SJohn.Forte@Sun.COM }
1501*7836SJohn.Forte@Sun.COM 
1502*7836SJohn.Forte@Sun.COM 
1503*7836SJohn.Forte@Sun.COM /*
1504*7836SJohn.Forte@Sun.COM  * The detach entry point to permit unloading fcip. We make sure
1505*7836SJohn.Forte@Sun.COM  * there are no active streams before we proceed with the detach
1506*7836SJohn.Forte@Sun.COM  */
1507*7836SJohn.Forte@Sun.COM /* ARGSUSED */
1508*7836SJohn.Forte@Sun.COM static int
fcip_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1509*7836SJohn.Forte@Sun.COM fcip_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1510*7836SJohn.Forte@Sun.COM {
1511*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
1512*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
1513*7836SJohn.Forte@Sun.COM 	int			detached;
1514*7836SJohn.Forte@Sun.COM 
1515*7836SJohn.Forte@Sun.COM 	switch (cmd) {
1516*7836SJohn.Forte@Sun.COM 	case DDI_DETACH: {
1517*7836SJohn.Forte@Sun.COM 		/*
1518*7836SJohn.Forte@Sun.COM 		 * If we got here, any active streams should have been
1519*7836SJohn.Forte@Sun.COM 		 * unplumbed but check anyway
1520*7836SJohn.Forte@Sun.COM 		 */
1521*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1522*7836SJohn.Forte@Sun.COM 		if (fcipstrup != NULL) {
1523*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1524*7836SJohn.Forte@Sun.COM 			return (DDI_FAILURE);
1525*7836SJohn.Forte@Sun.COM 		}
1526*7836SJohn.Forte@Sun.COM 
1527*7836SJohn.Forte@Sun.COM 		if (fcip_port_head != NULL) {
1528*7836SJohn.Forte@Sun.COM 			/*
1529*7836SJohn.Forte@Sun.COM 			 * Check to see if we have unattached/unbound
1530*7836SJohn.Forte@Sun.COM 			 * ports. If all the ports are unattached/unbound go
1531*7836SJohn.Forte@Sun.COM 			 * ahead and unregister with the transport
1532*7836SJohn.Forte@Sun.COM 			 */
1533*7836SJohn.Forte@Sun.COM 			fport = fcip_port_head;
1534*7836SJohn.Forte@Sun.COM 			while (fport != NULL) {
1535*7836SJohn.Forte@Sun.COM 				fptr = fport->fcipp_fcip;
1536*7836SJohn.Forte@Sun.COM 				if (fptr == NULL) {
1537*7836SJohn.Forte@Sun.COM 					continue;
1538*7836SJohn.Forte@Sun.COM 				}
1539*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_mutex);
1540*7836SJohn.Forte@Sun.COM 				fptr->fcip_flags |= FCIP_DETACHING;
1541*7836SJohn.Forte@Sun.COM 				if (fptr->fcip_ipq ||
1542*7836SJohn.Forte@Sun.COM 				    fptr->fcip_flags & (FCIP_IN_TIMEOUT |
1543*7836SJohn.Forte@Sun.COM 				    FCIP_IN_CALLBACK | FCIP_ATTACHING |
1544*7836SJohn.Forte@Sun.COM 				    FCIP_SUSPENDED | FCIP_POWER_DOWN |
1545*7836SJohn.Forte@Sun.COM 				    FCIP_REG_INPROGRESS)) {
1546*7836SJohn.Forte@Sun.COM 					FCIP_TNF_PROBE_1((fcip_detach,
1547*7836SJohn.Forte@Sun.COM 					    "fcip io", /* CSTYLED */,
1548*7836SJohn.Forte@Sun.COM 					    tnf_string, msg,
1549*7836SJohn.Forte@Sun.COM 					    "fcip instance busy"));
1550*7836SJohn.Forte@Sun.COM 
1551*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
1552*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_DETACH, (CE_WARN,
1553*7836SJohn.Forte@Sun.COM 					    "fcip instance busy"));
1554*7836SJohn.Forte@Sun.COM 					break;
1555*7836SJohn.Forte@Sun.COM 				}
1556*7836SJohn.Forte@Sun.COM 				/*
1557*7836SJohn.Forte@Sun.COM 				 * Check for any outstanding pkts. If yes
1558*7836SJohn.Forte@Sun.COM 				 * fail the detach
1559*7836SJohn.Forte@Sun.COM 				 */
1560*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_dest_mutex);
1561*7836SJohn.Forte@Sun.COM 				if (fcip_port_get_num_pkts(fptr) > 0) {
1562*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_dest_mutex);
1563*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
1564*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_DETACH, (CE_WARN,
1565*7836SJohn.Forte@Sun.COM 					    "fcip instance busy - pkts "
1566*7836SJohn.Forte@Sun.COM 					    "pending"));
1567*7836SJohn.Forte@Sun.COM 					break;
1568*7836SJohn.Forte@Sun.COM 				}
1569*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_dest_mutex);
1570*7836SJohn.Forte@Sun.COM 
1571*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_rt_mutex);
1572*7836SJohn.Forte@Sun.COM 				if (fcip_plogi_in_progress(fptr)) {
1573*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_rt_mutex);
1574*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
1575*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_DETACH, (CE_WARN,
1576*7836SJohn.Forte@Sun.COM 					    "fcip instance busy - plogi in "
1577*7836SJohn.Forte@Sun.COM 					    "progress"));
1578*7836SJohn.Forte@Sun.COM 					break;
1579*7836SJohn.Forte@Sun.COM 				}
1580*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_rt_mutex);
1581*7836SJohn.Forte@Sun.COM 
1582*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_mutex);
1583*7836SJohn.Forte@Sun.COM 				fport = fport->fcipp_next;
1584*7836SJohn.Forte@Sun.COM 			}
1585*7836SJohn.Forte@Sun.COM 			/*
1586*7836SJohn.Forte@Sun.COM 			 * if fport is non NULL - we have active ports
1587*7836SJohn.Forte@Sun.COM 			 */
1588*7836SJohn.Forte@Sun.COM 			if (fport != NULL) {
1589*7836SJohn.Forte@Sun.COM 				/*
1590*7836SJohn.Forte@Sun.COM 				 * Remove the DETACHING flags on the ports
1591*7836SJohn.Forte@Sun.COM 				 */
1592*7836SJohn.Forte@Sun.COM 				fport = fcip_port_head;
1593*7836SJohn.Forte@Sun.COM 				while (fport != NULL) {
1594*7836SJohn.Forte@Sun.COM 					fptr = fport->fcipp_fcip;
1595*7836SJohn.Forte@Sun.COM 					mutex_enter(&fptr->fcip_mutex);
1596*7836SJohn.Forte@Sun.COM 					fptr->fcip_flags &= ~(FCIP_DETACHING);
1597*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
1598*7836SJohn.Forte@Sun.COM 					fport = fport->fcipp_next;
1599*7836SJohn.Forte@Sun.COM 				}
1600*7836SJohn.Forte@Sun.COM 				mutex_exit(&fcip_global_mutex);
1601*7836SJohn.Forte@Sun.COM 				return (DDI_FAILURE);
1602*7836SJohn.Forte@Sun.COM 			}
1603*7836SJohn.Forte@Sun.COM 		}
1604*7836SJohn.Forte@Sun.COM 
1605*7836SJohn.Forte@Sun.COM 		/*
1606*7836SJohn.Forte@Sun.COM 		 * free up all softstate structures
1607*7836SJohn.Forte@Sun.COM 		 */
1608*7836SJohn.Forte@Sun.COM 		fport = fcip_port_head;
1609*7836SJohn.Forte@Sun.COM 		while (fport != NULL) {
1610*7836SJohn.Forte@Sun.COM 			detached = 1;
1611*7836SJohn.Forte@Sun.COM 
1612*7836SJohn.Forte@Sun.COM 			fptr = fport->fcipp_fcip;
1613*7836SJohn.Forte@Sun.COM 			if (fptr) {
1614*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_mutex);
1615*7836SJohn.Forte@Sun.COM 				/*
1616*7836SJohn.Forte@Sun.COM 				 * Check to see if somebody beat us to the
1617*7836SJohn.Forte@Sun.COM 				 * punch
1618*7836SJohn.Forte@Sun.COM 				 */
1619*7836SJohn.Forte@Sun.COM 				detached = fptr->fcip_flags & FCIP_DETACHED;
1620*7836SJohn.Forte@Sun.COM 				fptr->fcip_flags &= ~(FCIP_DETACHING);
1621*7836SJohn.Forte@Sun.COM 				fptr->fcip_flags |= FCIP_DETACHED;
1622*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_mutex);
1623*7836SJohn.Forte@Sun.COM 			}
1624*7836SJohn.Forte@Sun.COM 
1625*7836SJohn.Forte@Sun.COM 			if (!detached) {
1626*7836SJohn.Forte@Sun.COM 				fport = fcip_softstate_free(fport);
1627*7836SJohn.Forte@Sun.COM 			} else {
1628*7836SJohn.Forte@Sun.COM 				/*
1629*7836SJohn.Forte@Sun.COM 				 * If the port was marked as detached
1630*7836SJohn.Forte@Sun.COM 				 * but it was still in the list, that
1631*7836SJohn.Forte@Sun.COM 				 * means another thread has marked it
1632*7836SJohn.Forte@Sun.COM 				 * but we got in while it released the
1633*7836SJohn.Forte@Sun.COM 				 * fcip_global_mutex in softstate_free.
1634*7836SJohn.Forte@Sun.COM 				 * Given that, we're still safe to use
1635*7836SJohn.Forte@Sun.COM 				 * fport->fcipp_next to find out what
1636*7836SJohn.Forte@Sun.COM 				 * the next port on the list is.
1637*7836SJohn.Forte@Sun.COM 				 */
1638*7836SJohn.Forte@Sun.COM 				fport = fport->fcipp_next;
1639*7836SJohn.Forte@Sun.COM 			}
1640*7836SJohn.Forte@Sun.COM 
1641*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DETACH,
1642*7836SJohn.Forte@Sun.COM 			    (CE_NOTE, "detaching port"));
1643*7836SJohn.Forte@Sun.COM 
1644*7836SJohn.Forte@Sun.COM 			FCIP_TNF_PROBE_1((fcip_detach,
1645*7836SJohn.Forte@Sun.COM 				"fcip io", /* CSTYLED */, tnf_string,
1646*7836SJohn.Forte@Sun.COM 				msg, "detaching port"));
1647*7836SJohn.Forte@Sun.COM 		}
1648*7836SJohn.Forte@Sun.COM 
1649*7836SJohn.Forte@Sun.COM 		/*
1650*7836SJohn.Forte@Sun.COM 		 * If we haven't removed all the port structures, we
1651*7836SJohn.Forte@Sun.COM 		 * aren't yet ready to be detached.
1652*7836SJohn.Forte@Sun.COM 		 */
1653*7836SJohn.Forte@Sun.COM 		if (fcip_port_head != NULL) {
1654*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1655*7836SJohn.Forte@Sun.COM 			return (DDI_FAILURE);
1656*7836SJohn.Forte@Sun.COM 		}
1657*7836SJohn.Forte@Sun.COM 
1658*7836SJohn.Forte@Sun.COM 		fcip_num_instances = 0;
1659*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1660*7836SJohn.Forte@Sun.COM 		fcip_module_dip = NULL;
1661*7836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1662*7836SJohn.Forte@Sun.COM 	}
1663*7836SJohn.Forte@Sun.COM 	case DDI_SUSPEND:
1664*7836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1665*7836SJohn.Forte@Sun.COM 	default:
1666*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
1667*7836SJohn.Forte@Sun.COM 	}
1668*7836SJohn.Forte@Sun.COM }
1669*7836SJohn.Forte@Sun.COM 
1670*7836SJohn.Forte@Sun.COM /*
1671*7836SJohn.Forte@Sun.COM  * The port_detach callback is called from the transport when a
1672*7836SJohn.Forte@Sun.COM  * FC port is being removed from the transport's control. This routine
1673*7836SJohn.Forte@Sun.COM  * provides fcip with an opportunity to cleanup all activities and
1674*7836SJohn.Forte@Sun.COM  * structures on the port marked for removal.
1675*7836SJohn.Forte@Sun.COM  */
1676*7836SJohn.Forte@Sun.COM /* ARGSUSED */
1677*7836SJohn.Forte@Sun.COM static int
fcip_port_detach(opaque_t ulp_handle,fc_ulp_port_info_t * port_info,fc_detach_cmd_t cmd)1678*7836SJohn.Forte@Sun.COM fcip_port_detach(opaque_t ulp_handle, fc_ulp_port_info_t *port_info,
1679*7836SJohn.Forte@Sun.COM     fc_detach_cmd_t cmd)
1680*7836SJohn.Forte@Sun.COM {
1681*7836SJohn.Forte@Sun.COM 	int 			rval = FC_FAILURE;
1682*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
1683*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
1684*7836SJohn.Forte@Sun.COM 	struct fcipstr		*strp;
1685*7836SJohn.Forte@Sun.COM 
1686*7836SJohn.Forte@Sun.COM 	switch (cmd) {
1687*7836SJohn.Forte@Sun.COM 	case FC_CMD_DETACH: {
1688*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1689*7836SJohn.Forte@Sun.COM 
1690*7836SJohn.Forte@Sun.COM 		if (fcip_port_head == NULL) {
1691*7836SJohn.Forte@Sun.COM 			/*
1692*7836SJohn.Forte@Sun.COM 			 * we are all done but our fini has not been
1693*7836SJohn.Forte@Sun.COM 			 * called yet!! Let's hope we have no active
1694*7836SJohn.Forte@Sun.COM 			 * fcip instances here. - strange secnario but
1695*7836SJohn.Forte@Sun.COM 			 * no harm in having this return a success.
1696*7836SJohn.Forte@Sun.COM 			 */
1697*7836SJohn.Forte@Sun.COM 			fcip_check_remove_minor_node();
1698*7836SJohn.Forte@Sun.COM 
1699*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1700*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
1701*7836SJohn.Forte@Sun.COM 		} else {
1702*7836SJohn.Forte@Sun.COM 			/*
1703*7836SJohn.Forte@Sun.COM 			 * traverse the port list
1704*7836SJohn.Forte@Sun.COM 			 */
1705*7836SJohn.Forte@Sun.COM 			fport = fcip_port_head;
1706*7836SJohn.Forte@Sun.COM 			while (fport != NULL) {
1707*7836SJohn.Forte@Sun.COM 				if (fport->fcipp_handle ==
1708*7836SJohn.Forte@Sun.COM 				    port_info->port_handle) {
1709*7836SJohn.Forte@Sun.COM 					fptr = fport->fcipp_fcip;
1710*7836SJohn.Forte@Sun.COM 
1711*7836SJohn.Forte@Sun.COM 					/*
1712*7836SJohn.Forte@Sun.COM 					 * Fail the port detach if there is
1713*7836SJohn.Forte@Sun.COM 					 * still an attached, bound stream on
1714*7836SJohn.Forte@Sun.COM 					 * this interface.
1715*7836SJohn.Forte@Sun.COM 					 */
1716*7836SJohn.Forte@Sun.COM 
1717*7836SJohn.Forte@Sun.COM 					rw_enter(&fcipstruplock, RW_READER);
1718*7836SJohn.Forte@Sun.COM 
1719*7836SJohn.Forte@Sun.COM 					for (strp = fcipstrup; strp != NULL;
1720*7836SJohn.Forte@Sun.COM 					    strp = strp->sl_nextp) {
1721*7836SJohn.Forte@Sun.COM 						if (strp->sl_fcip == fptr) {
1722*7836SJohn.Forte@Sun.COM 							rw_exit(&fcipstruplock);
1723*7836SJohn.Forte@Sun.COM 							mutex_exit(
1724*7836SJohn.Forte@Sun.COM 							    &fcip_global_mutex);
1725*7836SJohn.Forte@Sun.COM 							return (FC_FAILURE);
1726*7836SJohn.Forte@Sun.COM 						}
1727*7836SJohn.Forte@Sun.COM 					}
1728*7836SJohn.Forte@Sun.COM 
1729*7836SJohn.Forte@Sun.COM 					rw_exit(&fcipstruplock);
1730*7836SJohn.Forte@Sun.COM 
1731*7836SJohn.Forte@Sun.COM 					/*
1732*7836SJohn.Forte@Sun.COM 					 * fail port detach if we are in
1733*7836SJohn.Forte@Sun.COM 					 * the middle of a deferred port attach
1734*7836SJohn.Forte@Sun.COM 					 * or if the port has outstanding pkts
1735*7836SJohn.Forte@Sun.COM 					 */
1736*7836SJohn.Forte@Sun.COM 					if (fptr != NULL) {
1737*7836SJohn.Forte@Sun.COM 						mutex_enter(&fptr->fcip_mutex);
1738*7836SJohn.Forte@Sun.COM 						if (fcip_check_port_busy
1739*7836SJohn.Forte@Sun.COM 						    (fptr) ||
1740*7836SJohn.Forte@Sun.COM 						    (fptr->fcip_flags &
1741*7836SJohn.Forte@Sun.COM 						    FCIP_DETACHED)) {
1742*7836SJohn.Forte@Sun.COM 							mutex_exit(
1743*7836SJohn.Forte@Sun.COM 							    &fptr->fcip_mutex);
1744*7836SJohn.Forte@Sun.COM 							mutex_exit(
1745*7836SJohn.Forte@Sun.COM 							    &fcip_global_mutex);
1746*7836SJohn.Forte@Sun.COM 							return (FC_FAILURE);
1747*7836SJohn.Forte@Sun.COM 						}
1748*7836SJohn.Forte@Sun.COM 
1749*7836SJohn.Forte@Sun.COM 						fptr->fcip_flags |=
1750*7836SJohn.Forte@Sun.COM 						    FCIP_DETACHED;
1751*7836SJohn.Forte@Sun.COM 						mutex_exit(&fptr->fcip_mutex);
1752*7836SJohn.Forte@Sun.COM 					}
1753*7836SJohn.Forte@Sun.COM 					(void) fcip_softstate_free(fport);
1754*7836SJohn.Forte@Sun.COM 
1755*7836SJohn.Forte@Sun.COM 					fcip_check_remove_minor_node();
1756*7836SJohn.Forte@Sun.COM 					mutex_exit(&fcip_global_mutex);
1757*7836SJohn.Forte@Sun.COM 					return (FC_SUCCESS);
1758*7836SJohn.Forte@Sun.COM 				}
1759*7836SJohn.Forte@Sun.COM 				fport = fport->fcipp_next;
1760*7836SJohn.Forte@Sun.COM 			}
1761*7836SJohn.Forte@Sun.COM 			ASSERT(fport == NULL);
1762*7836SJohn.Forte@Sun.COM 		}
1763*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1764*7836SJohn.Forte@Sun.COM 		break;
1765*7836SJohn.Forte@Sun.COM 	}
1766*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_DOWN:
1767*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
1768*7836SJohn.Forte@Sun.COM 	case FC_CMD_SUSPEND:
1769*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
1770*7836SJohn.Forte@Sun.COM 		fport = fcip_port_head;
1771*7836SJohn.Forte@Sun.COM 		while (fport != NULL) {
1772*7836SJohn.Forte@Sun.COM 			if (fport->fcipp_handle == port_info->port_handle) {
1773*7836SJohn.Forte@Sun.COM 				break;
1774*7836SJohn.Forte@Sun.COM 			}
1775*7836SJohn.Forte@Sun.COM 			fport = fport->fcipp_next;
1776*7836SJohn.Forte@Sun.COM 		}
1777*7836SJohn.Forte@Sun.COM 		if (fport == NULL) {
1778*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
1779*7836SJohn.Forte@Sun.COM 			break;
1780*7836SJohn.Forte@Sun.COM 		}
1781*7836SJohn.Forte@Sun.COM 		rval = fcip_handle_suspend(fport, cmd);
1782*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
1783*7836SJohn.Forte@Sun.COM 		break;
1784*7836SJohn.Forte@Sun.COM 	default:
1785*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DETACH,
1786*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "unknown port detach command!!"));
1787*7836SJohn.Forte@Sun.COM 		break;
1788*7836SJohn.Forte@Sun.COM 	}
1789*7836SJohn.Forte@Sun.COM 	return (rval);
1790*7836SJohn.Forte@Sun.COM }
1791*7836SJohn.Forte@Sun.COM 
1792*7836SJohn.Forte@Sun.COM 
1793*7836SJohn.Forte@Sun.COM /*
1794*7836SJohn.Forte@Sun.COM  * Returns 0 if the port is not busy, else returns non zero.
1795*7836SJohn.Forte@Sun.COM  */
1796*7836SJohn.Forte@Sun.COM static int
fcip_check_port_busy(struct fcip * fptr)1797*7836SJohn.Forte@Sun.COM fcip_check_port_busy(struct fcip *fptr)
1798*7836SJohn.Forte@Sun.COM {
1799*7836SJohn.Forte@Sun.COM 	int rval = 0, num_pkts = 0;
1800*7836SJohn.Forte@Sun.COM 
1801*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
1802*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fptr->fcip_mutex));
1803*7836SJohn.Forte@Sun.COM 
1804*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_dest_mutex);
1805*7836SJohn.Forte@Sun.COM 
1806*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_flags & FCIP_PORT_BUSY ||
1807*7836SJohn.Forte@Sun.COM 	    ((num_pkts = fcip_port_get_num_pkts(fptr)) > 0) ||
1808*7836SJohn.Forte@Sun.COM 	    fptr->fcip_num_ipkts_pending) {
1809*7836SJohn.Forte@Sun.COM 		rval = 1;
1810*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DETACH,
1811*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "!fcip_check_port_busy: port is busy "
1812*7836SJohn.Forte@Sun.COM 		    "fcip_flags: 0x%x, num_pkts: 0x%x, ipkts_pending: 0x%lx!",
1813*7836SJohn.Forte@Sun.COM 		    fptr->fcip_flags, num_pkts, fptr->fcip_num_ipkts_pending));
1814*7836SJohn.Forte@Sun.COM 	}
1815*7836SJohn.Forte@Sun.COM 
1816*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_dest_mutex);
1817*7836SJohn.Forte@Sun.COM 	return (rval);
1818*7836SJohn.Forte@Sun.COM }
1819*7836SJohn.Forte@Sun.COM 
1820*7836SJohn.Forte@Sun.COM /*
1821*7836SJohn.Forte@Sun.COM  * Helper routine to remove fcip's minor node
1822*7836SJohn.Forte@Sun.COM  * There is one minor node per system and it should be removed if there are no
1823*7836SJohn.Forte@Sun.COM  * other fcip instances (which has a 1:1 mapping for fp instances) present
1824*7836SJohn.Forte@Sun.COM  */
1825*7836SJohn.Forte@Sun.COM static void
fcip_check_remove_minor_node(void)1826*7836SJohn.Forte@Sun.COM fcip_check_remove_minor_node(void)
1827*7836SJohn.Forte@Sun.COM {
1828*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fcip_global_mutex));
1829*7836SJohn.Forte@Sun.COM 
1830*7836SJohn.Forte@Sun.COM 	/*
1831*7836SJohn.Forte@Sun.COM 	 * If there are no more fcip (fp) instances, remove the
1832*7836SJohn.Forte@Sun.COM 	 * minor node for fcip.
1833*7836SJohn.Forte@Sun.COM 	 * Reset fcip_minor_node_created to invalidate it.
1834*7836SJohn.Forte@Sun.COM 	 */
1835*7836SJohn.Forte@Sun.COM 	if (fcip_num_instances == 0 && (fcip_module_dip != NULL)) {
1836*7836SJohn.Forte@Sun.COM 		ddi_remove_minor_node(fcip_module_dip, NULL);
1837*7836SJohn.Forte@Sun.COM 		fcip_minor_node_created = 0;
1838*7836SJohn.Forte@Sun.COM 	}
1839*7836SJohn.Forte@Sun.COM }
1840*7836SJohn.Forte@Sun.COM 
1841*7836SJohn.Forte@Sun.COM /*
1842*7836SJohn.Forte@Sun.COM  * This routine permits the suspend operation during a CPR/System
1843*7836SJohn.Forte@Sun.COM  * power management operation. The routine basically quiesces I/Os
1844*7836SJohn.Forte@Sun.COM  * on all active interfaces
1845*7836SJohn.Forte@Sun.COM  */
1846*7836SJohn.Forte@Sun.COM static int
fcip_handle_suspend(fcip_port_info_t * fport,fc_detach_cmd_t cmd)1847*7836SJohn.Forte@Sun.COM fcip_handle_suspend(fcip_port_info_t *fport, fc_detach_cmd_t cmd)
1848*7836SJohn.Forte@Sun.COM {
1849*7836SJohn.Forte@Sun.COM 	struct fcip	*fptr = fport->fcipp_fcip;
1850*7836SJohn.Forte@Sun.COM 	timeout_id_t	tid;
1851*7836SJohn.Forte@Sun.COM 	int 		index;
1852*7836SJohn.Forte@Sun.COM 	int		tryagain = 0;
1853*7836SJohn.Forte@Sun.COM 	int		count;
1854*7836SJohn.Forte@Sun.COM 	struct fcipstr	*tslp;
1855*7836SJohn.Forte@Sun.COM 
1856*7836SJohn.Forte@Sun.COM 
1857*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
1858*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
1859*7836SJohn.Forte@Sun.COM 
1860*7836SJohn.Forte@Sun.COM 	/*
1861*7836SJohn.Forte@Sun.COM 	 * Fail if we are in the middle of a callback. Don't use delay during
1862*7836SJohn.Forte@Sun.COM 	 * suspend since clock intrs are not available so busy wait
1863*7836SJohn.Forte@Sun.COM 	 */
1864*7836SJohn.Forte@Sun.COM 	count = 0;
1865*7836SJohn.Forte@Sun.COM 	while (count++ < 15 &&
1866*7836SJohn.Forte@Sun.COM 	    ((fptr->fcip_flags & FCIP_IN_CALLBACK) ||
1867*7836SJohn.Forte@Sun.COM 	    (fptr->fcip_flags & FCIP_IN_TIMEOUT))) {
1868*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
1869*7836SJohn.Forte@Sun.COM 		drv_usecwait(1000000);
1870*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
1871*7836SJohn.Forte@Sun.COM 	}
1872*7836SJohn.Forte@Sun.COM 
1873*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_flags & FCIP_IN_CALLBACK ||
1874*7836SJohn.Forte@Sun.COM 	    fptr->fcip_flags & FCIP_IN_TIMEOUT) {
1875*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
1876*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
1877*7836SJohn.Forte@Sun.COM 	}
1878*7836SJohn.Forte@Sun.COM 
1879*7836SJohn.Forte@Sun.COM 	if (cmd == FC_CMD_POWER_DOWN) {
1880*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_flags & FCIP_SUSPENDED) {
1881*7836SJohn.Forte@Sun.COM 			fptr->fcip_flags |= FCIP_POWER_DOWN;
1882*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
1883*7836SJohn.Forte@Sun.COM 			goto success;
1884*7836SJohn.Forte@Sun.COM 		} else {
1885*7836SJohn.Forte@Sun.COM 			fptr->fcip_flags |= FCIP_POWER_DOWN;
1886*7836SJohn.Forte@Sun.COM 		}
1887*7836SJohn.Forte@Sun.COM 	} else if (cmd == FC_CMD_SUSPEND) {
1888*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags |= FCIP_SUSPENDED;
1889*7836SJohn.Forte@Sun.COM 	} else {
1890*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
1891*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
1892*7836SJohn.Forte@Sun.COM 	}
1893*7836SJohn.Forte@Sun.COM 
1894*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
1895*7836SJohn.Forte@Sun.COM 	/*
1896*7836SJohn.Forte@Sun.COM 	 * If no streams are plumbed - its the easiest case - Just
1897*7836SJohn.Forte@Sun.COM 	 * bail out without having to do much
1898*7836SJohn.Forte@Sun.COM 	 */
1899*7836SJohn.Forte@Sun.COM 
1900*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_READER);
1901*7836SJohn.Forte@Sun.COM 	for (tslp = fcipstrup; tslp; tslp = tslp->sl_nextp) {
1902*7836SJohn.Forte@Sun.COM 		if (tslp->sl_fcip == fptr) {
1903*7836SJohn.Forte@Sun.COM 			break;
1904*7836SJohn.Forte@Sun.COM 		}
1905*7836SJohn.Forte@Sun.COM 	}
1906*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
1907*7836SJohn.Forte@Sun.COM 
1908*7836SJohn.Forte@Sun.COM 	/*
1909*7836SJohn.Forte@Sun.COM 	 * No active streams on this port
1910*7836SJohn.Forte@Sun.COM 	 */
1911*7836SJohn.Forte@Sun.COM 	if (tslp == NULL) {
1912*7836SJohn.Forte@Sun.COM 		goto success;
1913*7836SJohn.Forte@Sun.COM 	}
1914*7836SJohn.Forte@Sun.COM 
1915*7836SJohn.Forte@Sun.COM 	/*
1916*7836SJohn.Forte@Sun.COM 	 * Walk through each Routing table structure and check if
1917*7836SJohn.Forte@Sun.COM 	 * the destination table has any outstanding commands. If yes
1918*7836SJohn.Forte@Sun.COM 	 * wait for the commands to drain. Since we go through each
1919*7836SJohn.Forte@Sun.COM 	 * routing table entry in succession, it may be wise to wait
1920*7836SJohn.Forte@Sun.COM 	 * only a few seconds for each entry.
1921*7836SJohn.Forte@Sun.COM 	 */
1922*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
1923*7836SJohn.Forte@Sun.COM 	while (!tryagain) {
1924*7836SJohn.Forte@Sun.COM 
1925*7836SJohn.Forte@Sun.COM 		tryagain = 0;
1926*7836SJohn.Forte@Sun.COM 		for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
1927*7836SJohn.Forte@Sun.COM 			struct fcip_routing_table 	*frp;
1928*7836SJohn.Forte@Sun.COM 			struct fcip_dest 		*fdestp;
1929*7836SJohn.Forte@Sun.COM 			la_wwn_t			*pwwn;
1930*7836SJohn.Forte@Sun.COM 			int				hash_bucket;
1931*7836SJohn.Forte@Sun.COM 
1932*7836SJohn.Forte@Sun.COM 			frp = fptr->fcip_rtable[index];
1933*7836SJohn.Forte@Sun.COM 			while (frp) {
1934*7836SJohn.Forte@Sun.COM 				/*
1935*7836SJohn.Forte@Sun.COM 				 * Mark the routing table as SUSPENDED. Even
1936*7836SJohn.Forte@Sun.COM 				 * mark the broadcast entry SUSPENDED to
1937*7836SJohn.Forte@Sun.COM 				 * prevent any ARP or other broadcasts. We
1938*7836SJohn.Forte@Sun.COM 				 * can reset the state of the broadcast
1939*7836SJohn.Forte@Sun.COM 				 * RTE when we resume.
1940*7836SJohn.Forte@Sun.COM 				 */
1941*7836SJohn.Forte@Sun.COM 				frp->fcipr_state = FCIP_RT_SUSPENDED;
1942*7836SJohn.Forte@Sun.COM 				pwwn = &frp->fcipr_pwwn;
1943*7836SJohn.Forte@Sun.COM 
1944*7836SJohn.Forte@Sun.COM 				/*
1945*7836SJohn.Forte@Sun.COM 				 * Get hold of destination pointer
1946*7836SJohn.Forte@Sun.COM 				 */
1947*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_dest_mutex);
1948*7836SJohn.Forte@Sun.COM 
1949*7836SJohn.Forte@Sun.COM 				hash_bucket = FCIP_DEST_HASH(pwwn->raw_wwn);
1950*7836SJohn.Forte@Sun.COM 				ASSERT(hash_bucket < FCIP_DEST_HASH_ELEMS);
1951*7836SJohn.Forte@Sun.COM 
1952*7836SJohn.Forte@Sun.COM 				fdestp = fptr->fcip_dest[hash_bucket];
1953*7836SJohn.Forte@Sun.COM 				while (fdestp != NULL) {
1954*7836SJohn.Forte@Sun.COM 					mutex_enter(&fdestp->fcipd_mutex);
1955*7836SJohn.Forte@Sun.COM 					if (fdestp->fcipd_rtable) {
1956*7836SJohn.Forte@Sun.COM 						if (fcip_wwn_compare(pwwn,
1957*7836SJohn.Forte@Sun.COM 						    &fdestp->fcipd_pwwn,
1958*7836SJohn.Forte@Sun.COM 						    FCIP_COMPARE_PWWN) == 0) {
1959*7836SJohn.Forte@Sun.COM 							mutex_exit(
1960*7836SJohn.Forte@Sun.COM 							&fdestp->fcipd_mutex);
1961*7836SJohn.Forte@Sun.COM 							break;
1962*7836SJohn.Forte@Sun.COM 						}
1963*7836SJohn.Forte@Sun.COM 					}
1964*7836SJohn.Forte@Sun.COM 					mutex_exit(&fdestp->fcipd_mutex);
1965*7836SJohn.Forte@Sun.COM 					fdestp = fdestp->fcipd_next;
1966*7836SJohn.Forte@Sun.COM 				}
1967*7836SJohn.Forte@Sun.COM 
1968*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_dest_mutex);
1969*7836SJohn.Forte@Sun.COM 				if (fdestp == NULL) {
1970*7836SJohn.Forte@Sun.COM 					frp = frp->fcipr_next;
1971*7836SJohn.Forte@Sun.COM 					continue;
1972*7836SJohn.Forte@Sun.COM 				}
1973*7836SJohn.Forte@Sun.COM 
1974*7836SJohn.Forte@Sun.COM 				/*
1975*7836SJohn.Forte@Sun.COM 				 * Wait for fcip_wait_cmds seconds for
1976*7836SJohn.Forte@Sun.COM 				 * the commands to drain.
1977*7836SJohn.Forte@Sun.COM 				 */
1978*7836SJohn.Forte@Sun.COM 				count = 0;
1979*7836SJohn.Forte@Sun.COM 				mutex_enter(&fdestp->fcipd_mutex);
1980*7836SJohn.Forte@Sun.COM 				while (fdestp->fcipd_ncmds &&
1981*7836SJohn.Forte@Sun.COM 				    count < fcip_wait_cmds) {
1982*7836SJohn.Forte@Sun.COM 					mutex_exit(&fdestp->fcipd_mutex);
1983*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_rt_mutex);
1984*7836SJohn.Forte@Sun.COM 					drv_usecwait(1000000);
1985*7836SJohn.Forte@Sun.COM 					mutex_enter(&fptr->fcip_rt_mutex);
1986*7836SJohn.Forte@Sun.COM 					mutex_enter(&fdestp->fcipd_mutex);
1987*7836SJohn.Forte@Sun.COM 					count++;
1988*7836SJohn.Forte@Sun.COM 				}
1989*7836SJohn.Forte@Sun.COM 				/*
1990*7836SJohn.Forte@Sun.COM 				 * Check if we were able to drain all cmds
1991*7836SJohn.Forte@Sun.COM 				 * successfully. Else continue with other
1992*7836SJohn.Forte@Sun.COM 				 * ports and try during the second pass
1993*7836SJohn.Forte@Sun.COM 				 */
1994*7836SJohn.Forte@Sun.COM 				if (fdestp->fcipd_ncmds) {
1995*7836SJohn.Forte@Sun.COM 					tryagain++;
1996*7836SJohn.Forte@Sun.COM 				}
1997*7836SJohn.Forte@Sun.COM 				mutex_exit(&fdestp->fcipd_mutex);
1998*7836SJohn.Forte@Sun.COM 
1999*7836SJohn.Forte@Sun.COM 				frp = frp->fcipr_next;
2000*7836SJohn.Forte@Sun.COM 			}
2001*7836SJohn.Forte@Sun.COM 		}
2002*7836SJohn.Forte@Sun.COM 		if (tryagain == 0) {
2003*7836SJohn.Forte@Sun.COM 			break;
2004*7836SJohn.Forte@Sun.COM 		}
2005*7836SJohn.Forte@Sun.COM 	}
2006*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
2007*7836SJohn.Forte@Sun.COM 
2008*7836SJohn.Forte@Sun.COM 	if (tryagain) {
2009*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
2010*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags &= ~(FCIP_SUSPENDED | FCIP_POWER_DOWN);
2011*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2012*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
2013*7836SJohn.Forte@Sun.COM 	}
2014*7836SJohn.Forte@Sun.COM 
2015*7836SJohn.Forte@Sun.COM success:
2016*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2017*7836SJohn.Forte@Sun.COM 	tid = fptr->fcip_timeout_id;
2018*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_id = NULL;
2019*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2020*7836SJohn.Forte@Sun.COM 
2021*7836SJohn.Forte@Sun.COM 	(void) untimeout(tid);
2022*7836SJohn.Forte@Sun.COM 
2023*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
2024*7836SJohn.Forte@Sun.COM }
2025*7836SJohn.Forte@Sun.COM 
2026*7836SJohn.Forte@Sun.COM /*
2027*7836SJohn.Forte@Sun.COM  * the getinfo(9E) entry point
2028*7836SJohn.Forte@Sun.COM  */
2029*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2030*7836SJohn.Forte@Sun.COM static int
fcip_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2031*7836SJohn.Forte@Sun.COM fcip_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2032*7836SJohn.Forte@Sun.COM {
2033*7836SJohn.Forte@Sun.COM 	int rval = DDI_FAILURE;
2034*7836SJohn.Forte@Sun.COM 
2035*7836SJohn.Forte@Sun.COM 	switch (cmd) {
2036*7836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
2037*7836SJohn.Forte@Sun.COM 		*result = fcip_module_dip;
2038*7836SJohn.Forte@Sun.COM 		if (*result)
2039*7836SJohn.Forte@Sun.COM 			rval = DDI_SUCCESS;
2040*7836SJohn.Forte@Sun.COM 		break;
2041*7836SJohn.Forte@Sun.COM 
2042*7836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
2043*7836SJohn.Forte@Sun.COM 		*result = (void *)0;
2044*7836SJohn.Forte@Sun.COM 		rval = DDI_SUCCESS;
2045*7836SJohn.Forte@Sun.COM 		break;
2046*7836SJohn.Forte@Sun.COM 	default:
2047*7836SJohn.Forte@Sun.COM 		break;
2048*7836SJohn.Forte@Sun.COM 	}
2049*7836SJohn.Forte@Sun.COM 
2050*7836SJohn.Forte@Sun.COM 	return (rval);
2051*7836SJohn.Forte@Sun.COM }
2052*7836SJohn.Forte@Sun.COM 
2053*7836SJohn.Forte@Sun.COM /*
2054*7836SJohn.Forte@Sun.COM  * called from fcip_attach to initialize kstats for the link
2055*7836SJohn.Forte@Sun.COM  */
2056*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2057*7836SJohn.Forte@Sun.COM static void
fcip_kstat_init(struct fcip * fptr)2058*7836SJohn.Forte@Sun.COM fcip_kstat_init(struct fcip *fptr)
2059*7836SJohn.Forte@Sun.COM {
2060*7836SJohn.Forte@Sun.COM 	int instance;
2061*7836SJohn.Forte@Sun.COM 	char buf[16];
2062*7836SJohn.Forte@Sun.COM 	struct fcipstat	*fcipstatp;
2063*7836SJohn.Forte@Sun.COM 
2064*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_mutex));
2065*7836SJohn.Forte@Sun.COM 
2066*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(fptr->fcip_dip);
2067*7836SJohn.Forte@Sun.COM 	(void) sprintf(buf, "fcip%d", instance);
2068*7836SJohn.Forte@Sun.COM 
2069*7836SJohn.Forte@Sun.COM #ifdef	kstat
2070*7836SJohn.Forte@Sun.COM 	fptr->fcip_kstatp = kstat_create("fcip", instance, buf, "net",
2071*7836SJohn.Forte@Sun.COM 	    KSTAT_TYPE_NAMED,
2072*7836SJohn.Forte@Sun.COM 	    (sizeof (struct fcipstat)/ sizeof (kstat_named_t)),
2073*7836SJohn.Forte@Sun.COM 	    KSTAT_FLAG_PERSISTENT);
2074*7836SJohn.Forte@Sun.COM #else
2075*7836SJohn.Forte@Sun.COM 	fptr->fcip_kstatp = kstat_create("fcip", instance, buf, "net",
2076*7836SJohn.Forte@Sun.COM 	    KSTAT_TYPE_NAMED,
2077*7836SJohn.Forte@Sun.COM 	    (sizeof (struct fcipstat)/ sizeof (kstat_named_t)), 0);
2078*7836SJohn.Forte@Sun.COM #endif
2079*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_kstatp == NULL) {
2080*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_WARN, "kstat created failed"));
2081*7836SJohn.Forte@Sun.COM 		return;
2082*7836SJohn.Forte@Sun.COM 	}
2083*7836SJohn.Forte@Sun.COM 
2084*7836SJohn.Forte@Sun.COM 	fcipstatp = (struct  fcipstat *)fptr->fcip_kstatp->ks_data;
2085*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_ipackets,	"ipackets",
2086*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2087*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_ierrors,	"ierrors",
2088*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2089*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_opackets,	"opackets",
2090*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2091*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_oerrors,	"oerrors",
2092*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2093*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_collisions,	"collisions",
2094*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2095*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_nocanput,	"nocanput",
2096*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2097*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_allocbfail,	"allocbfail",
2098*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2099*7836SJohn.Forte@Sun.COM 
2100*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_defer, "defer",
2101*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2102*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_fram, "fram",
2103*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2104*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_crc, "crc",
2105*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2106*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_oflo, "oflo",
2107*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2108*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_uflo, "uflo",
2109*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2110*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_missed, "missed",
2111*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2112*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_tlcol, "tlcol",
2113*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2114*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_trtry, "trtry",
2115*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2116*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_tnocar, "tnocar",
2117*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2118*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_inits, "inits",
2119*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2120*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_notbufs, "notbufs",
2121*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2122*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_norbufs, "norbufs",
2123*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2124*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_allocbfail, "allocbfail",
2125*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);
2126*7836SJohn.Forte@Sun.COM 
2127*7836SJohn.Forte@Sun.COM 	/*
2128*7836SJohn.Forte@Sun.COM 	 * required by kstat for MIB II objects(RFC 1213)
2129*7836SJohn.Forte@Sun.COM 	 */
2130*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_rcvbytes, "fcips_rcvbytes",
2131*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # octets received */
2132*7836SJohn.Forte@Sun.COM 					/* MIB - ifInOctets */
2133*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_xmtbytes, "fcips_xmtbytes",
2134*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # octets xmitted */
2135*7836SJohn.Forte@Sun.COM 					/* MIB - ifOutOctets */
2136*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_multircv,	"fcips_multircv",
2137*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # multicast packets */
2138*7836SJohn.Forte@Sun.COM 					/* delivered to upper layer */
2139*7836SJohn.Forte@Sun.COM 					/* MIB - ifInNUcastPkts */
2140*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_multixmt,	"fcips_multixmt",
2141*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # multicast packets */
2142*7836SJohn.Forte@Sun.COM 					/* requested to be sent */
2143*7836SJohn.Forte@Sun.COM 					/* MIB - ifOutNUcastPkts */
2144*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_brdcstrcv, "fcips_brdcstrcv",
2145*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG); /* # broadcast packets */
2146*7836SJohn.Forte@Sun.COM 					/* delivered to upper layer */
2147*7836SJohn.Forte@Sun.COM 					/* MIB - ifInNUcastPkts */
2148*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_brdcstxmt, "fcips_brdcstxmt",
2149*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # broadcast packets */
2150*7836SJohn.Forte@Sun.COM 					/* requested to be sent */
2151*7836SJohn.Forte@Sun.COM 					/* MIB - ifOutNUcastPkts */
2152*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_norcvbuf,	"fcips_norcvbuf",
2153*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # rcv packets discarded */
2154*7836SJohn.Forte@Sun.COM 					/* MIB - ifInDiscards */
2155*7836SJohn.Forte@Sun.COM 	kstat_named_init(&fcipstatp->fcips_noxmtbuf,	"fcips_noxmtbuf",
2156*7836SJohn.Forte@Sun.COM 		KSTAT_DATA_ULONG);	/* # xmt packets discarded */
2157*7836SJohn.Forte@Sun.COM 
2158*7836SJohn.Forte@Sun.COM 	fptr->fcip_kstatp->ks_update = fcip_stat_update;
2159*7836SJohn.Forte@Sun.COM 	fptr->fcip_kstatp->ks_private = (void *) fptr;
2160*7836SJohn.Forte@Sun.COM 	kstat_install(fptr->fcip_kstatp);
2161*7836SJohn.Forte@Sun.COM }
2162*7836SJohn.Forte@Sun.COM 
2163*7836SJohn.Forte@Sun.COM /*
2164*7836SJohn.Forte@Sun.COM  * Update the defined kstats for netstat et al to use
2165*7836SJohn.Forte@Sun.COM  */
2166*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2167*7836SJohn.Forte@Sun.COM static int
fcip_stat_update(kstat_t * fcip_statp,int val)2168*7836SJohn.Forte@Sun.COM fcip_stat_update(kstat_t *fcip_statp, int val)
2169*7836SJohn.Forte@Sun.COM {
2170*7836SJohn.Forte@Sun.COM 	struct fcipstat	*fcipstatp;
2171*7836SJohn.Forte@Sun.COM 	struct fcip	*fptr;
2172*7836SJohn.Forte@Sun.COM 
2173*7836SJohn.Forte@Sun.COM 	fptr = (struct fcip *)fcip_statp->ks_private;
2174*7836SJohn.Forte@Sun.COM 	fcipstatp = (struct fcipstat *)fcip_statp->ks_data;
2175*7836SJohn.Forte@Sun.COM 
2176*7836SJohn.Forte@Sun.COM 	if (val == KSTAT_WRITE) {
2177*7836SJohn.Forte@Sun.COM 		fptr->fcip_ipackets	= fcipstatp->fcips_ipackets.value.ul;
2178*7836SJohn.Forte@Sun.COM 		fptr->fcip_ierrors	= fcipstatp->fcips_ierrors.value.ul;
2179*7836SJohn.Forte@Sun.COM 		fptr->fcip_opackets	= fcipstatp->fcips_opackets.value.ul;
2180*7836SJohn.Forte@Sun.COM 		fptr->fcip_oerrors	= fcipstatp->fcips_oerrors.value.ul;
2181*7836SJohn.Forte@Sun.COM 		fptr->fcip_collisions	= fcipstatp->fcips_collisions.value.ul;
2182*7836SJohn.Forte@Sun.COM 		fptr->fcip_defer	= fcipstatp->fcips_defer.value.ul;
2183*7836SJohn.Forte@Sun.COM 		fptr->fcip_fram	= fcipstatp->fcips_fram.value.ul;
2184*7836SJohn.Forte@Sun.COM 		fptr->fcip_crc	= fcipstatp->fcips_crc.value.ul;
2185*7836SJohn.Forte@Sun.COM 		fptr->fcip_oflo	= fcipstatp->fcips_oflo.value.ul;
2186*7836SJohn.Forte@Sun.COM 		fptr->fcip_uflo	= fcipstatp->fcips_uflo.value.ul;
2187*7836SJohn.Forte@Sun.COM 		fptr->fcip_missed	= fcipstatp->fcips_missed.value.ul;
2188*7836SJohn.Forte@Sun.COM 		fptr->fcip_tlcol	= fcipstatp->fcips_tlcol.value.ul;
2189*7836SJohn.Forte@Sun.COM 		fptr->fcip_trtry	= fcipstatp->fcips_trtry.value.ul;
2190*7836SJohn.Forte@Sun.COM 		fptr->fcip_tnocar	= fcipstatp->fcips_tnocar.value.ul;
2191*7836SJohn.Forte@Sun.COM 		fptr->fcip_inits	= fcipstatp->fcips_inits.value.ul;
2192*7836SJohn.Forte@Sun.COM 		fptr->fcip_notbufs	= fcipstatp->fcips_notbufs.value.ul;
2193*7836SJohn.Forte@Sun.COM 		fptr->fcip_norbufs	= fcipstatp->fcips_norbufs.value.ul;
2194*7836SJohn.Forte@Sun.COM 		fptr->fcip_nocanput	= fcipstatp->fcips_nocanput.value.ul;
2195*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2196*7836SJohn.Forte@Sun.COM 		fptr->fcip_rcvbytes	= fcipstatp->fcips_rcvbytes.value.ul;
2197*7836SJohn.Forte@Sun.COM 		fptr->fcip_xmtbytes	= fcipstatp->fcips_xmtbytes.value.ul;
2198*7836SJohn.Forte@Sun.COM 		fptr->fcip_multircv	= fcipstatp->fcips_multircv.value.ul;
2199*7836SJohn.Forte@Sun.COM 		fptr->fcip_multixmt	= fcipstatp->fcips_multixmt.value.ul;
2200*7836SJohn.Forte@Sun.COM 		fptr->fcip_brdcstrcv	= fcipstatp->fcips_brdcstrcv.value.ul;
2201*7836SJohn.Forte@Sun.COM 		fptr->fcip_norcvbuf	= fcipstatp->fcips_norcvbuf.value.ul;
2202*7836SJohn.Forte@Sun.COM 		fptr->fcip_noxmtbuf	= fcipstatp->fcips_noxmtbuf.value.ul;
2203*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2204*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2205*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2206*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2207*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2208*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2209*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2210*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail	= fcipstatp->fcips_allocbfail.value.ul;
2211*7836SJohn.Forte@Sun.COM 
2212*7836SJohn.Forte@Sun.COM 	} else {
2213*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_ipackets.value.ul	= fptr->fcip_ipackets;
2214*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_ierrors.value.ul	= fptr->fcip_ierrors;
2215*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_opackets.value.ul	= fptr->fcip_opackets;
2216*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_oerrors.value.ul	= fptr->fcip_oerrors;
2217*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_collisions.value.ul	= fptr->fcip_collisions;
2218*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_nocanput.value.ul	= fptr->fcip_nocanput;
2219*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_allocbfail.value.ul	= fptr->fcip_allocbfail;
2220*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_defer.value.ul	= fptr->fcip_defer;
2221*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_fram.value.ul	= fptr->fcip_fram;
2222*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_crc.value.ul	= fptr->fcip_crc;
2223*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_oflo.value.ul	= fptr->fcip_oflo;
2224*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_uflo.value.ul	= fptr->fcip_uflo;
2225*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_missed.value.ul	= fptr->fcip_missed;
2226*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_tlcol.value.ul	= fptr->fcip_tlcol;
2227*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_trtry.value.ul	= fptr->fcip_trtry;
2228*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_tnocar.value.ul	= fptr->fcip_tnocar;
2229*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_inits.value.ul	= fptr->fcip_inits;
2230*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_norbufs.value.ul	= fptr->fcip_norbufs;
2231*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_notbufs.value.ul	= fptr->fcip_notbufs;
2232*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_rcvbytes.value.ul	= fptr->fcip_rcvbytes;
2233*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_xmtbytes.value.ul	= fptr->fcip_xmtbytes;
2234*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_multircv.value.ul	= fptr->fcip_multircv;
2235*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_multixmt.value.ul	= fptr->fcip_multixmt;
2236*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_brdcstrcv.value.ul	= fptr->fcip_brdcstrcv;
2237*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_brdcstxmt.value.ul	= fptr->fcip_brdcstxmt;
2238*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_norcvbuf.value.ul	= fptr->fcip_norcvbuf;
2239*7836SJohn.Forte@Sun.COM 		fcipstatp->fcips_noxmtbuf.value.ul	= fptr->fcip_noxmtbuf;
2240*7836SJohn.Forte@Sun.COM 
2241*7836SJohn.Forte@Sun.COM 	}
2242*7836SJohn.Forte@Sun.COM 	return (0);
2243*7836SJohn.Forte@Sun.COM }
2244*7836SJohn.Forte@Sun.COM 
2245*7836SJohn.Forte@Sun.COM 
2246*7836SJohn.Forte@Sun.COM /*
2247*7836SJohn.Forte@Sun.COM  * fcip_statec_cb: handles all required state change callback notifications
2248*7836SJohn.Forte@Sun.COM  * it receives from the transport
2249*7836SJohn.Forte@Sun.COM  */
2250*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2251*7836SJohn.Forte@Sun.COM static void
fcip_statec_cb(opaque_t ulp_handle,opaque_t phandle,uint32_t port_state,uint32_t port_top,fc_portmap_t changelist[],uint32_t listlen,uint32_t sid)2252*7836SJohn.Forte@Sun.COM fcip_statec_cb(opaque_t ulp_handle, opaque_t phandle,
2253*7836SJohn.Forte@Sun.COM     uint32_t port_state, uint32_t port_top, fc_portmap_t changelist[],
2254*7836SJohn.Forte@Sun.COM     uint32_t listlen, uint32_t sid)
2255*7836SJohn.Forte@Sun.COM {
2256*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
2257*7836SJohn.Forte@Sun.COM 	struct fcip 		*fptr;
2258*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
2259*7836SJohn.Forte@Sun.COM 	queue_t			*wrq;
2260*7836SJohn.Forte@Sun.COM 	int			instance;
2261*7836SJohn.Forte@Sun.COM 	int 			index;
2262*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table 	*frtp;
2263*7836SJohn.Forte@Sun.COM 
2264*7836SJohn.Forte@Sun.COM 	fport = fcip_get_port(phandle);
2265*7836SJohn.Forte@Sun.COM 
2266*7836SJohn.Forte@Sun.COM 	if (fport == NULL) {
2267*7836SJohn.Forte@Sun.COM 		return;
2268*7836SJohn.Forte@Sun.COM 	}
2269*7836SJohn.Forte@Sun.COM 
2270*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
2271*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
2272*7836SJohn.Forte@Sun.COM 
2273*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
2274*7836SJohn.Forte@Sun.COM 		return;
2275*7836SJohn.Forte@Sun.COM 	}
2276*7836SJohn.Forte@Sun.COM 
2277*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(fport->fcipp_dip);
2278*7836SJohn.Forte@Sun.COM 
2279*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_4((fcip_statec_cb, "fcip io", /* CSTYLED */,
2280*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "state change callback",
2281*7836SJohn.Forte@Sun.COM 		tnf_uint, instance, instance,
2282*7836SJohn.Forte@Sun.COM 		tnf_uint, S_ID, sid,
2283*7836SJohn.Forte@Sun.COM 		tnf_int, count, listlen));
2284*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_ELS,
2285*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "fcip%d, state change callback: state:0x%x, "
2286*7836SJohn.Forte@Sun.COM 	    "S_ID:0x%x, count:0x%x", instance, port_state, sid, listlen));
2287*7836SJohn.Forte@Sun.COM 
2288*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2289*7836SJohn.Forte@Sun.COM 
2290*7836SJohn.Forte@Sun.COM 	if ((fptr->fcip_flags & (FCIP_DETACHING | FCIP_DETACHED)) ||
2291*7836SJohn.Forte@Sun.COM 	    (fptr->fcip_flags & (FCIP_SUSPENDED | FCIP_POWER_DOWN))) {
2292*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2293*7836SJohn.Forte@Sun.COM 		return;
2294*7836SJohn.Forte@Sun.COM 	}
2295*7836SJohn.Forte@Sun.COM 
2296*7836SJohn.Forte@Sun.COM 	/*
2297*7836SJohn.Forte@Sun.COM 	 * set fcip flags to indicate we are in the middle of a
2298*7836SJohn.Forte@Sun.COM 	 * state change callback so we can wait till the statechange
2299*7836SJohn.Forte@Sun.COM 	 * is handled before succeeding/failing the SUSPEND/POWER DOWN.
2300*7836SJohn.Forte@Sun.COM 	 */
2301*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags |= FCIP_IN_SC_CB;
2302*7836SJohn.Forte@Sun.COM 
2303*7836SJohn.Forte@Sun.COM 	fport->fcipp_pstate = port_state;
2304*7836SJohn.Forte@Sun.COM 
2305*7836SJohn.Forte@Sun.COM 	/*
2306*7836SJohn.Forte@Sun.COM 	 * Check if topology changed. If Yes - Modify the broadcast
2307*7836SJohn.Forte@Sun.COM 	 * RTE entries to understand the new broadcast D_IDs
2308*7836SJohn.Forte@Sun.COM 	 */
2309*7836SJohn.Forte@Sun.COM 	if (fport->fcipp_topology != port_top &&
2310*7836SJohn.Forte@Sun.COM 	    (port_top != FC_TOP_UNKNOWN)) {
2311*7836SJohn.Forte@Sun.COM 		/* REMOVE later */
2312*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_NOTE,
2313*7836SJohn.Forte@Sun.COM 		    "topology changed: Old topology: 0x%x New topology 0x%x",
2314*7836SJohn.Forte@Sun.COM 		    fport->fcipp_topology, port_top));
2315*7836SJohn.Forte@Sun.COM 		/*
2316*7836SJohn.Forte@Sun.COM 		 * If topology changed - attempt a rediscovery of
2317*7836SJohn.Forte@Sun.COM 		 * devices. Helps specially in Fabric/Public loops
2318*7836SJohn.Forte@Sun.COM 		 * and if on_demand_node_creation is disabled
2319*7836SJohn.Forte@Sun.COM 		 */
2320*7836SJohn.Forte@Sun.COM 		fport->fcipp_topology = port_top;
2321*7836SJohn.Forte@Sun.COM 		fcip_handle_topology(fptr);
2322*7836SJohn.Forte@Sun.COM 	}
2323*7836SJohn.Forte@Sun.COM 
2324*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2325*7836SJohn.Forte@Sun.COM 
2326*7836SJohn.Forte@Sun.COM 	switch (FC_PORT_STATE_MASK(port_state)) {
2327*7836SJohn.Forte@Sun.COM 	case FC_STATE_ONLINE:
2328*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
2329*7836SJohn.Forte@Sun.COM 	case FC_STATE_LIP:
2330*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
2331*7836SJohn.Forte@Sun.COM 	case FC_STATE_LIP_LBIT_SET:
2332*7836SJohn.Forte@Sun.COM 
2333*7836SJohn.Forte@Sun.COM 		/*
2334*7836SJohn.Forte@Sun.COM 		 * nothing to do here actually other than if we
2335*7836SJohn.Forte@Sun.COM 		 * were actually logged onto a port in the devlist
2336*7836SJohn.Forte@Sun.COM 		 * (which indicates active communication between
2337*7836SJohn.Forte@Sun.COM 		 * the host port and the port in the changelist).
2338*7836SJohn.Forte@Sun.COM 		 * If however we are in a private loop or point to
2339*7836SJohn.Forte@Sun.COM 		 * point mode, we need to check for any IP capable
2340*7836SJohn.Forte@Sun.COM 		 * ports and update our routing table.
2341*7836SJohn.Forte@Sun.COM 		 */
2342*7836SJohn.Forte@Sun.COM 		switch (port_top) {
2343*7836SJohn.Forte@Sun.COM 		case FC_TOP_FABRIC:
2344*7836SJohn.Forte@Sun.COM 			/*
2345*7836SJohn.Forte@Sun.COM 			 * This indicates a fabric port with a NameServer.
2346*7836SJohn.Forte@Sun.COM 			 * Check the devlist to see if we are in active
2347*7836SJohn.Forte@Sun.COM 			 * communication with a port on the devlist.
2348*7836SJohn.Forte@Sun.COM 			 */
2349*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_NOTE,
2350*7836SJohn.Forte@Sun.COM 			    "Statec_cb: fabric topology"));
2351*7836SJohn.Forte@Sun.COM 			fcip_rt_update(fptr, changelist, listlen);
2352*7836SJohn.Forte@Sun.COM 			break;
2353*7836SJohn.Forte@Sun.COM 		case FC_TOP_NO_NS:
2354*7836SJohn.Forte@Sun.COM 			/*
2355*7836SJohn.Forte@Sun.COM 			 * No nameserver - so treat it like a Private loop
2356*7836SJohn.Forte@Sun.COM 			 * or point to point topology and get a map of
2357*7836SJohn.Forte@Sun.COM 			 * devices on the link and get IP capable ports to
2358*7836SJohn.Forte@Sun.COM 			 * to update the routing table.
2359*7836SJohn.Forte@Sun.COM 			 */
2360*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ELS,
2361*7836SJohn.Forte@Sun.COM 			    (CE_NOTE, "Statec_cb: NO_NS topology"));
2362*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
2363*7836SJohn.Forte@Sun.COM 		case FC_TOP_PRIVATE_LOOP:
2364*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_NOTE,
2365*7836SJohn.Forte@Sun.COM 			    "Statec_cb: Pvt_Loop topology"));
2366*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
2367*7836SJohn.Forte@Sun.COM 		case FC_TOP_PT_PT:
2368*7836SJohn.Forte@Sun.COM 			/*
2369*7836SJohn.Forte@Sun.COM 			 * call get_port_map() and update routing table
2370*7836SJohn.Forte@Sun.COM 			 */
2371*7836SJohn.Forte@Sun.COM 			fcip_rt_update(fptr, changelist, listlen);
2372*7836SJohn.Forte@Sun.COM 			break;
2373*7836SJohn.Forte@Sun.COM 		default:
2374*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_ELS,
2375*7836SJohn.Forte@Sun.COM 			    (CE_NOTE, "Statec_cb: Unknown topology"));
2376*7836SJohn.Forte@Sun.COM 		}
2377*7836SJohn.Forte@Sun.COM 
2378*7836SJohn.Forte@Sun.COM 		/*
2379*7836SJohn.Forte@Sun.COM 		 * We should now enable the Queues and permit I/Os
2380*7836SJohn.Forte@Sun.COM 		 * to flow through downstream. The update of routing
2381*7836SJohn.Forte@Sun.COM 		 * table should have flushed out any port entries that
2382*7836SJohn.Forte@Sun.COM 		 * don't exist or are not available after the state change
2383*7836SJohn.Forte@Sun.COM 		 */
2384*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
2385*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_ONLINE;
2386*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_flags & FCIP_LINK_DOWN) {
2387*7836SJohn.Forte@Sun.COM 			fptr->fcip_flags &= ~FCIP_LINK_DOWN;
2388*7836SJohn.Forte@Sun.COM 		}
2389*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2390*7836SJohn.Forte@Sun.COM 
2391*7836SJohn.Forte@Sun.COM 		/*
2392*7836SJohn.Forte@Sun.COM 		 * Enable write queues
2393*7836SJohn.Forte@Sun.COM 		 */
2394*7836SJohn.Forte@Sun.COM 		rw_enter(&fcipstruplock, RW_READER);
2395*7836SJohn.Forte@Sun.COM 		for (slp = fcipstrup; slp != NULL; slp = slp->sl_nextp) {
2396*7836SJohn.Forte@Sun.COM 			if (slp && slp->sl_fcip == fptr) {
2397*7836SJohn.Forte@Sun.COM 				wrq = WR(slp->sl_rq);
2398*7836SJohn.Forte@Sun.COM 				if (wrq->q_flag & QFULL) {
2399*7836SJohn.Forte@Sun.COM 					qenable(wrq);
2400*7836SJohn.Forte@Sun.COM 				}
2401*7836SJohn.Forte@Sun.COM 			}
2402*7836SJohn.Forte@Sun.COM 		}
2403*7836SJohn.Forte@Sun.COM 		rw_exit(&fcipstruplock);
2404*7836SJohn.Forte@Sun.COM 		break;
2405*7836SJohn.Forte@Sun.COM 	case FC_STATE_OFFLINE:
2406*7836SJohn.Forte@Sun.COM 		/*
2407*7836SJohn.Forte@Sun.COM 		 * mark the port_state OFFLINE and wait for it to
2408*7836SJohn.Forte@Sun.COM 		 * become online. Any new messages in this state will
2409*7836SJohn.Forte@Sun.COM 		 * simply be queued back up. If the port does not
2410*7836SJohn.Forte@Sun.COM 		 * come online in a short while, we can begin failing
2411*7836SJohn.Forte@Sun.COM 		 * messages and flush the routing table
2412*7836SJohn.Forte@Sun.COM 		 */
2413*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
2414*7836SJohn.Forte@Sun.COM 		fptr->fcip_mark_offline = fptr->fcip_timeout_ticks +
2415*7836SJohn.Forte@Sun.COM 		    FCIP_OFFLINE_TIMEOUT;
2416*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_OFFLINE;
2417*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2418*7836SJohn.Forte@Sun.COM 
2419*7836SJohn.Forte@Sun.COM 		/*
2420*7836SJohn.Forte@Sun.COM 		 * Mark all Routing table entries as invalid to prevent
2421*7836SJohn.Forte@Sun.COM 		 * any commands from trickling through to ports that
2422*7836SJohn.Forte@Sun.COM 		 * have disappeared from under us
2423*7836SJohn.Forte@Sun.COM 		 */
2424*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
2425*7836SJohn.Forte@Sun.COM 		for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
2426*7836SJohn.Forte@Sun.COM 			frtp = fptr->fcip_rtable[index];
2427*7836SJohn.Forte@Sun.COM 			while (frtp) {
2428*7836SJohn.Forte@Sun.COM 				frtp->fcipr_state = PORT_DEVICE_INVALID;
2429*7836SJohn.Forte@Sun.COM 				frtp = frtp->fcipr_next;
2430*7836SJohn.Forte@Sun.COM 			}
2431*7836SJohn.Forte@Sun.COM 		}
2432*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
2433*7836SJohn.Forte@Sun.COM 
2434*7836SJohn.Forte@Sun.COM 		break;
2435*7836SJohn.Forte@Sun.COM 
2436*7836SJohn.Forte@Sun.COM 	case FC_STATE_RESET_REQUESTED:
2437*7836SJohn.Forte@Sun.COM 		/*
2438*7836SJohn.Forte@Sun.COM 		 * Release all Unsolicited buffers back to transport/FCA.
2439*7836SJohn.Forte@Sun.COM 		 * This also means the port state is marked offline - so
2440*7836SJohn.Forte@Sun.COM 		 * we may have to do what OFFLINE state requires us to do.
2441*7836SJohn.Forte@Sun.COM 		 * Care must be taken to wait for any active unsolicited
2442*7836SJohn.Forte@Sun.COM 		 * buffer with the other Streams modules - so wait for
2443*7836SJohn.Forte@Sun.COM 		 * a freeb if the unsolicited buffer is passed back all
2444*7836SJohn.Forte@Sun.COM 		 * the way upstream.
2445*7836SJohn.Forte@Sun.COM 		 */
2446*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
2447*7836SJohn.Forte@Sun.COM 
2448*7836SJohn.Forte@Sun.COM #ifdef FCIP_ESBALLOC
2449*7836SJohn.Forte@Sun.COM 		while (fptr->fcip_ub_upstream) {
2450*7836SJohn.Forte@Sun.COM 			cv_wait(&fptr->fcip_ub_cv, &fptr->fcip_mutex);
2451*7836SJohn.Forte@Sun.COM 		}
2452*7836SJohn.Forte@Sun.COM #endif	/* FCIP_ESBALLOC */
2453*7836SJohn.Forte@Sun.COM 
2454*7836SJohn.Forte@Sun.COM 		fptr->fcip_mark_offline = fptr->fcip_timeout_ticks +
2455*7836SJohn.Forte@Sun.COM 		    FCIP_OFFLINE_TIMEOUT;
2456*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_OFFLINE;
2457*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2458*7836SJohn.Forte@Sun.COM 		break;
2459*7836SJohn.Forte@Sun.COM 
2460*7836SJohn.Forte@Sun.COM 	case FC_STATE_DEVICE_CHANGE:
2461*7836SJohn.Forte@Sun.COM 		if (listlen) {
2462*7836SJohn.Forte@Sun.COM 			fcip_rt_update(fptr, changelist, listlen);
2463*7836SJohn.Forte@Sun.COM 		}
2464*7836SJohn.Forte@Sun.COM 		break;
2465*7836SJohn.Forte@Sun.COM 	case FC_STATE_RESET:
2466*7836SJohn.Forte@Sun.COM 		/*
2467*7836SJohn.Forte@Sun.COM 		 * Not much to do I guess - wait for port to become
2468*7836SJohn.Forte@Sun.COM 		 * ONLINE. If the port doesn't become online in a short
2469*7836SJohn.Forte@Sun.COM 		 * while, the upper layers abort any request themselves.
2470*7836SJohn.Forte@Sun.COM 		 * We can just putback the messages in the streams queues
2471*7836SJohn.Forte@Sun.COM 		 * if the link is offline
2472*7836SJohn.Forte@Sun.COM 		 */
2473*7836SJohn.Forte@Sun.COM 		break;
2474*7836SJohn.Forte@Sun.COM 	}
2475*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2476*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~(FCIP_IN_SC_CB);
2477*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2478*7836SJohn.Forte@Sun.COM }
2479*7836SJohn.Forte@Sun.COM 
2480*7836SJohn.Forte@Sun.COM /*
2481*7836SJohn.Forte@Sun.COM  * Given a port handle, return the fcip_port_info structure corresponding
2482*7836SJohn.Forte@Sun.COM  * to that port handle. The transport allocates and communicates with
2483*7836SJohn.Forte@Sun.COM  * ULPs using port handles
2484*7836SJohn.Forte@Sun.COM  */
2485*7836SJohn.Forte@Sun.COM static fcip_port_info_t *
fcip_get_port(opaque_t phandle)2486*7836SJohn.Forte@Sun.COM fcip_get_port(opaque_t phandle)
2487*7836SJohn.Forte@Sun.COM {
2488*7836SJohn.Forte@Sun.COM 	fcip_port_info_t *fport;
2489*7836SJohn.Forte@Sun.COM 
2490*7836SJohn.Forte@Sun.COM 	ASSERT(phandle != NULL);
2491*7836SJohn.Forte@Sun.COM 
2492*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
2493*7836SJohn.Forte@Sun.COM 	fport = fcip_port_head;
2494*7836SJohn.Forte@Sun.COM 
2495*7836SJohn.Forte@Sun.COM 	while (fport != NULL) {
2496*7836SJohn.Forte@Sun.COM 		if (fport->fcipp_handle == phandle) {
2497*7836SJohn.Forte@Sun.COM 			/* found */
2498*7836SJohn.Forte@Sun.COM 			break;
2499*7836SJohn.Forte@Sun.COM 		}
2500*7836SJohn.Forte@Sun.COM 		fport = fport->fcipp_next;
2501*7836SJohn.Forte@Sun.COM 	}
2502*7836SJohn.Forte@Sun.COM 
2503*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
2504*7836SJohn.Forte@Sun.COM 
2505*7836SJohn.Forte@Sun.COM 	return (fport);
2506*7836SJohn.Forte@Sun.COM }
2507*7836SJohn.Forte@Sun.COM 
2508*7836SJohn.Forte@Sun.COM /*
2509*7836SJohn.Forte@Sun.COM  * Handle inbound ELS requests received by the transport. We are only
2510*7836SJohn.Forte@Sun.COM  * intereseted in FARP/InARP mostly.
2511*7836SJohn.Forte@Sun.COM  */
2512*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2513*7836SJohn.Forte@Sun.COM static int
fcip_els_cb(opaque_t ulp_handle,opaque_t phandle,fc_unsol_buf_t * buf,uint32_t claimed)2514*7836SJohn.Forte@Sun.COM fcip_els_cb(opaque_t ulp_handle, opaque_t phandle,
2515*7836SJohn.Forte@Sun.COM     fc_unsol_buf_t *buf, uint32_t claimed)
2516*7836SJohn.Forte@Sun.COM {
2517*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
2518*7836SJohn.Forte@Sun.COM 	struct fcip 		*fptr;
2519*7836SJohn.Forte@Sun.COM 	int			instance;
2520*7836SJohn.Forte@Sun.COM 	uchar_t			r_ctl;
2521*7836SJohn.Forte@Sun.COM 	uchar_t			ls_code;
2522*7836SJohn.Forte@Sun.COM 	la_els_farp_t		farp_cmd;
2523*7836SJohn.Forte@Sun.COM 	la_els_farp_t		*fcmd;
2524*7836SJohn.Forte@Sun.COM 	int			rval = FC_UNCLAIMED;
2525*7836SJohn.Forte@Sun.COM 
2526*7836SJohn.Forte@Sun.COM 	fport = fcip_get_port(phandle);
2527*7836SJohn.Forte@Sun.COM 	if (fport == NULL) {
2528*7836SJohn.Forte@Sun.COM 		return (FC_UNCLAIMED);
2529*7836SJohn.Forte@Sun.COM 	}
2530*7836SJohn.Forte@Sun.COM 
2531*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
2532*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
2533*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
2534*7836SJohn.Forte@Sun.COM 		return (FC_UNCLAIMED);
2535*7836SJohn.Forte@Sun.COM 	}
2536*7836SJohn.Forte@Sun.COM 
2537*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(fport->fcipp_dip);
2538*7836SJohn.Forte@Sun.COM 
2539*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2540*7836SJohn.Forte@Sun.COM 	if ((fptr->fcip_flags & (FCIP_DETACHING | FCIP_DETACHED)) ||
2541*7836SJohn.Forte@Sun.COM 	    (fptr->fcip_flags & (FCIP_SUSPENDED | FCIP_POWER_DOWN))) {
2542*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2543*7836SJohn.Forte@Sun.COM 		return (FC_UNCLAIMED);
2544*7836SJohn.Forte@Sun.COM 	}
2545*7836SJohn.Forte@Sun.COM 
2546*7836SJohn.Forte@Sun.COM 	/*
2547*7836SJohn.Forte@Sun.COM 	 * set fcip flags to indicate we are in the middle of a
2548*7836SJohn.Forte@Sun.COM 	 * ELS callback so we can wait till the statechange
2549*7836SJohn.Forte@Sun.COM 	 * is handled before succeeding/failing the SUSPEND/POWER DOWN.
2550*7836SJohn.Forte@Sun.COM 	 */
2551*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags |= FCIP_IN_ELS_CB;
2552*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2553*7836SJohn.Forte@Sun.COM 
2554*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_els_cb, "fcip io", /* CSTYLED */,
2555*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "ELS callback",
2556*7836SJohn.Forte@Sun.COM 		tnf_uint, instance, instance));
2557*7836SJohn.Forte@Sun.COM 
2558*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_ELS,
2559*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "fcip%d, ELS callback , ", instance));
2560*7836SJohn.Forte@Sun.COM 
2561*7836SJohn.Forte@Sun.COM 	r_ctl = buf->ub_frame.r_ctl;
2562*7836SJohn.Forte@Sun.COM 	switch (r_ctl & R_CTL_ROUTING) {
2563*7836SJohn.Forte@Sun.COM 	case R_CTL_EXTENDED_SVC:
2564*7836SJohn.Forte@Sun.COM 		if (r_ctl == R_CTL_ELS_REQ) {
2565*7836SJohn.Forte@Sun.COM 			ls_code = buf->ub_buffer[0];
2566*7836SJohn.Forte@Sun.COM 			if (ls_code == LA_ELS_FARP_REQ) {
2567*7836SJohn.Forte@Sun.COM 				/*
2568*7836SJohn.Forte@Sun.COM 				 * Inbound FARP broadcast request
2569*7836SJohn.Forte@Sun.COM 				 */
2570*7836SJohn.Forte@Sun.COM 				if (buf->ub_bufsize != sizeof (la_els_farp_t)) {
2571*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_WARN,
2572*7836SJohn.Forte@Sun.COM 					    "Invalid FARP req buffer size "
2573*7836SJohn.Forte@Sun.COM 					    "expected 0x%lx, got 0x%x",
2574*7836SJohn.Forte@Sun.COM 					    (long)(sizeof (la_els_farp_t)),
2575*7836SJohn.Forte@Sun.COM 					    buf->ub_bufsize));
2576*7836SJohn.Forte@Sun.COM 					rval = FC_UNCLAIMED;
2577*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2578*7836SJohn.Forte@Sun.COM 				}
2579*7836SJohn.Forte@Sun.COM 				fcmd = (la_els_farp_t *)buf;
2580*7836SJohn.Forte@Sun.COM 				if (fcip_wwn_compare(&fcmd->resp_nwwn,
2581*7836SJohn.Forte@Sun.COM 				    &fport->fcipp_nwwn,
2582*7836SJohn.Forte@Sun.COM 				    FCIP_COMPARE_NWWN) != 0) {
2583*7836SJohn.Forte@Sun.COM 					rval = FC_UNCLAIMED;
2584*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2585*7836SJohn.Forte@Sun.COM 				}
2586*7836SJohn.Forte@Sun.COM 				/*
2587*7836SJohn.Forte@Sun.COM 				 * copy the FARP request and release the
2588*7836SJohn.Forte@Sun.COM 				 * unsolicited buffer
2589*7836SJohn.Forte@Sun.COM 				 */
2590*7836SJohn.Forte@Sun.COM 				fcmd = &farp_cmd;
2591*7836SJohn.Forte@Sun.COM 				bcopy((void *)buf, (void *)fcmd,
2592*7836SJohn.Forte@Sun.COM 				    sizeof (la_els_farp_t));
2593*7836SJohn.Forte@Sun.COM 				(void) fc_ulp_ubrelease(fport->fcipp_handle, 1,
2594*7836SJohn.Forte@Sun.COM 				    &buf->ub_token);
2595*7836SJohn.Forte@Sun.COM 
2596*7836SJohn.Forte@Sun.COM 				if (fcip_farp_supported &&
2597*7836SJohn.Forte@Sun.COM 				    fcip_handle_farp_request(fptr, fcmd) ==
2598*7836SJohn.Forte@Sun.COM 				    FC_SUCCESS) {
2599*7836SJohn.Forte@Sun.COM 					/*
2600*7836SJohn.Forte@Sun.COM 					 * We successfully sent out a FARP
2601*7836SJohn.Forte@Sun.COM 					 * reply to the requesting port
2602*7836SJohn.Forte@Sun.COM 					 */
2603*7836SJohn.Forte@Sun.COM 					rval = FC_SUCCESS;
2604*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2605*7836SJohn.Forte@Sun.COM 				} else {
2606*7836SJohn.Forte@Sun.COM 					rval = FC_UNCLAIMED;
2607*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2608*7836SJohn.Forte@Sun.COM 				}
2609*7836SJohn.Forte@Sun.COM 			}
2610*7836SJohn.Forte@Sun.COM 		} else if (r_ctl == R_CTL_ELS_RSP) {
2611*7836SJohn.Forte@Sun.COM 			ls_code = buf->ub_buffer[0];
2612*7836SJohn.Forte@Sun.COM 			if (ls_code == LA_ELS_FARP_REPLY) {
2613*7836SJohn.Forte@Sun.COM 				/*
2614*7836SJohn.Forte@Sun.COM 				 * We received a REPLY to our FARP request
2615*7836SJohn.Forte@Sun.COM 				 */
2616*7836SJohn.Forte@Sun.COM 				if (buf->ub_bufsize != sizeof (la_els_farp_t)) {
2617*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_WARN,
2618*7836SJohn.Forte@Sun.COM 					    "Invalid FARP req buffer size "
2619*7836SJohn.Forte@Sun.COM 					    "expected 0x%lx, got 0x%x",
2620*7836SJohn.Forte@Sun.COM 					    (long)(sizeof (la_els_farp_t)),
2621*7836SJohn.Forte@Sun.COM 					    buf->ub_bufsize));
2622*7836SJohn.Forte@Sun.COM 					rval = FC_UNCLAIMED;
2623*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2624*7836SJohn.Forte@Sun.COM 				}
2625*7836SJohn.Forte@Sun.COM 				fcmd = &farp_cmd;
2626*7836SJohn.Forte@Sun.COM 				bcopy((void *)buf, (void *)fcmd,
2627*7836SJohn.Forte@Sun.COM 				    sizeof (la_els_farp_t));
2628*7836SJohn.Forte@Sun.COM 				(void) fc_ulp_ubrelease(fport->fcipp_handle, 1,
2629*7836SJohn.Forte@Sun.COM 				    &buf->ub_token);
2630*7836SJohn.Forte@Sun.COM 				if (fcip_farp_supported &&
2631*7836SJohn.Forte@Sun.COM 				    fcip_handle_farp_response(fptr, fcmd) ==
2632*7836SJohn.Forte@Sun.COM 				    FC_SUCCESS) {
2633*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_NOTE,
2634*7836SJohn.Forte@Sun.COM 					    "Successfully recevied a FARP "
2635*7836SJohn.Forte@Sun.COM 					    "response"));
2636*7836SJohn.Forte@Sun.COM 					mutex_enter(&fptr->fcip_mutex);
2637*7836SJohn.Forte@Sun.COM 					fptr->fcip_farp_rsp_flag = 1;
2638*7836SJohn.Forte@Sun.COM 					cv_signal(&fptr->fcip_farp_cv);
2639*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
2640*7836SJohn.Forte@Sun.COM 					rval = FC_SUCCESS;
2641*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2642*7836SJohn.Forte@Sun.COM 				} else {
2643*7836SJohn.Forte@Sun.COM 					FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_WARN,
2644*7836SJohn.Forte@Sun.COM 					    "Unable to handle a FARP response "
2645*7836SJohn.Forte@Sun.COM 					    "receive"));
2646*7836SJohn.Forte@Sun.COM 					rval = FC_UNCLAIMED;
2647*7836SJohn.Forte@Sun.COM 					goto els_cb_done;
2648*7836SJohn.Forte@Sun.COM 				}
2649*7836SJohn.Forte@Sun.COM 			}
2650*7836SJohn.Forte@Sun.COM 		}
2651*7836SJohn.Forte@Sun.COM 		break;
2652*7836SJohn.Forte@Sun.COM 	default:
2653*7836SJohn.Forte@Sun.COM 		break;
2654*7836SJohn.Forte@Sun.COM 	}
2655*7836SJohn.Forte@Sun.COM els_cb_done:
2656*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2657*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~(FCIP_IN_ELS_CB);
2658*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2659*7836SJohn.Forte@Sun.COM 	return (rval);
2660*7836SJohn.Forte@Sun.COM }
2661*7836SJohn.Forte@Sun.COM 
2662*7836SJohn.Forte@Sun.COM 
2663*7836SJohn.Forte@Sun.COM /*
2664*7836SJohn.Forte@Sun.COM  * Handle inbound FARP requests
2665*7836SJohn.Forte@Sun.COM  */
2666*7836SJohn.Forte@Sun.COM static int
fcip_handle_farp_request(struct fcip * fptr,la_els_farp_t * fcmd)2667*7836SJohn.Forte@Sun.COM fcip_handle_farp_request(struct fcip *fptr, la_els_farp_t *fcmd)
2668*7836SJohn.Forte@Sun.COM {
2669*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt;
2670*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
2671*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
2672*7836SJohn.Forte@Sun.COM 	int			rval = FC_FAILURE;
2673*7836SJohn.Forte@Sun.COM 	opaque_t		fca_dev;
2674*7836SJohn.Forte@Sun.COM 	fc_portmap_t 		map;
2675*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table *frp;
2676*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp;
2677*7836SJohn.Forte@Sun.COM 
2678*7836SJohn.Forte@Sun.COM 	/*
2679*7836SJohn.Forte@Sun.COM 	 * Add an entry for the remote port into our routing and destination
2680*7836SJohn.Forte@Sun.COM 	 * tables.
2681*7836SJohn.Forte@Sun.COM 	 */
2682*7836SJohn.Forte@Sun.COM 	map.map_did = fcmd->req_id;
2683*7836SJohn.Forte@Sun.COM 	map.map_hard_addr.hard_addr = fcmd->req_id.port_id;
2684*7836SJohn.Forte@Sun.COM 	map.map_state = PORT_DEVICE_VALID;
2685*7836SJohn.Forte@Sun.COM 	map.map_type = PORT_DEVICE_NEW;
2686*7836SJohn.Forte@Sun.COM 	map.map_flags = 0;
2687*7836SJohn.Forte@Sun.COM 	map.map_pd = NULL;
2688*7836SJohn.Forte@Sun.COM 	bcopy((void *)&fcmd->req_pwwn, (void *)&map.map_pwwn,
2689*7836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t));
2690*7836SJohn.Forte@Sun.COM 	bcopy((void *)&fcmd->req_nwwn, (void *)&map.map_nwwn,
2691*7836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t));
2692*7836SJohn.Forte@Sun.COM 	fcip_rt_update(fptr, &map, 1);
2693*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
2694*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, &fcmd->req_pwwn, FCIP_COMPARE_NWWN);
2695*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
2696*7836SJohn.Forte@Sun.COM 
2697*7836SJohn.Forte@Sun.COM 	fdestp = fcip_add_dest(fptr, frp);
2698*7836SJohn.Forte@Sun.COM 
2699*7836SJohn.Forte@Sun.COM 	fcip_pkt = fcip_ipkt_alloc(fptr, sizeof (la_els_farp_t),
2700*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_farp_t), NULL, KM_SLEEP);
2701*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
2702*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
2703*7836SJohn.Forte@Sun.COM 		goto farp_done;
2704*7836SJohn.Forte@Sun.COM 	}
2705*7836SJohn.Forte@Sun.COM 	/*
2706*7836SJohn.Forte@Sun.COM 	 * Fill in our port's PWWN and NWWN
2707*7836SJohn.Forte@Sun.COM 	 */
2708*7836SJohn.Forte@Sun.COM 	fcmd->resp_pwwn = fport->fcipp_pwwn;
2709*7836SJohn.Forte@Sun.COM 	fcmd->resp_nwwn = fport->fcipp_nwwn;
2710*7836SJohn.Forte@Sun.COM 
2711*7836SJohn.Forte@Sun.COM 	fcip_init_unicast_pkt(fcip_pkt, fport->fcipp_sid,
2712*7836SJohn.Forte@Sun.COM 	    fcmd->req_id, NULL);
2713*7836SJohn.Forte@Sun.COM 
2714*7836SJohn.Forte@Sun.COM 	fca_dev =
2715*7836SJohn.Forte@Sun.COM 	    fc_ulp_get_fca_device(fport->fcipp_handle, fcmd->req_id);
2716*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
2717*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_RSP;
2718*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_fca_device = fca_dev;
2719*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dest = fdestp;
2720*7836SJohn.Forte@Sun.COM 
2721*7836SJohn.Forte@Sun.COM 	/*
2722*7836SJohn.Forte@Sun.COM 	 * Attempt a PLOGI again
2723*7836SJohn.Forte@Sun.COM 	 */
2724*7836SJohn.Forte@Sun.COM 	if (fcmd->resp_flags & FARP_INIT_P_LOGI) {
2725*7836SJohn.Forte@Sun.COM 		if (fcip_do_plogi(fptr, frp) != FC_SUCCESS) {
2726*7836SJohn.Forte@Sun.COM 			/*
2727*7836SJohn.Forte@Sun.COM 			 * Login to the remote port failed. There is no
2728*7836SJohn.Forte@Sun.COM 			 * point continuing with the FARP request further
2729*7836SJohn.Forte@Sun.COM 			 * so bail out here.
2730*7836SJohn.Forte@Sun.COM 			 */
2731*7836SJohn.Forte@Sun.COM 			frp->fcipr_state = PORT_DEVICE_INVALID;
2732*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2733*7836SJohn.Forte@Sun.COM 			goto farp_done;
2734*7836SJohn.Forte@Sun.COM 		}
2735*7836SJohn.Forte@Sun.COM 	}
2736*7836SJohn.Forte@Sun.COM 
2737*7836SJohn.Forte@Sun.COM 	FCIP_CP_OUT(fcmd, fc_pkt->pkt_cmd, fc_pkt->pkt_cmd_acc,
2738*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_farp_t));
2739*7836SJohn.Forte@Sun.COM 
2740*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_issue_els(fport->fcipp_handle, fc_pkt);
2741*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
2742*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_2((fcip_handle_farp_request, "fcip io",
2743*7836SJohn.Forte@Sun.COM 		    /* CSTYLED */, tnf_string, msg,
2744*7836SJohn.Forte@Sun.COM 		    "fcip_transport of farp reply failed",
2745*7836SJohn.Forte@Sun.COM 		    tnf_uint, rval, rval));
2746*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_WARN,
2747*7836SJohn.Forte@Sun.COM 		    "fcip_transport of farp reply failed 0x%x", rval));
2748*7836SJohn.Forte@Sun.COM 	}
2749*7836SJohn.Forte@Sun.COM 
2750*7836SJohn.Forte@Sun.COM farp_done:
2751*7836SJohn.Forte@Sun.COM 	return (rval);
2752*7836SJohn.Forte@Sun.COM }
2753*7836SJohn.Forte@Sun.COM 
2754*7836SJohn.Forte@Sun.COM 
2755*7836SJohn.Forte@Sun.COM /*
2756*7836SJohn.Forte@Sun.COM  * Handle FARP responses to our FARP requests. When we receive a FARP
2757*7836SJohn.Forte@Sun.COM  * reply, we need to add the entry for the Port that replied into our
2758*7836SJohn.Forte@Sun.COM  * routing and destination hash tables. It is possible that the remote
2759*7836SJohn.Forte@Sun.COM  * port did not login into us (FARP responses can be received without
2760*7836SJohn.Forte@Sun.COM  * a PLOGI)
2761*7836SJohn.Forte@Sun.COM  */
2762*7836SJohn.Forte@Sun.COM static int
fcip_handle_farp_response(struct fcip * fptr,la_els_farp_t * fcmd)2763*7836SJohn.Forte@Sun.COM fcip_handle_farp_response(struct fcip *fptr, la_els_farp_t *fcmd)
2764*7836SJohn.Forte@Sun.COM {
2765*7836SJohn.Forte@Sun.COM 	int			rval = FC_FAILURE;
2766*7836SJohn.Forte@Sun.COM 	fc_portmap_t 		map;
2767*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table *frp;
2768*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp;
2769*7836SJohn.Forte@Sun.COM 
2770*7836SJohn.Forte@Sun.COM 	/*
2771*7836SJohn.Forte@Sun.COM 	 * Add an entry for the remote port into our routing and destination
2772*7836SJohn.Forte@Sun.COM 	 * tables.
2773*7836SJohn.Forte@Sun.COM 	 */
2774*7836SJohn.Forte@Sun.COM 	map.map_did = fcmd->dest_id;
2775*7836SJohn.Forte@Sun.COM 	map.map_hard_addr.hard_addr = fcmd->dest_id.port_id;
2776*7836SJohn.Forte@Sun.COM 	map.map_state = PORT_DEVICE_VALID;
2777*7836SJohn.Forte@Sun.COM 	map.map_type = PORT_DEVICE_NEW;
2778*7836SJohn.Forte@Sun.COM 	map.map_flags = 0;
2779*7836SJohn.Forte@Sun.COM 	map.map_pd = NULL;
2780*7836SJohn.Forte@Sun.COM 	bcopy((void *)&fcmd->resp_pwwn, (void *)&map.map_pwwn,
2781*7836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t));
2782*7836SJohn.Forte@Sun.COM 	bcopy((void *)&fcmd->resp_nwwn, (void *)&map.map_nwwn,
2783*7836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t));
2784*7836SJohn.Forte@Sun.COM 	fcip_rt_update(fptr, &map, 1);
2785*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
2786*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, &fcmd->resp_pwwn, FCIP_COMPARE_NWWN);
2787*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
2788*7836SJohn.Forte@Sun.COM 
2789*7836SJohn.Forte@Sun.COM 	fdestp = fcip_add_dest(fptr, frp);
2790*7836SJohn.Forte@Sun.COM 
2791*7836SJohn.Forte@Sun.COM 	if (fdestp != NULL) {
2792*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
2793*7836SJohn.Forte@Sun.COM 	}
2794*7836SJohn.Forte@Sun.COM 	return (rval);
2795*7836SJohn.Forte@Sun.COM }
2796*7836SJohn.Forte@Sun.COM 
2797*7836SJohn.Forte@Sun.COM 
2798*7836SJohn.Forte@Sun.COM #define	FCIP_HDRS_LENGTH	\
2799*7836SJohn.Forte@Sun.COM 	sizeof (fcph_network_hdr_t)+sizeof (llc_snap_hdr_t)+sizeof (ipha_t)
2800*7836SJohn.Forte@Sun.COM 
2801*7836SJohn.Forte@Sun.COM /*
2802*7836SJohn.Forte@Sun.COM  * fcip_data_cb is the heart of most IP operations. This routine is called
2803*7836SJohn.Forte@Sun.COM  * by the transport when any unsolicited IP data arrives at a port (which
2804*7836SJohn.Forte@Sun.COM  * is almost all IP data). This routine then strips off the Network header
2805*7836SJohn.Forte@Sun.COM  * from the payload (after authenticating the received payload ofcourse),
2806*7836SJohn.Forte@Sun.COM  * creates a message blk and sends the data upstream. You will see ugly
2807*7836SJohn.Forte@Sun.COM  * #defines because of problems with using esballoc() as opposed to
2808*7836SJohn.Forte@Sun.COM  * allocb to prevent an extra copy of data. We should probably move to
2809*7836SJohn.Forte@Sun.COM  * esballoc entirely when the MTU eventually will be larger than 1500 bytes
2810*7836SJohn.Forte@Sun.COM  * since copies will get more expensive then. At 1500 byte MTUs, there is
2811*7836SJohn.Forte@Sun.COM  * no noticable difference between using allocb and esballoc. The other
2812*7836SJohn.Forte@Sun.COM  * caveat is that the qlc firmware still cannot tell us accurately the
2813*7836SJohn.Forte@Sun.COM  * no. of valid bytes in the unsol buffer it DMA'ed so we have to resort
2814*7836SJohn.Forte@Sun.COM  * to looking into the IP header and hoping that the no. of bytes speficified
2815*7836SJohn.Forte@Sun.COM  * in the header was actually received.
2816*7836SJohn.Forte@Sun.COM  */
2817*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2818*7836SJohn.Forte@Sun.COM static int
fcip_data_cb(opaque_t ulp_handle,opaque_t phandle,fc_unsol_buf_t * buf,uint32_t claimed)2819*7836SJohn.Forte@Sun.COM fcip_data_cb(opaque_t ulp_handle, opaque_t phandle,
2820*7836SJohn.Forte@Sun.COM     fc_unsol_buf_t *buf, uint32_t claimed)
2821*7836SJohn.Forte@Sun.COM {
2822*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport;
2823*7836SJohn.Forte@Sun.COM 	struct fcip 			*fptr;
2824*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t		*nhdr;
2825*7836SJohn.Forte@Sun.COM 	llc_snap_hdr_t			*snaphdr;
2826*7836SJohn.Forte@Sun.COM 	mblk_t				*bp;
2827*7836SJohn.Forte@Sun.COM 	uint32_t 			len;
2828*7836SJohn.Forte@Sun.COM 	uint32_t			hdrlen;
2829*7836SJohn.Forte@Sun.COM 	ushort_t			type;
2830*7836SJohn.Forte@Sun.COM 	ipha_t				*iphdr;
2831*7836SJohn.Forte@Sun.COM 	int				rval;
2832*7836SJohn.Forte@Sun.COM 
2833*7836SJohn.Forte@Sun.COM #ifdef FCIP_ESBALLOC
2834*7836SJohn.Forte@Sun.COM 	frtn_t				*free_ubuf;
2835*7836SJohn.Forte@Sun.COM 	struct fcip_esballoc_arg	*fesb_argp;
2836*7836SJohn.Forte@Sun.COM #endif /* FCIP_ESBALLOC */
2837*7836SJohn.Forte@Sun.COM 
2838*7836SJohn.Forte@Sun.COM 	fport = fcip_get_port(phandle);
2839*7836SJohn.Forte@Sun.COM 	if (fport == NULL) {
2840*7836SJohn.Forte@Sun.COM 		return (FC_UNCLAIMED);
2841*7836SJohn.Forte@Sun.COM 	}
2842*7836SJohn.Forte@Sun.COM 
2843*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
2844*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
2845*7836SJohn.Forte@Sun.COM 
2846*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
2847*7836SJohn.Forte@Sun.COM 		return (FC_UNCLAIMED);
2848*7836SJohn.Forte@Sun.COM 	}
2849*7836SJohn.Forte@Sun.COM 
2850*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
2851*7836SJohn.Forte@Sun.COM 	if ((fptr->fcip_flags & (FCIP_DETACHING | FCIP_DETACHED)) ||
2852*7836SJohn.Forte@Sun.COM 	    (fptr->fcip_flags & (FCIP_SUSPENDED | FCIP_POWER_DOWN))) {
2853*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
2854*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2855*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2856*7836SJohn.Forte@Sun.COM 	}
2857*7836SJohn.Forte@Sun.COM 
2858*7836SJohn.Forte@Sun.COM 	/*
2859*7836SJohn.Forte@Sun.COM 	 * set fcip flags to indicate we are in the middle of a
2860*7836SJohn.Forte@Sun.COM 	 * data callback so we can wait till the statechange
2861*7836SJohn.Forte@Sun.COM 	 * is handled before succeeding/failing the SUSPEND/POWER DOWN.
2862*7836SJohn.Forte@Sun.COM 	 */
2863*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags |= FCIP_IN_DATA_CB;
2864*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
2865*7836SJohn.Forte@Sun.COM 
2866*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_data_cb, "fcip io", /* CSTYLED */,
2867*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "data callback",
2868*7836SJohn.Forte@Sun.COM 		tnf_int, instance, ddi_get_instance(fport->fcipp_dip)));
2869*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2870*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "fcip%d, data callback",
2871*7836SJohn.Forte@Sun.COM 	    ddi_get_instance(fport->fcipp_dip)));
2872*7836SJohn.Forte@Sun.COM 
2873*7836SJohn.Forte@Sun.COM 	/*
2874*7836SJohn.Forte@Sun.COM 	 * get to the network and snap headers in the payload
2875*7836SJohn.Forte@Sun.COM 	 */
2876*7836SJohn.Forte@Sun.COM 	nhdr = (fcph_network_hdr_t *)buf->ub_buffer;
2877*7836SJohn.Forte@Sun.COM 	snaphdr = (llc_snap_hdr_t *)(buf->ub_buffer +
2878*7836SJohn.Forte@Sun.COM 	    sizeof (fcph_network_hdr_t));
2879*7836SJohn.Forte@Sun.COM 
2880*7836SJohn.Forte@Sun.COM 	hdrlen = sizeof (fcph_network_hdr_t) + sizeof (llc_snap_hdr_t);
2881*7836SJohn.Forte@Sun.COM 
2882*7836SJohn.Forte@Sun.COM 	/*
2883*7836SJohn.Forte@Sun.COM 	 * get the IP header to obtain the no. of bytes we need to read
2884*7836SJohn.Forte@Sun.COM 	 * off from the unsol buffer. This obviously is because not all
2885*7836SJohn.Forte@Sun.COM 	 * data fills up the unsol buffer completely and the firmware
2886*7836SJohn.Forte@Sun.COM 	 * doesn't tell us how many valid bytes are in there as well
2887*7836SJohn.Forte@Sun.COM 	 */
2888*7836SJohn.Forte@Sun.COM 	iphdr = (ipha_t *)(buf->ub_buffer + hdrlen);
2889*7836SJohn.Forte@Sun.COM 	snaphdr->pid = BE_16(snaphdr->pid);
2890*7836SJohn.Forte@Sun.COM 	type = snaphdr->pid;
2891*7836SJohn.Forte@Sun.COM 
2892*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2893*7836SJohn.Forte@Sun.COM 	    (CE_CONT, "SNAPHDR: dsap %x, ssap %x, ctrl %x\n",
2894*7836SJohn.Forte@Sun.COM 	    snaphdr->dsap, snaphdr->ssap, snaphdr->ctrl));
2895*7836SJohn.Forte@Sun.COM 
2896*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2897*7836SJohn.Forte@Sun.COM 	    (CE_CONT, "oui[0] 0x%x oui[1] 0x%x oui[2] 0x%x pid 0x%x\n",
2898*7836SJohn.Forte@Sun.COM 	    snaphdr->oui[0], snaphdr->oui[1], snaphdr->oui[2], snaphdr->pid));
2899*7836SJohn.Forte@Sun.COM 
2900*7836SJohn.Forte@Sun.COM 	/* Authneticate, Authenticate */
2901*7836SJohn.Forte@Sun.COM 	if (type == ETHERTYPE_IP) {
2902*7836SJohn.Forte@Sun.COM 		len = hdrlen + BE_16(iphdr->ipha_length);
2903*7836SJohn.Forte@Sun.COM 	} else if (type == ETHERTYPE_ARP) {
2904*7836SJohn.Forte@Sun.COM 		len = hdrlen + 28;
2905*7836SJohn.Forte@Sun.COM 	} else {
2906*7836SJohn.Forte@Sun.COM 		len = buf->ub_bufsize;
2907*7836SJohn.Forte@Sun.COM 	}
2908*7836SJohn.Forte@Sun.COM 
2909*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2910*7836SJohn.Forte@Sun.COM 	    (CE_CONT, "effective packet length is %d bytes.\n", len));
2911*7836SJohn.Forte@Sun.COM 
2912*7836SJohn.Forte@Sun.COM 	if (len < hdrlen || len > FCIP_UB_SIZE) {
2913*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2914*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Incorrect buffer size %d bytes", len));
2915*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2916*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2917*7836SJohn.Forte@Sun.COM 	}
2918*7836SJohn.Forte@Sun.COM 
2919*7836SJohn.Forte@Sun.COM 	if (buf->ub_frame.type != FC_TYPE_IS8802_SNAP) {
2920*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM, (CE_NOTE, "Not IP/ARP data"));
2921*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2922*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2923*7836SJohn.Forte@Sun.COM 	}
2924*7836SJohn.Forte@Sun.COM 
2925*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM, (CE_NOTE, "checking wwn"));
2926*7836SJohn.Forte@Sun.COM 
2927*7836SJohn.Forte@Sun.COM 	if ((fcip_wwn_compare(&nhdr->net_dest_addr, &fport->fcipp_pwwn,
2928*7836SJohn.Forte@Sun.COM 	    FCIP_COMPARE_NWWN) != 0) &&
2929*7836SJohn.Forte@Sun.COM 	    (!IS_BROADCAST_ADDR(&nhdr->net_dest_addr))) {
2930*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2931*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2932*7836SJohn.Forte@Sun.COM 	} else if (fcip_cache_on_arp_broadcast &&
2933*7836SJohn.Forte@Sun.COM 	    IS_BROADCAST_ADDR(&nhdr->net_dest_addr)) {
2934*7836SJohn.Forte@Sun.COM 		fcip_cache_arp_broadcast(fptr, buf);
2935*7836SJohn.Forte@Sun.COM 	}
2936*7836SJohn.Forte@Sun.COM 
2937*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM, (CE_NOTE, "Allocate streams block"));
2938*7836SJohn.Forte@Sun.COM 
2939*7836SJohn.Forte@Sun.COM 	/*
2940*7836SJohn.Forte@Sun.COM 	 * Using esballoc instead of allocb should be faster, atleast at
2941*7836SJohn.Forte@Sun.COM 	 * larger MTUs than 1500 bytes. Someday we'll get there :)
2942*7836SJohn.Forte@Sun.COM 	 */
2943*7836SJohn.Forte@Sun.COM #if defined(FCIP_ESBALLOC)
2944*7836SJohn.Forte@Sun.COM 	/*
2945*7836SJohn.Forte@Sun.COM 	 * allocate memory for the frtn function arg. The Function
2946*7836SJohn.Forte@Sun.COM 	 * (fcip_ubfree) arg is a struct fcip_esballoc_arg type
2947*7836SJohn.Forte@Sun.COM 	 * which contains pointers to the unsol buffer and the
2948*7836SJohn.Forte@Sun.COM 	 * opaque port handle for releasing the unsol buffer back to
2949*7836SJohn.Forte@Sun.COM 	 * the FCA for reuse
2950*7836SJohn.Forte@Sun.COM 	 */
2951*7836SJohn.Forte@Sun.COM 	fesb_argp = (struct fcip_esballoc_arg *)
2952*7836SJohn.Forte@Sun.COM 	    kmem_zalloc(sizeof (struct fcip_esballoc_arg), KM_NOSLEEP);
2953*7836SJohn.Forte@Sun.COM 
2954*7836SJohn.Forte@Sun.COM 	if (fesb_argp == NULL) {
2955*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2956*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "esballoc of mblk failed in data_cb"));
2957*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2958*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2959*7836SJohn.Forte@Sun.COM 	}
2960*7836SJohn.Forte@Sun.COM 	/*
2961*7836SJohn.Forte@Sun.COM 	 * Check with KM_NOSLEEP
2962*7836SJohn.Forte@Sun.COM 	 */
2963*7836SJohn.Forte@Sun.COM 	free_ubuf = (frtn_t *)kmem_zalloc(sizeof (frtn_t), KM_NOSLEEP);
2964*7836SJohn.Forte@Sun.COM 	if (free_ubuf == NULL) {
2965*7836SJohn.Forte@Sun.COM 		kmem_free(fesb_argp, sizeof (struct fcip_esballoc_arg));
2966*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2967*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "esballoc of mblk failed in data_cb"));
2968*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2969*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2970*7836SJohn.Forte@Sun.COM 	}
2971*7836SJohn.Forte@Sun.COM 
2972*7836SJohn.Forte@Sun.COM 	fesb_argp->frtnp = free_ubuf;
2973*7836SJohn.Forte@Sun.COM 	fesb_argp->buf = buf;
2974*7836SJohn.Forte@Sun.COM 	fesb_argp->phandle = phandle;
2975*7836SJohn.Forte@Sun.COM 	free_ubuf->free_func = fcip_ubfree;
2976*7836SJohn.Forte@Sun.COM 	free_ubuf->free_arg = (char *)fesb_argp;
2977*7836SJohn.Forte@Sun.COM 	if ((bp = (mblk_t *)esballoc((unsigned char *)buf->ub_buffer,
2978*7836SJohn.Forte@Sun.COM 	    len, BPRI_MED, free_ubuf)) == NULL) {
2979*7836SJohn.Forte@Sun.COM 		kmem_free(fesb_argp, sizeof (struct fcip_esballoc_arg));
2980*7836SJohn.Forte@Sun.COM 		kmem_free(free_ubuf, sizeof (frtn_t));
2981*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2982*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "esballoc of mblk failed in data_cb"));
2983*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2984*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2985*7836SJohn.Forte@Sun.COM 	}
2986*7836SJohn.Forte@Sun.COM #elif !defined(FCIP_ESBALLOC)
2987*7836SJohn.Forte@Sun.COM 	/*
2988*7836SJohn.Forte@Sun.COM 	 * allocate streams mblk and copy the contents of the
2989*7836SJohn.Forte@Sun.COM 	 * unsolicited buffer into this newly alloc'ed mblk
2990*7836SJohn.Forte@Sun.COM 	 */
2991*7836SJohn.Forte@Sun.COM 	if ((bp = (mblk_t *)fcip_allocb((size_t)len, BPRI_LO)) == NULL) {
2992*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
2993*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "alloc of mblk failed in data_cb"));
2994*7836SJohn.Forte@Sun.COM 		rval = FC_UNCLAIMED;
2995*7836SJohn.Forte@Sun.COM 		goto data_cb_done;
2996*7836SJohn.Forte@Sun.COM 	}
2997*7836SJohn.Forte@Sun.COM 
2998*7836SJohn.Forte@Sun.COM 	/*
2999*7836SJohn.Forte@Sun.COM 	 * Unsolicited buffers handed up to us from the FCA must be
3000*7836SJohn.Forte@Sun.COM 	 * endian clean so just bcopy the data into our mblk. Else
3001*7836SJohn.Forte@Sun.COM 	 * we may have to either copy the data byte by byte or
3002*7836SJohn.Forte@Sun.COM 	 * use the ddi_rep_get* routines to do the copy for us.
3003*7836SJohn.Forte@Sun.COM 	 */
3004*7836SJohn.Forte@Sun.COM 	bcopy(buf->ub_buffer, bp->b_rptr, len);
3005*7836SJohn.Forte@Sun.COM 
3006*7836SJohn.Forte@Sun.COM 	/*
3007*7836SJohn.Forte@Sun.COM 	 * for esballoc'ed mblks - free the UB in the frtn function
3008*7836SJohn.Forte@Sun.COM 	 * along with the memory allocated for the function arg.
3009*7836SJohn.Forte@Sun.COM 	 * for allocb'ed mblk - release the unsolicited buffer here
3010*7836SJohn.Forte@Sun.COM 	 */
3011*7836SJohn.Forte@Sun.COM 	(void) fc_ulp_ubrelease(phandle, 1, &buf->ub_token);
3012*7836SJohn.Forte@Sun.COM 
3013*7836SJohn.Forte@Sun.COM #endif	/* FCIP_ESBALLOC */
3014*7836SJohn.Forte@Sun.COM 
3015*7836SJohn.Forte@Sun.COM 	bp->b_wptr = bp->b_rptr + len;
3016*7836SJohn.Forte@Sun.COM 	fptr->fcip_ipackets++;
3017*7836SJohn.Forte@Sun.COM 
3018*7836SJohn.Forte@Sun.COM 	if (type == ETHERTYPE_IP) {
3019*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
3020*7836SJohn.Forte@Sun.COM 		fptr->fcip_ub_upstream++;
3021*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
3022*7836SJohn.Forte@Sun.COM 		bp->b_rptr += hdrlen;
3023*7836SJohn.Forte@Sun.COM 
3024*7836SJohn.Forte@Sun.COM 		/*
3025*7836SJohn.Forte@Sun.COM 		 * Check if ipq is valid in the sendup thread
3026*7836SJohn.Forte@Sun.COM 		 */
3027*7836SJohn.Forte@Sun.COM 		if (fcip_sendup_alloc_enque(fptr, bp, NULL) != FC_SUCCESS) {
3028*7836SJohn.Forte@Sun.COM 			freemsg(bp);
3029*7836SJohn.Forte@Sun.COM 		}
3030*7836SJohn.Forte@Sun.COM 	} else {
3031*7836SJohn.Forte@Sun.COM 		/*
3032*7836SJohn.Forte@Sun.COM 		 * We won't get ethernet 802.3 packets in FCIP but we may get
3033*7836SJohn.Forte@Sun.COM 		 * types other than ETHERTYPE_IP, such as ETHERTYPE_ARP. Let
3034*7836SJohn.Forte@Sun.COM 		 * fcip_sendup() do the matching.
3035*7836SJohn.Forte@Sun.COM 		 */
3036*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
3037*7836SJohn.Forte@Sun.COM 		fptr->fcip_ub_upstream++;
3038*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
3039*7836SJohn.Forte@Sun.COM 		if (fcip_sendup_alloc_enque(fptr, bp,
3040*7836SJohn.Forte@Sun.COM 		    fcip_accept) != FC_SUCCESS) {
3041*7836SJohn.Forte@Sun.COM 			freemsg(bp);
3042*7836SJohn.Forte@Sun.COM 		}
3043*7836SJohn.Forte@Sun.COM 	}
3044*7836SJohn.Forte@Sun.COM 
3045*7836SJohn.Forte@Sun.COM 	rval = FC_SUCCESS;
3046*7836SJohn.Forte@Sun.COM 
3047*7836SJohn.Forte@Sun.COM 	/*
3048*7836SJohn.Forte@Sun.COM 	 * Unset fcip_flags to indicate we are out of callback and return
3049*7836SJohn.Forte@Sun.COM 	 */
3050*7836SJohn.Forte@Sun.COM data_cb_done:
3051*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
3052*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~(FCIP_IN_DATA_CB);
3053*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
3054*7836SJohn.Forte@Sun.COM 	return (rval);
3055*7836SJohn.Forte@Sun.COM }
3056*7836SJohn.Forte@Sun.COM 
3057*7836SJohn.Forte@Sun.COM #if !defined(FCIP_ESBALLOC)
3058*7836SJohn.Forte@Sun.COM /*
3059*7836SJohn.Forte@Sun.COM  * Allocate a message block for the inbound data to be sent upstream.
3060*7836SJohn.Forte@Sun.COM  */
3061*7836SJohn.Forte@Sun.COM static void *
fcip_allocb(size_t size,uint_t pri)3062*7836SJohn.Forte@Sun.COM fcip_allocb(size_t size, uint_t pri)
3063*7836SJohn.Forte@Sun.COM {
3064*7836SJohn.Forte@Sun.COM 	mblk_t	*mp;
3065*7836SJohn.Forte@Sun.COM 
3066*7836SJohn.Forte@Sun.COM 	if ((mp = allocb(size, pri)) == NULL) {
3067*7836SJohn.Forte@Sun.COM 		return (NULL);
3068*7836SJohn.Forte@Sun.COM 	}
3069*7836SJohn.Forte@Sun.COM 	return (mp);
3070*7836SJohn.Forte@Sun.COM }
3071*7836SJohn.Forte@Sun.COM 
3072*7836SJohn.Forte@Sun.COM #endif
3073*7836SJohn.Forte@Sun.COM 
3074*7836SJohn.Forte@Sun.COM /*
3075*7836SJohn.Forte@Sun.COM  * This helper routine kmem cache alloc's a sendup element for enquing
3076*7836SJohn.Forte@Sun.COM  * into the sendup list for callbacks upstream from the dedicated sendup
3077*7836SJohn.Forte@Sun.COM  * thread. We enque the msg buf into the sendup list and cv_signal the
3078*7836SJohn.Forte@Sun.COM  * sendup thread to finish the callback for us.
3079*7836SJohn.Forte@Sun.COM  */
3080*7836SJohn.Forte@Sun.COM static int
fcip_sendup_alloc_enque(struct fcip * fptr,mblk_t * mp,struct fcipstr * (* f)())3081*7836SJohn.Forte@Sun.COM fcip_sendup_alloc_enque(struct fcip *fptr, mblk_t *mp, struct fcipstr *(*f)())
3082*7836SJohn.Forte@Sun.COM {
3083*7836SJohn.Forte@Sun.COM 	struct fcip_sendup_elem 	*msg_elem;
3084*7836SJohn.Forte@Sun.COM 	int				rval = FC_FAILURE;
3085*7836SJohn.Forte@Sun.COM 
3086*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_sendup_alloc_enque, "fcip io", /* CSTYLED */,
3087*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "sendup msg enque"));
3088*7836SJohn.Forte@Sun.COM 	msg_elem = kmem_cache_alloc(fptr->fcip_sendup_cache, KM_NOSLEEP);
3089*7836SJohn.Forte@Sun.COM 	if (msg_elem == NULL) {
3090*7836SJohn.Forte@Sun.COM 		/* drop pkt to floor - update stats */
3091*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
3092*7836SJohn.Forte@Sun.COM 		goto sendup_alloc_done;
3093*7836SJohn.Forte@Sun.COM 	}
3094*7836SJohn.Forte@Sun.COM 	msg_elem->fcipsu_mp = mp;
3095*7836SJohn.Forte@Sun.COM 	msg_elem->fcipsu_func = f;
3096*7836SJohn.Forte@Sun.COM 
3097*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_sendup_mutex);
3098*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_sendup_head == NULL) {
3099*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_head = fptr->fcip_sendup_tail = msg_elem;
3100*7836SJohn.Forte@Sun.COM 	} else {
3101*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_tail->fcipsu_next = msg_elem;
3102*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_tail = msg_elem;
3103*7836SJohn.Forte@Sun.COM 	}
3104*7836SJohn.Forte@Sun.COM 	fptr->fcip_sendup_cnt++;
3105*7836SJohn.Forte@Sun.COM 	cv_signal(&fptr->fcip_sendup_cv);
3106*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_sendup_mutex);
3107*7836SJohn.Forte@Sun.COM 	rval = FC_SUCCESS;
3108*7836SJohn.Forte@Sun.COM 
3109*7836SJohn.Forte@Sun.COM sendup_alloc_done:
3110*7836SJohn.Forte@Sun.COM 	return (rval);
3111*7836SJohn.Forte@Sun.COM }
3112*7836SJohn.Forte@Sun.COM 
3113*7836SJohn.Forte@Sun.COM /*
3114*7836SJohn.Forte@Sun.COM  * One of the ways of performing the WWN to D_ID mapping required for
3115*7836SJohn.Forte@Sun.COM  * IPFC data is to cache the unsolicited ARP broadcast messages received
3116*7836SJohn.Forte@Sun.COM  * and update the routing table to add entry for the destination port
3117*7836SJohn.Forte@Sun.COM  * if we are the intended recipient of the ARP broadcast message. This is
3118*7836SJohn.Forte@Sun.COM  * one of the methods recommended in the rfc to obtain the WWN to D_ID mapping
3119*7836SJohn.Forte@Sun.COM  * but is not typically used unless enabled. The driver prefers to use the
3120*7836SJohn.Forte@Sun.COM  * nameserver/lilp map to obtain this mapping.
3121*7836SJohn.Forte@Sun.COM  */
3122*7836SJohn.Forte@Sun.COM static void
fcip_cache_arp_broadcast(struct fcip * fptr,fc_unsol_buf_t * buf)3123*7836SJohn.Forte@Sun.COM fcip_cache_arp_broadcast(struct fcip *fptr, fc_unsol_buf_t *buf)
3124*7836SJohn.Forte@Sun.COM {
3125*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport;
3126*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t		*nhdr;
3127*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table	*frp;
3128*7836SJohn.Forte@Sun.COM 	fc_portmap_t			map;
3129*7836SJohn.Forte@Sun.COM 
3130*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
3131*7836SJohn.Forte@Sun.COM 	if (fport == NULL) {
3132*7836SJohn.Forte@Sun.COM 		return;
3133*7836SJohn.Forte@Sun.COM 	}
3134*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
3135*7836SJohn.Forte@Sun.COM 
3136*7836SJohn.Forte@Sun.COM 	nhdr = (fcph_network_hdr_t *)buf->ub_buffer;
3137*7836SJohn.Forte@Sun.COM 
3138*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
3139*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, &nhdr->net_src_addr, FCIP_COMPARE_NWWN);
3140*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
3141*7836SJohn.Forte@Sun.COM 	if (frp == NULL) {
3142*7836SJohn.Forte@Sun.COM 		map.map_did.port_id = buf->ub_frame.s_id;
3143*7836SJohn.Forte@Sun.COM 		map.map_hard_addr.hard_addr = buf->ub_frame.s_id;
3144*7836SJohn.Forte@Sun.COM 		map.map_state = PORT_DEVICE_VALID;
3145*7836SJohn.Forte@Sun.COM 		map.map_type = PORT_DEVICE_NEW;
3146*7836SJohn.Forte@Sun.COM 		map.map_flags = 0;
3147*7836SJohn.Forte@Sun.COM 		map.map_pd = NULL;
3148*7836SJohn.Forte@Sun.COM 		bcopy((void *)&nhdr->net_src_addr, (void *)&map.map_pwwn,
3149*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
3150*7836SJohn.Forte@Sun.COM 		bcopy((void *)&nhdr->net_src_addr, (void *)&map.map_nwwn,
3151*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
3152*7836SJohn.Forte@Sun.COM 		fcip_rt_update(fptr, &map, 1);
3153*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
3154*7836SJohn.Forte@Sun.COM 		frp = fcip_lookup_rtable(fptr, &nhdr->net_src_addr,
3155*7836SJohn.Forte@Sun.COM 		    FCIP_COMPARE_NWWN);
3156*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
3157*7836SJohn.Forte@Sun.COM 
3158*7836SJohn.Forte@Sun.COM 		(void) fcip_add_dest(fptr, frp);
3159*7836SJohn.Forte@Sun.COM 	}
3160*7836SJohn.Forte@Sun.COM 
3161*7836SJohn.Forte@Sun.COM }
3162*7836SJohn.Forte@Sun.COM 
3163*7836SJohn.Forte@Sun.COM /*
3164*7836SJohn.Forte@Sun.COM  * This is a dedicated thread to do callbacks from fcip's data callback
3165*7836SJohn.Forte@Sun.COM  * routines into the modules upstream. The reason for this thread is
3166*7836SJohn.Forte@Sun.COM  * the data callback function can be called from an interrupt context and
3167*7836SJohn.Forte@Sun.COM  * the upstream modules *can* make calls downstream in the same thread
3168*7836SJohn.Forte@Sun.COM  * context. If the call is to a fabric port which is not yet in our
3169*7836SJohn.Forte@Sun.COM  * routing tables, we may have to query the nameserver/fabric for the
3170*7836SJohn.Forte@Sun.COM  * MAC addr to Port_ID mapping which may be blocking calls.
3171*7836SJohn.Forte@Sun.COM  */
3172*7836SJohn.Forte@Sun.COM static void
fcip_sendup_thr(void * arg)3173*7836SJohn.Forte@Sun.COM fcip_sendup_thr(void *arg)
3174*7836SJohn.Forte@Sun.COM {
3175*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr = (struct fcip *)arg;
3176*7836SJohn.Forte@Sun.COM 	struct fcip_sendup_elem	*msg_elem;
3177*7836SJohn.Forte@Sun.COM 	queue_t			*ip4q = NULL;
3178*7836SJohn.Forte@Sun.COM 
3179*7836SJohn.Forte@Sun.COM 	CALLB_CPR_INIT(&fptr->fcip_cpr_info, &fptr->fcip_sendup_mutex,
3180*7836SJohn.Forte@Sun.COM 	    callb_generic_cpr, "fcip_sendup_thr");
3181*7836SJohn.Forte@Sun.COM 
3182*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_sendup_mutex);
3183*7836SJohn.Forte@Sun.COM 	for (;;) {
3184*7836SJohn.Forte@Sun.COM 
3185*7836SJohn.Forte@Sun.COM 		while (fptr->fcip_sendup_thr_initted &&
3186*7836SJohn.Forte@Sun.COM 		    fptr->fcip_sendup_head == NULL) {
3187*7836SJohn.Forte@Sun.COM 			CALLB_CPR_SAFE_BEGIN(&fptr->fcip_cpr_info);
3188*7836SJohn.Forte@Sun.COM 			cv_wait(&fptr->fcip_sendup_cv,
3189*7836SJohn.Forte@Sun.COM 			    &fptr->fcip_sendup_mutex);
3190*7836SJohn.Forte@Sun.COM 			CALLB_CPR_SAFE_END(&fptr->fcip_cpr_info,
3191*7836SJohn.Forte@Sun.COM 			    &fptr->fcip_sendup_mutex);
3192*7836SJohn.Forte@Sun.COM 		}
3193*7836SJohn.Forte@Sun.COM 
3194*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_sendup_thr_initted == 0) {
3195*7836SJohn.Forte@Sun.COM 			break;
3196*7836SJohn.Forte@Sun.COM 		}
3197*7836SJohn.Forte@Sun.COM 
3198*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_sendup_thr, "fcip io", /* CSTYLED */,
3199*7836SJohn.Forte@Sun.COM 		    tnf_string, msg, "fcip sendup thr - new msg"));
3200*7836SJohn.Forte@Sun.COM 
3201*7836SJohn.Forte@Sun.COM 		msg_elem = fptr->fcip_sendup_head;
3202*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_head = msg_elem->fcipsu_next;
3203*7836SJohn.Forte@Sun.COM 		msg_elem->fcipsu_next = NULL;
3204*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_sendup_mutex);
3205*7836SJohn.Forte@Sun.COM 
3206*7836SJohn.Forte@Sun.COM 		if (msg_elem->fcipsu_func == NULL) {
3207*7836SJohn.Forte@Sun.COM 			/*
3208*7836SJohn.Forte@Sun.COM 			 * Message for ipq. Check to see if the ipq is
3209*7836SJohn.Forte@Sun.COM 			 * is still valid. Since the thread is asynchronous,
3210*7836SJohn.Forte@Sun.COM 			 * there could have been a close on the stream
3211*7836SJohn.Forte@Sun.COM 			 */
3212*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_mutex);
3213*7836SJohn.Forte@Sun.COM 			if (fptr->fcip_ipq && canputnext(fptr->fcip_ipq)) {
3214*7836SJohn.Forte@Sun.COM 				ip4q = fptr->fcip_ipq;
3215*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_mutex);
3216*7836SJohn.Forte@Sun.COM 				putnext(ip4q, msg_elem->fcipsu_mp);
3217*7836SJohn.Forte@Sun.COM 			} else {
3218*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_mutex);
3219*7836SJohn.Forte@Sun.COM 				freemsg(msg_elem->fcipsu_mp);
3220*7836SJohn.Forte@Sun.COM 			}
3221*7836SJohn.Forte@Sun.COM 		} else {
3222*7836SJohn.Forte@Sun.COM 			fcip_sendup(fptr, msg_elem->fcipsu_mp,
3223*7836SJohn.Forte@Sun.COM 			    msg_elem->fcipsu_func);
3224*7836SJohn.Forte@Sun.COM 		}
3225*7836SJohn.Forte@Sun.COM 
3226*7836SJohn.Forte@Sun.COM #if !defined(FCIP_ESBALLOC)
3227*7836SJohn.Forte@Sun.COM 		/*
3228*7836SJohn.Forte@Sun.COM 		 * for allocb'ed mblk - decrement upstream count here
3229*7836SJohn.Forte@Sun.COM 		 */
3230*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
3231*7836SJohn.Forte@Sun.COM 		ASSERT(fptr->fcip_ub_upstream > 0);
3232*7836SJohn.Forte@Sun.COM 		fptr->fcip_ub_upstream--;
3233*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
3234*7836SJohn.Forte@Sun.COM #endif /* FCIP_ESBALLOC */
3235*7836SJohn.Forte@Sun.COM 
3236*7836SJohn.Forte@Sun.COM 		kmem_cache_free(fptr->fcip_sendup_cache, (void *)msg_elem);
3237*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_sendup_mutex);
3238*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_cnt--;
3239*7836SJohn.Forte@Sun.COM 	}
3240*7836SJohn.Forte@Sun.COM 
3241*7836SJohn.Forte@Sun.COM 
3242*7836SJohn.Forte@Sun.COM #ifndef	__lock_lint
3243*7836SJohn.Forte@Sun.COM 	CALLB_CPR_EXIT(&fptr->fcip_cpr_info);
3244*7836SJohn.Forte@Sun.COM #else
3245*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_sendup_mutex);
3246*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */
3247*7836SJohn.Forte@Sun.COM 
3248*7836SJohn.Forte@Sun.COM 	/* Wake up fcip detach thread by the end */
3249*7836SJohn.Forte@Sun.COM 	cv_signal(&fptr->fcip_sendup_cv);
3250*7836SJohn.Forte@Sun.COM 
3251*7836SJohn.Forte@Sun.COM 	thread_exit();
3252*7836SJohn.Forte@Sun.COM }
3253*7836SJohn.Forte@Sun.COM 
3254*7836SJohn.Forte@Sun.COM #ifdef FCIP_ESBALLOC
3255*7836SJohn.Forte@Sun.COM 
3256*7836SJohn.Forte@Sun.COM /*
3257*7836SJohn.Forte@Sun.COM  * called from the stream head when it is done using an unsolicited buffer.
3258*7836SJohn.Forte@Sun.COM  * We release this buffer then to the FCA for reuse.
3259*7836SJohn.Forte@Sun.COM  */
3260*7836SJohn.Forte@Sun.COM static void
fcip_ubfree(char * arg)3261*7836SJohn.Forte@Sun.COM fcip_ubfree(char *arg)
3262*7836SJohn.Forte@Sun.COM {
3263*7836SJohn.Forte@Sun.COM 	struct fcip_esballoc_arg *fesb_argp = (struct fcip_esballoc_arg *)arg;
3264*7836SJohn.Forte@Sun.COM 	fc_unsol_buf_t	*ubuf;
3265*7836SJohn.Forte@Sun.COM 	frtn_t		*frtnp;
3266*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport;
3267*7836SJohn.Forte@Sun.COM 	struct fcip 			*fptr;
3268*7836SJohn.Forte@Sun.COM 
3269*7836SJohn.Forte@Sun.COM 
3270*7836SJohn.Forte@Sun.COM 	fport = fcip_get_port(fesb_argp->phandle);
3271*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
3272*7836SJohn.Forte@Sun.COM 
3273*7836SJohn.Forte@Sun.COM 	ASSERT(fesb_argp != NULL);
3274*7836SJohn.Forte@Sun.COM 	ubuf = fesb_argp->buf;
3275*7836SJohn.Forte@Sun.COM 	frtnp = fesb_argp->frtnp;
3276*7836SJohn.Forte@Sun.COM 
3277*7836SJohn.Forte@Sun.COM 
3278*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_UPSTREAM,
3279*7836SJohn.Forte@Sun.COM 	    (CE_WARN, "freeing ubuf after esballoc in fcip_ubfree"));
3280*7836SJohn.Forte@Sun.COM 	(void) fc_ulp_ubrelease(fesb_argp->phandle, 1, &ubuf->ub_token);
3281*7836SJohn.Forte@Sun.COM 
3282*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
3283*7836SJohn.Forte@Sun.COM 	ASSERT(fptr->fcip_ub_upstream > 0);
3284*7836SJohn.Forte@Sun.COM 	fptr->fcip_ub_upstream--;
3285*7836SJohn.Forte@Sun.COM 	cv_signal(&fptr->fcip_ub_cv);
3286*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
3287*7836SJohn.Forte@Sun.COM 
3288*7836SJohn.Forte@Sun.COM 	kmem_free(frtnp, sizeof (frtn_t));
3289*7836SJohn.Forte@Sun.COM 	kmem_free(fesb_argp, sizeof (struct fcip_esballoc_arg));
3290*7836SJohn.Forte@Sun.COM }
3291*7836SJohn.Forte@Sun.COM 
3292*7836SJohn.Forte@Sun.COM #endif /* FCIP_ESBALLOC */
3293*7836SJohn.Forte@Sun.COM 
3294*7836SJohn.Forte@Sun.COM /*
3295*7836SJohn.Forte@Sun.COM  * handle data other than that of type ETHERTYPE_IP and send it on its
3296*7836SJohn.Forte@Sun.COM  * way upstream to the right streams module to handle
3297*7836SJohn.Forte@Sun.COM  */
3298*7836SJohn.Forte@Sun.COM static void
fcip_sendup(struct fcip * fptr,mblk_t * mp,struct fcipstr * (* acceptfunc)())3299*7836SJohn.Forte@Sun.COM fcip_sendup(struct fcip *fptr, mblk_t *mp, struct fcipstr *(*acceptfunc)())
3300*7836SJohn.Forte@Sun.COM {
3301*7836SJohn.Forte@Sun.COM 	struct fcipstr	*slp, *nslp;
3302*7836SJohn.Forte@Sun.COM 	la_wwn_t	*dhostp;
3303*7836SJohn.Forte@Sun.COM 	mblk_t		*nmp;
3304*7836SJohn.Forte@Sun.COM 	uint32_t 	isgroupaddr;
3305*7836SJohn.Forte@Sun.COM 	int 		type;
3306*7836SJohn.Forte@Sun.COM 	uint32_t	hdrlen;
3307*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t	*nhdr;
3308*7836SJohn.Forte@Sun.COM 	llc_snap_hdr_t		*snaphdr;
3309*7836SJohn.Forte@Sun.COM 
3310*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_sendup, "fcip io", /* CSTYLED */,
3311*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "fcip sendup"));
3312*7836SJohn.Forte@Sun.COM 	nhdr = (fcph_network_hdr_t *)mp->b_rptr;
3313*7836SJohn.Forte@Sun.COM 	snaphdr =
3314*7836SJohn.Forte@Sun.COM 	    (llc_snap_hdr_t *)(mp->b_rptr + sizeof (fcph_network_hdr_t));
3315*7836SJohn.Forte@Sun.COM 	dhostp = &nhdr->net_dest_addr;
3316*7836SJohn.Forte@Sun.COM 	type = snaphdr->pid;
3317*7836SJohn.Forte@Sun.COM 	hdrlen = sizeof (fcph_network_hdr_t) + sizeof (llc_snap_hdr_t);
3318*7836SJohn.Forte@Sun.COM 
3319*7836SJohn.Forte@Sun.COM 	/* No group address with fibre channel */
3320*7836SJohn.Forte@Sun.COM 	isgroupaddr = 0;
3321*7836SJohn.Forte@Sun.COM 
3322*7836SJohn.Forte@Sun.COM 	/*
3323*7836SJohn.Forte@Sun.COM 	 * While holding a reader lock on the linked list of streams structures,
3324*7836SJohn.Forte@Sun.COM 	 * attempt to match the address criteria for each stream
3325*7836SJohn.Forte@Sun.COM 	 * and pass up the raw M_DATA ("fastpath") or a DL_UNITDATA_IND.
3326*7836SJohn.Forte@Sun.COM 	 */
3327*7836SJohn.Forte@Sun.COM 
3328*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_READER);
3329*7836SJohn.Forte@Sun.COM 
3330*7836SJohn.Forte@Sun.COM 	if ((slp = (*acceptfunc)(fcipstrup, fptr, type, dhostp)) == NULL) {
3331*7836SJohn.Forte@Sun.COM 		rw_exit(&fcipstruplock);
3332*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_sendup, "fcip io", /* CSTYLED */,
3333*7836SJohn.Forte@Sun.COM 		    tnf_string, msg, "fcip sendup - no slp"));
3334*7836SJohn.Forte@Sun.COM 		freemsg(mp);
3335*7836SJohn.Forte@Sun.COM 		return;
3336*7836SJohn.Forte@Sun.COM 	}
3337*7836SJohn.Forte@Sun.COM 
3338*7836SJohn.Forte@Sun.COM 	/*
3339*7836SJohn.Forte@Sun.COM 	 * Loop on matching open streams until (*acceptfunc)() returns NULL.
3340*7836SJohn.Forte@Sun.COM 	 */
3341*7836SJohn.Forte@Sun.COM 	for (; nslp = (*acceptfunc)(slp->sl_nextp, fptr, type, dhostp);
3342*7836SJohn.Forte@Sun.COM 	    slp = nslp) {
3343*7836SJohn.Forte@Sun.COM 		if (canputnext(slp->sl_rq)) {
3344*7836SJohn.Forte@Sun.COM 			if (nmp = dupmsg(mp)) {
3345*7836SJohn.Forte@Sun.COM 				if ((slp->sl_flags & FCIP_SLFAST) &&
3346*7836SJohn.Forte@Sun.COM 							!isgroupaddr) {
3347*7836SJohn.Forte@Sun.COM 					nmp->b_rptr += hdrlen;
3348*7836SJohn.Forte@Sun.COM 					putnext(slp->sl_rq, nmp);
3349*7836SJohn.Forte@Sun.COM 				} else if (slp->sl_flags & FCIP_SLRAW) {
3350*7836SJohn.Forte@Sun.COM 					/* No headers when FCIP_SLRAW is set */
3351*7836SJohn.Forte@Sun.COM 					putnext(slp->sl_rq, nmp);
3352*7836SJohn.Forte@Sun.COM 				} else if ((nmp = fcip_addudind(fptr, nmp,
3353*7836SJohn.Forte@Sun.COM 				    nhdr, type))) {
3354*7836SJohn.Forte@Sun.COM 					putnext(slp->sl_rq, nmp);
3355*7836SJohn.Forte@Sun.COM 				}
3356*7836SJohn.Forte@Sun.COM 			}
3357*7836SJohn.Forte@Sun.COM 		}
3358*7836SJohn.Forte@Sun.COM 	}
3359*7836SJohn.Forte@Sun.COM 
3360*7836SJohn.Forte@Sun.COM 	/*
3361*7836SJohn.Forte@Sun.COM 	 * Do the last one.
3362*7836SJohn.Forte@Sun.COM 	 */
3363*7836SJohn.Forte@Sun.COM 	if (canputnext(slp->sl_rq)) {
3364*7836SJohn.Forte@Sun.COM 		if (slp->sl_flags & FCIP_SLFAST) {
3365*7836SJohn.Forte@Sun.COM 			mp->b_rptr += hdrlen;
3366*7836SJohn.Forte@Sun.COM 			putnext(slp->sl_rq, mp);
3367*7836SJohn.Forte@Sun.COM 		} else if (slp->sl_flags & FCIP_SLRAW) {
3368*7836SJohn.Forte@Sun.COM 			putnext(slp->sl_rq, mp);
3369*7836SJohn.Forte@Sun.COM 		} else if ((mp = fcip_addudind(fptr, mp, nhdr, type))) {
3370*7836SJohn.Forte@Sun.COM 			putnext(slp->sl_rq, mp);
3371*7836SJohn.Forte@Sun.COM 		}
3372*7836SJohn.Forte@Sun.COM 	} else {
3373*7836SJohn.Forte@Sun.COM 		freemsg(mp);
3374*7836SJohn.Forte@Sun.COM 	}
3375*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_sendup, "fcip io", /* CSTYLED */,
3376*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip sendup done"));
3377*7836SJohn.Forte@Sun.COM 
3378*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
3379*7836SJohn.Forte@Sun.COM }
3380*7836SJohn.Forte@Sun.COM 
3381*7836SJohn.Forte@Sun.COM /*
3382*7836SJohn.Forte@Sun.COM  * Match the stream based on type and wwn if necessary.
3383*7836SJohn.Forte@Sun.COM  * Destination wwn dhostp is passed to this routine is reserved
3384*7836SJohn.Forte@Sun.COM  * for future usage. We don't need to use it right now since port
3385*7836SJohn.Forte@Sun.COM  * to fcip instance mapping is unique and wwn is already validated when
3386*7836SJohn.Forte@Sun.COM  * packet comes to fcip.
3387*7836SJohn.Forte@Sun.COM  */
3388*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3389*7836SJohn.Forte@Sun.COM static struct fcipstr *
fcip_accept(struct fcipstr * slp,struct fcip * fptr,int type,la_wwn_t * dhostp)3390*7836SJohn.Forte@Sun.COM fcip_accept(struct fcipstr *slp, struct fcip *fptr, int type, la_wwn_t *dhostp)
3391*7836SJohn.Forte@Sun.COM {
3392*7836SJohn.Forte@Sun.COM 	t_uscalar_t 	sap;
3393*7836SJohn.Forte@Sun.COM 
3394*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_accept, "fcip io", /* CSTYLED */,
3395*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip accept"));
3396*7836SJohn.Forte@Sun.COM 
3397*7836SJohn.Forte@Sun.COM 	for (; slp; slp = slp->sl_nextp) {
3398*7836SJohn.Forte@Sun.COM 		sap = slp->sl_sap;
3399*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_UPSTREAM, (CE_CONT,
3400*7836SJohn.Forte@Sun.COM 		    "fcip_accept: checking next sap = %x, type = %x",
3401*7836SJohn.Forte@Sun.COM 		    sap, type));
3402*7836SJohn.Forte@Sun.COM 
3403*7836SJohn.Forte@Sun.COM 		if ((slp->sl_fcip == fptr) && (type == sap)) {
3404*7836SJohn.Forte@Sun.COM 			return (slp);
3405*7836SJohn.Forte@Sun.COM 		}
3406*7836SJohn.Forte@Sun.COM 	}
3407*7836SJohn.Forte@Sun.COM 	return (NULL);
3408*7836SJohn.Forte@Sun.COM }
3409*7836SJohn.Forte@Sun.COM 
3410*7836SJohn.Forte@Sun.COM /*
3411*7836SJohn.Forte@Sun.COM  * Handle DL_UNITDATA_IND messages
3412*7836SJohn.Forte@Sun.COM  */
3413*7836SJohn.Forte@Sun.COM static mblk_t *
fcip_addudind(struct fcip * fptr,mblk_t * mp,fcph_network_hdr_t * nhdr,int type)3414*7836SJohn.Forte@Sun.COM fcip_addudind(struct fcip *fptr, mblk_t *mp, fcph_network_hdr_t *nhdr,
3415*7836SJohn.Forte@Sun.COM     int type)
3416*7836SJohn.Forte@Sun.COM {
3417*7836SJohn.Forte@Sun.COM 	dl_unitdata_ind_t	*dludindp;
3418*7836SJohn.Forte@Sun.COM 	struct	fcipdladdr	*dlap;
3419*7836SJohn.Forte@Sun.COM 	mblk_t	*nmp;
3420*7836SJohn.Forte@Sun.COM 	int	size;
3421*7836SJohn.Forte@Sun.COM 	uint32_t hdrlen;
3422*7836SJohn.Forte@Sun.COM 	struct ether_addr	src_addr;
3423*7836SJohn.Forte@Sun.COM 	struct ether_addr	dest_addr;
3424*7836SJohn.Forte@Sun.COM 
3425*7836SJohn.Forte@Sun.COM 
3426*7836SJohn.Forte@Sun.COM 	hdrlen = (sizeof (llc_snap_hdr_t) + sizeof (fcph_network_hdr_t));
3427*7836SJohn.Forte@Sun.COM 	mp->b_rptr += hdrlen;
3428*7836SJohn.Forte@Sun.COM 
3429*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_addudind, "fcip io", /* CSTYLED */,
3430*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip addudind"));
3431*7836SJohn.Forte@Sun.COM 
3432*7836SJohn.Forte@Sun.COM 	/*
3433*7836SJohn.Forte@Sun.COM 	 * Allocate an M_PROTO mblk for the DL_UNITDATA_IND.
3434*7836SJohn.Forte@Sun.COM 	 */
3435*7836SJohn.Forte@Sun.COM 	size = sizeof (dl_unitdata_ind_t) + FCIPADDRL + FCIPADDRL;
3436*7836SJohn.Forte@Sun.COM 	if ((nmp = allocb(size, BPRI_LO)) == NULL) {
3437*7836SJohn.Forte@Sun.COM 		fptr->fcip_allocbfail++;
3438*7836SJohn.Forte@Sun.COM 		freemsg(mp);
3439*7836SJohn.Forte@Sun.COM 		return (NULL);
3440*7836SJohn.Forte@Sun.COM 	}
3441*7836SJohn.Forte@Sun.COM 	DB_TYPE(nmp) = M_PROTO;
3442*7836SJohn.Forte@Sun.COM 	nmp->b_wptr = nmp->b_datap->db_lim;
3443*7836SJohn.Forte@Sun.COM 	nmp->b_rptr = nmp->b_wptr - size;
3444*7836SJohn.Forte@Sun.COM 
3445*7836SJohn.Forte@Sun.COM 	/*
3446*7836SJohn.Forte@Sun.COM 	 * Construct a DL_UNITDATA_IND primitive.
3447*7836SJohn.Forte@Sun.COM 	 */
3448*7836SJohn.Forte@Sun.COM 	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
3449*7836SJohn.Forte@Sun.COM 	dludindp->dl_primitive = DL_UNITDATA_IND;
3450*7836SJohn.Forte@Sun.COM 	dludindp->dl_dest_addr_length = FCIPADDRL;
3451*7836SJohn.Forte@Sun.COM 	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
3452*7836SJohn.Forte@Sun.COM 	dludindp->dl_src_addr_length = FCIPADDRL;
3453*7836SJohn.Forte@Sun.COM 	dludindp->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + FCIPADDRL;
3454*7836SJohn.Forte@Sun.COM 	dludindp->dl_group_address = 0;		/* not DL_MULTI */
3455*7836SJohn.Forte@Sun.COM 
3456*7836SJohn.Forte@Sun.COM 	dlap = (struct fcipdladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t));
3457*7836SJohn.Forte@Sun.COM 	wwn_to_ether(&nhdr->net_dest_addr, &dest_addr);
3458*7836SJohn.Forte@Sun.COM 	ether_bcopy(&dest_addr, &dlap->dl_phys);
3459*7836SJohn.Forte@Sun.COM 	dlap->dl_sap = (uint16_t)type;
3460*7836SJohn.Forte@Sun.COM 
3461*7836SJohn.Forte@Sun.COM 	dlap = (struct fcipdladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t)
3462*7836SJohn.Forte@Sun.COM 		+ FCIPADDRL);
3463*7836SJohn.Forte@Sun.COM 	wwn_to_ether(&nhdr->net_src_addr, &src_addr);
3464*7836SJohn.Forte@Sun.COM 	ether_bcopy(&src_addr, &dlap->dl_phys);
3465*7836SJohn.Forte@Sun.COM 	dlap->dl_sap = (uint16_t)type;
3466*7836SJohn.Forte@Sun.COM 
3467*7836SJohn.Forte@Sun.COM 	/*
3468*7836SJohn.Forte@Sun.COM 	 * Link the M_PROTO and M_DATA together.
3469*7836SJohn.Forte@Sun.COM 	 */
3470*7836SJohn.Forte@Sun.COM 	nmp->b_cont = mp;
3471*7836SJohn.Forte@Sun.COM 	return (nmp);
3472*7836SJohn.Forte@Sun.COM }
3473*7836SJohn.Forte@Sun.COM 
3474*7836SJohn.Forte@Sun.COM 
3475*7836SJohn.Forte@Sun.COM /*
3476*7836SJohn.Forte@Sun.COM  * The open routine. For clone opens, we return the next available minor
3477*7836SJohn.Forte@Sun.COM  * no. for the stream to use
3478*7836SJohn.Forte@Sun.COM  */
3479*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3480*7836SJohn.Forte@Sun.COM static int
fcip_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)3481*7836SJohn.Forte@Sun.COM fcip_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
3482*7836SJohn.Forte@Sun.COM {
3483*7836SJohn.Forte@Sun.COM 	struct fcipstr	*slp;
3484*7836SJohn.Forte@Sun.COM 	struct fcipstr	**prevslp;
3485*7836SJohn.Forte@Sun.COM 	minor_t	minor;
3486*7836SJohn.Forte@Sun.COM 
3487*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "in fcip_open"));
3488*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_open, "fcip io", /* CSTYLED */,
3489*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
3490*7836SJohn.Forte@Sun.COM 	/*
3491*7836SJohn.Forte@Sun.COM 	 * We need to ensure that the port driver is loaded before
3492*7836SJohn.Forte@Sun.COM 	 * we proceed
3493*7836SJohn.Forte@Sun.COM 	 */
3494*7836SJohn.Forte@Sun.COM 	if (ddi_hold_installed_driver(ddi_name_to_major(PORT_DRIVER)) == NULL) {
3495*7836SJohn.Forte@Sun.COM 		/* no port driver instances found */
3496*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_STARTUP, (CE_WARN,
3497*7836SJohn.Forte@Sun.COM 		    "!ddi_hold_installed_driver of fp failed\n"));
3498*7836SJohn.Forte@Sun.COM 		return (ENXIO);
3499*7836SJohn.Forte@Sun.COM 	}
3500*7836SJohn.Forte@Sun.COM 	/* serialize opens */
3501*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_WRITER);
3502*7836SJohn.Forte@Sun.COM 
3503*7836SJohn.Forte@Sun.COM 	prevslp = &fcipstrup;
3504*7836SJohn.Forte@Sun.COM 	if (sflag == CLONEOPEN) {
3505*7836SJohn.Forte@Sun.COM 		minor = 0;
3506*7836SJohn.Forte@Sun.COM 		for (; (slp = *prevslp) != NULL; prevslp = &slp->sl_nextp) {
3507*7836SJohn.Forte@Sun.COM 			if (minor < slp->sl_minor) {
3508*7836SJohn.Forte@Sun.COM 				break;
3509*7836SJohn.Forte@Sun.COM 			}
3510*7836SJohn.Forte@Sun.COM 			minor ++;
3511*7836SJohn.Forte@Sun.COM 		}
3512*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE,
3513*7836SJohn.Forte@Sun.COM 		    "getmajor returns 0x%x", getmajor(*devp)));
3514*7836SJohn.Forte@Sun.COM 		*devp = makedevice(getmajor(*devp), minor);
3515*7836SJohn.Forte@Sun.COM 	} else {
3516*7836SJohn.Forte@Sun.COM 		minor = getminor(*devp);
3517*7836SJohn.Forte@Sun.COM 	}
3518*7836SJohn.Forte@Sun.COM 
3519*7836SJohn.Forte@Sun.COM 	/*
3520*7836SJohn.Forte@Sun.COM 	 * check if our qp's private area is already initialized. If yes
3521*7836SJohn.Forte@Sun.COM 	 * the stream is already open - just return
3522*7836SJohn.Forte@Sun.COM 	 */
3523*7836SJohn.Forte@Sun.COM 	if (rq->q_ptr) {
3524*7836SJohn.Forte@Sun.COM 		goto done;
3525*7836SJohn.Forte@Sun.COM 	}
3526*7836SJohn.Forte@Sun.COM 
3527*7836SJohn.Forte@Sun.COM 	slp = GETSTRUCT(struct fcipstr, 1);
3528*7836SJohn.Forte@Sun.COM 	slp->sl_minor = minor;
3529*7836SJohn.Forte@Sun.COM 	slp->sl_rq = rq;
3530*7836SJohn.Forte@Sun.COM 	slp->sl_sap = 0;
3531*7836SJohn.Forte@Sun.COM 	slp->sl_flags = 0;
3532*7836SJohn.Forte@Sun.COM 	slp->sl_state = DL_UNATTACHED;
3533*7836SJohn.Forte@Sun.COM 	slp->sl_fcip = NULL;
3534*7836SJohn.Forte@Sun.COM 
3535*7836SJohn.Forte@Sun.COM 	mutex_init(&slp->sl_lock, NULL, MUTEX_DRIVER, NULL);
3536*7836SJohn.Forte@Sun.COM 
3537*7836SJohn.Forte@Sun.COM 	/*
3538*7836SJohn.Forte@Sun.COM 	 * link this new stream entry into list of active streams
3539*7836SJohn.Forte@Sun.COM 	 */
3540*7836SJohn.Forte@Sun.COM 	slp->sl_nextp = *prevslp;
3541*7836SJohn.Forte@Sun.COM 	*prevslp = slp;
3542*7836SJohn.Forte@Sun.COM 
3543*7836SJohn.Forte@Sun.COM 	rq->q_ptr = WR(rq)->q_ptr = (char *)slp;
3544*7836SJohn.Forte@Sun.COM 
3545*7836SJohn.Forte@Sun.COM 	/*
3546*7836SJohn.Forte@Sun.COM 	 * Disable automatic enabling of our write service procedures
3547*7836SJohn.Forte@Sun.COM 	 * we need to control this explicitly. This will prevent
3548*7836SJohn.Forte@Sun.COM 	 * anyone scheduling of our write service procedures.
3549*7836SJohn.Forte@Sun.COM 	 */
3550*7836SJohn.Forte@Sun.COM 	noenable(WR(rq));
3551*7836SJohn.Forte@Sun.COM 
3552*7836SJohn.Forte@Sun.COM done:
3553*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
3554*7836SJohn.Forte@Sun.COM 	/*
3555*7836SJohn.Forte@Sun.COM 	 * enable our put and service routines on the read side
3556*7836SJohn.Forte@Sun.COM 	 */
3557*7836SJohn.Forte@Sun.COM 	qprocson(rq);
3558*7836SJohn.Forte@Sun.COM 
3559*7836SJohn.Forte@Sun.COM 	/*
3560*7836SJohn.Forte@Sun.COM 	 * There is only one instance of fcip (instance = 0)
3561*7836SJohn.Forte@Sun.COM 	 * for multiple instances of hardware
3562*7836SJohn.Forte@Sun.COM 	 */
3563*7836SJohn.Forte@Sun.COM 	(void) qassociate(rq, 0);	/* don't allow drcompat to be pushed */
3564*7836SJohn.Forte@Sun.COM 	return (0);
3565*7836SJohn.Forte@Sun.COM }
3566*7836SJohn.Forte@Sun.COM 
3567*7836SJohn.Forte@Sun.COM /*
3568*7836SJohn.Forte@Sun.COM  * close an opened stream. The minor no. will then be available for
3569*7836SJohn.Forte@Sun.COM  * future opens.
3570*7836SJohn.Forte@Sun.COM  */
3571*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3572*7836SJohn.Forte@Sun.COM static int
fcip_close(queue_t * rq,int flag,int otyp,cred_t * credp)3573*7836SJohn.Forte@Sun.COM fcip_close(queue_t *rq, int flag, int otyp, cred_t *credp)
3574*7836SJohn.Forte@Sun.COM {
3575*7836SJohn.Forte@Sun.COM 	struct fcipstr *slp;
3576*7836SJohn.Forte@Sun.COM 	struct fcipstr **prevslp;
3577*7836SJohn.Forte@Sun.COM 
3578*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "in fcip_close"));
3579*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_close, "fcip io", /* CSTYLED */,
3580*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
3581*7836SJohn.Forte@Sun.COM 	ASSERT(rq);
3582*7836SJohn.Forte@Sun.COM 	/* we should also have the active stream pointer in q_ptr */
3583*7836SJohn.Forte@Sun.COM 	ASSERT(rq->q_ptr);
3584*7836SJohn.Forte@Sun.COM 
3585*7836SJohn.Forte@Sun.COM 	ddi_rele_driver(ddi_name_to_major(PORT_DRIVER));
3586*7836SJohn.Forte@Sun.COM 	/*
3587*7836SJohn.Forte@Sun.COM 	 * disable our put and service procedures. We had enabled them
3588*7836SJohn.Forte@Sun.COM 	 * on open
3589*7836SJohn.Forte@Sun.COM 	 */
3590*7836SJohn.Forte@Sun.COM 	qprocsoff(rq);
3591*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)rq->q_ptr;
3592*7836SJohn.Forte@Sun.COM 
3593*7836SJohn.Forte@Sun.COM 	/*
3594*7836SJohn.Forte@Sun.COM 	 * Implicitly detach stream  a stream from an interface.
3595*7836SJohn.Forte@Sun.COM 	 */
3596*7836SJohn.Forte@Sun.COM 	if (slp->sl_fcip) {
3597*7836SJohn.Forte@Sun.COM 		fcip_dodetach(slp);
3598*7836SJohn.Forte@Sun.COM 	}
3599*7836SJohn.Forte@Sun.COM 
3600*7836SJohn.Forte@Sun.COM 	(void) qassociate(rq, -1);	/* undo association in open */
3601*7836SJohn.Forte@Sun.COM 
3602*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_WRITER);
3603*7836SJohn.Forte@Sun.COM 
3604*7836SJohn.Forte@Sun.COM 	/*
3605*7836SJohn.Forte@Sun.COM 	 * unlink this stream from the active stream list and free it
3606*7836SJohn.Forte@Sun.COM 	 */
3607*7836SJohn.Forte@Sun.COM 	for (prevslp = &fcipstrup; (slp = *prevslp) != NULL;
3608*7836SJohn.Forte@Sun.COM 	    prevslp = &slp->sl_nextp) {
3609*7836SJohn.Forte@Sun.COM 		if (slp == (struct fcipstr *)rq->q_ptr) {
3610*7836SJohn.Forte@Sun.COM 			break;
3611*7836SJohn.Forte@Sun.COM 		}
3612*7836SJohn.Forte@Sun.COM 	}
3613*7836SJohn.Forte@Sun.COM 
3614*7836SJohn.Forte@Sun.COM 	/* we should have found slp */
3615*7836SJohn.Forte@Sun.COM 	ASSERT(slp);
3616*7836SJohn.Forte@Sun.COM 
3617*7836SJohn.Forte@Sun.COM 	*prevslp = slp->sl_nextp;
3618*7836SJohn.Forte@Sun.COM 	mutex_destroy(&slp->sl_lock);
3619*7836SJohn.Forte@Sun.COM 	kmem_free(slp, sizeof (struct fcipstr));
3620*7836SJohn.Forte@Sun.COM 	rq->q_ptr = WR(rq)->q_ptr = NULL;
3621*7836SJohn.Forte@Sun.COM 
3622*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
3623*7836SJohn.Forte@Sun.COM 	return (0);
3624*7836SJohn.Forte@Sun.COM }
3625*7836SJohn.Forte@Sun.COM 
3626*7836SJohn.Forte@Sun.COM /*
3627*7836SJohn.Forte@Sun.COM  * This is not an extension of the DDI_DETACH request. This routine
3628*7836SJohn.Forte@Sun.COM  * only detaches a stream from an interface
3629*7836SJohn.Forte@Sun.COM  */
3630*7836SJohn.Forte@Sun.COM static void
fcip_dodetach(struct fcipstr * slp)3631*7836SJohn.Forte@Sun.COM fcip_dodetach(struct fcipstr *slp)
3632*7836SJohn.Forte@Sun.COM {
3633*7836SJohn.Forte@Sun.COM 	struct fcipstr	*tslp;
3634*7836SJohn.Forte@Sun.COM 	struct fcip	*fptr;
3635*7836SJohn.Forte@Sun.COM 
3636*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DETACH, (CE_NOTE, "in fcip_dodetach"));
3637*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_dodetach, "fcip io", /* CSTYLED */,
3638*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
3639*7836SJohn.Forte@Sun.COM 	ASSERT(slp->sl_fcip != NULL);
3640*7836SJohn.Forte@Sun.COM 
3641*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
3642*7836SJohn.Forte@Sun.COM 	slp->sl_fcip = NULL;
3643*7836SJohn.Forte@Sun.COM 
3644*7836SJohn.Forte@Sun.COM 	/*
3645*7836SJohn.Forte@Sun.COM 	 * we don't support promiscuous mode currently but check
3646*7836SJohn.Forte@Sun.COM 	 * for and disable any promiscuous mode operation
3647*7836SJohn.Forte@Sun.COM 	 */
3648*7836SJohn.Forte@Sun.COM 	if (slp->sl_flags & SLALLPHYS) {
3649*7836SJohn.Forte@Sun.COM 		slp->sl_flags &= ~SLALLPHYS;
3650*7836SJohn.Forte@Sun.COM 	}
3651*7836SJohn.Forte@Sun.COM 
3652*7836SJohn.Forte@Sun.COM 	/*
3653*7836SJohn.Forte@Sun.COM 	 * disable ALLMULTI mode if all mulitcast addr are ON
3654*7836SJohn.Forte@Sun.COM 	 */
3655*7836SJohn.Forte@Sun.COM 	if (slp->sl_flags & SLALLMULTI) {
3656*7836SJohn.Forte@Sun.COM 		slp->sl_flags &= ~SLALLMULTI;
3657*7836SJohn.Forte@Sun.COM 	}
3658*7836SJohn.Forte@Sun.COM 
3659*7836SJohn.Forte@Sun.COM 	/*
3660*7836SJohn.Forte@Sun.COM 	 * we are most likely going to perform multicast by
3661*7836SJohn.Forte@Sun.COM 	 * broadcasting to the well known addr (D_ID) 0xFFFFFF or
3662*7836SJohn.Forte@Sun.COM 	 * ALPA 0x00 in case of public loops
3663*7836SJohn.Forte@Sun.COM 	 */
3664*7836SJohn.Forte@Sun.COM 
3665*7836SJohn.Forte@Sun.COM 
3666*7836SJohn.Forte@Sun.COM 	/*
3667*7836SJohn.Forte@Sun.COM 	 * detach unit from device structure.
3668*7836SJohn.Forte@Sun.COM 	 */
3669*7836SJohn.Forte@Sun.COM 	for (tslp = fcipstrup; tslp != NULL; tslp = tslp->sl_nextp) {
3670*7836SJohn.Forte@Sun.COM 		if (tslp->sl_fcip == fptr) {
3671*7836SJohn.Forte@Sun.COM 			break;
3672*7836SJohn.Forte@Sun.COM 		}
3673*7836SJohn.Forte@Sun.COM 	}
3674*7836SJohn.Forte@Sun.COM 	if (tslp == NULL) {
3675*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DETACH, (CE_WARN,
3676*7836SJohn.Forte@Sun.COM 		"fcip_dodeatch - active stream struct not found"));
3677*7836SJohn.Forte@Sun.COM 
3678*7836SJohn.Forte@Sun.COM 		/* unregister with Fabric nameserver?? */
3679*7836SJohn.Forte@Sun.COM 	}
3680*7836SJohn.Forte@Sun.COM 	slp->sl_state = DL_UNATTACHED;
3681*7836SJohn.Forte@Sun.COM 
3682*7836SJohn.Forte@Sun.COM 	fcip_setipq(fptr);
3683*7836SJohn.Forte@Sun.COM }
3684*7836SJohn.Forte@Sun.COM 
3685*7836SJohn.Forte@Sun.COM 
3686*7836SJohn.Forte@Sun.COM /*
3687*7836SJohn.Forte@Sun.COM  * Set or clear device ipq pointer.
3688*7836SJohn.Forte@Sun.COM  * Walk thru all the streams on this device, if a ETHERTYPE_IP
3689*7836SJohn.Forte@Sun.COM  * stream is found, assign device ipq to its sl_rq.
3690*7836SJohn.Forte@Sun.COM  */
3691*7836SJohn.Forte@Sun.COM static void
fcip_setipq(struct fcip * fptr)3692*7836SJohn.Forte@Sun.COM fcip_setipq(struct fcip *fptr)
3693*7836SJohn.Forte@Sun.COM {
3694*7836SJohn.Forte@Sun.COM 	struct fcipstr	*slp;
3695*7836SJohn.Forte@Sun.COM 	int		ok = 1;
3696*7836SJohn.Forte@Sun.COM 	queue_t		*ipq = NULL;
3697*7836SJohn.Forte@Sun.COM 
3698*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_NOTE, "entered fcip_setipq"));
3699*7836SJohn.Forte@Sun.COM 
3700*7836SJohn.Forte@Sun.COM 	rw_enter(&fcipstruplock, RW_READER);
3701*7836SJohn.Forte@Sun.COM 
3702*7836SJohn.Forte@Sun.COM 	for (slp = fcipstrup; slp != NULL; slp = slp->sl_nextp) {
3703*7836SJohn.Forte@Sun.COM 		if (slp->sl_fcip == fptr) {
3704*7836SJohn.Forte@Sun.COM 			if (slp->sl_flags & (SLALLPHYS|SLALLSAP)) {
3705*7836SJohn.Forte@Sun.COM 				ok = 0;
3706*7836SJohn.Forte@Sun.COM 			}
3707*7836SJohn.Forte@Sun.COM 			if (slp->sl_sap == ETHERTYPE_IP) {
3708*7836SJohn.Forte@Sun.COM 				if (ipq == NULL) {
3709*7836SJohn.Forte@Sun.COM 					ipq = slp->sl_rq;
3710*7836SJohn.Forte@Sun.COM 				} else {
3711*7836SJohn.Forte@Sun.COM 					ok = 0;
3712*7836SJohn.Forte@Sun.COM 				}
3713*7836SJohn.Forte@Sun.COM 			}
3714*7836SJohn.Forte@Sun.COM 		}
3715*7836SJohn.Forte@Sun.COM 	}
3716*7836SJohn.Forte@Sun.COM 
3717*7836SJohn.Forte@Sun.COM 	rw_exit(&fcipstruplock);
3718*7836SJohn.Forte@Sun.COM 
3719*7836SJohn.Forte@Sun.COM 	if (fcip_check_port_exists(fptr)) {
3720*7836SJohn.Forte@Sun.COM 		/* fptr passed to us is stale */
3721*7836SJohn.Forte@Sun.COM 		return;
3722*7836SJohn.Forte@Sun.COM 	}
3723*7836SJohn.Forte@Sun.COM 
3724*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
3725*7836SJohn.Forte@Sun.COM 	if (ok) {
3726*7836SJohn.Forte@Sun.COM 		fptr->fcip_ipq = ipq;
3727*7836SJohn.Forte@Sun.COM 	} else {
3728*7836SJohn.Forte@Sun.COM 		fptr->fcip_ipq = NULL;
3729*7836SJohn.Forte@Sun.COM 	}
3730*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
3731*7836SJohn.Forte@Sun.COM }
3732*7836SJohn.Forte@Sun.COM 
3733*7836SJohn.Forte@Sun.COM 
3734*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3735*7836SJohn.Forte@Sun.COM static void
fcip_ioctl(queue_t * wq,mblk_t * mp)3736*7836SJohn.Forte@Sun.COM fcip_ioctl(queue_t *wq, mblk_t *mp)
3737*7836SJohn.Forte@Sun.COM {
3738*7836SJohn.Forte@Sun.COM 	struct iocblk		*iocp = (struct iocblk *)mp->b_rptr;
3739*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp = (struct fcipstr *)wq->q_ptr;
3740*7836SJohn.Forte@Sun.COM 
3741*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
3742*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "in fcip ioctl : %d", iocp->ioc_cmd));
3743*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_ioctl, "fcip io", /* CSTYLED */,
3744*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
3745*7836SJohn.Forte@Sun.COM 
3746*7836SJohn.Forte@Sun.COM 	switch (iocp->ioc_cmd) {
3747*7836SJohn.Forte@Sun.COM 	case DLIOCRAW:
3748*7836SJohn.Forte@Sun.COM 		slp->sl_flags |= FCIP_SLRAW;
3749*7836SJohn.Forte@Sun.COM 		miocack(wq, mp, 0, 0);
3750*7836SJohn.Forte@Sun.COM 		break;
3751*7836SJohn.Forte@Sun.COM 
3752*7836SJohn.Forte@Sun.COM 	case DL_IOC_HDR_INFO:
3753*7836SJohn.Forte@Sun.COM 		fcip_dl_ioc_hdr_info(wq, mp);
3754*7836SJohn.Forte@Sun.COM 		break;
3755*7836SJohn.Forte@Sun.COM 
3756*7836SJohn.Forte@Sun.COM 	default:
3757*7836SJohn.Forte@Sun.COM 		miocnak(wq, mp, 0, EINVAL);
3758*7836SJohn.Forte@Sun.COM 		break;
3759*7836SJohn.Forte@Sun.COM 	}
3760*7836SJohn.Forte@Sun.COM }
3761*7836SJohn.Forte@Sun.COM 
3762*7836SJohn.Forte@Sun.COM /*
3763*7836SJohn.Forte@Sun.COM  * The streams 'Put' routine.
3764*7836SJohn.Forte@Sun.COM  */
3765*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3766*7836SJohn.Forte@Sun.COM static int
fcip_wput(queue_t * wq,mblk_t * mp)3767*7836SJohn.Forte@Sun.COM fcip_wput(queue_t *wq, mblk_t *mp)
3768*7836SJohn.Forte@Sun.COM {
3769*7836SJohn.Forte@Sun.COM 	struct fcipstr *slp = (struct fcipstr *)wq->q_ptr;
3770*7836SJohn.Forte@Sun.COM 	struct fcip *fptr;
3771*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp;
3772*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t *headerp;
3773*7836SJohn.Forte@Sun.COM 
3774*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
3775*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "in fcip_wput :: type:%x", DB_TYPE(mp)));
3776*7836SJohn.Forte@Sun.COM 
3777*7836SJohn.Forte@Sun.COM 	switch (DB_TYPE(mp)) {
3778*7836SJohn.Forte@Sun.COM 	case M_DATA: {
3779*7836SJohn.Forte@Sun.COM 
3780*7836SJohn.Forte@Sun.COM 		fptr = slp->sl_fcip;
3781*7836SJohn.Forte@Sun.COM 
3782*7836SJohn.Forte@Sun.COM 		if (((slp->sl_flags & (FCIP_SLFAST|FCIP_SLRAW)) == 0) ||
3783*7836SJohn.Forte@Sun.COM 		    (slp->sl_state != DL_IDLE) ||
3784*7836SJohn.Forte@Sun.COM 		    (fptr == NULL)) {
3785*7836SJohn.Forte@Sun.COM 			/*
3786*7836SJohn.Forte@Sun.COM 			 * set error in the message block and send a reply
3787*7836SJohn.Forte@Sun.COM 			 * back upstream. Sun's merror routine does this
3788*7836SJohn.Forte@Sun.COM 			 * for us more cleanly.
3789*7836SJohn.Forte@Sun.COM 			 */
3790*7836SJohn.Forte@Sun.COM 			merror(wq, mp, EPROTO);
3791*7836SJohn.Forte@Sun.COM 			break;
3792*7836SJohn.Forte@Sun.COM 		}
3793*7836SJohn.Forte@Sun.COM 
3794*7836SJohn.Forte@Sun.COM 		/*
3795*7836SJohn.Forte@Sun.COM 		 * if any messages are already enqueued or if the interface
3796*7836SJohn.Forte@Sun.COM 		 * is in promiscuous mode, causing the packets to loop back
3797*7836SJohn.Forte@Sun.COM 		 * up, then enqueue the message. Otherwise just transmit
3798*7836SJohn.Forte@Sun.COM 		 * the message. putq() puts the message on fcip's
3799*7836SJohn.Forte@Sun.COM 		 * write queue and qenable() puts the queue (wq) on
3800*7836SJohn.Forte@Sun.COM 		 * the list of queues to be called by the streams scheduler.
3801*7836SJohn.Forte@Sun.COM 		 */
3802*7836SJohn.Forte@Sun.COM 		if (wq->q_first) {
3803*7836SJohn.Forte@Sun.COM 			(void) putq(wq, mp);
3804*7836SJohn.Forte@Sun.COM 			fptr->fcip_wantw = 1;
3805*7836SJohn.Forte@Sun.COM 			qenable(wq);
3806*7836SJohn.Forte@Sun.COM 		} else if (fptr->fcip_flags & FCIP_PROMISC) {
3807*7836SJohn.Forte@Sun.COM 			/*
3808*7836SJohn.Forte@Sun.COM 			 * Promiscous mode not supported but add this code in
3809*7836SJohn.Forte@Sun.COM 			 * case it will be supported in future.
3810*7836SJohn.Forte@Sun.COM 			 */
3811*7836SJohn.Forte@Sun.COM 			(void) putq(wq, mp);
3812*7836SJohn.Forte@Sun.COM 			qenable(wq);
3813*7836SJohn.Forte@Sun.COM 		} else {
3814*7836SJohn.Forte@Sun.COM 
3815*7836SJohn.Forte@Sun.COM 			headerp = (fcph_network_hdr_t *)mp->b_rptr;
3816*7836SJohn.Forte@Sun.COM 			fdestp = fcip_get_dest(fptr, &headerp->net_dest_addr);
3817*7836SJohn.Forte@Sun.COM 
3818*7836SJohn.Forte@Sun.COM 			if (fdestp == NULL) {
3819*7836SJohn.Forte@Sun.COM 				merror(wq, mp, EPROTO);
3820*7836SJohn.Forte@Sun.COM 				break;
3821*7836SJohn.Forte@Sun.COM 			}
3822*7836SJohn.Forte@Sun.COM 
3823*7836SJohn.Forte@Sun.COM 			ASSERT(fdestp != NULL);
3824*7836SJohn.Forte@Sun.COM 
3825*7836SJohn.Forte@Sun.COM 			(void) fcip_start(wq, mp, fptr, fdestp, KM_SLEEP);
3826*7836SJohn.Forte@Sun.COM 		}
3827*7836SJohn.Forte@Sun.COM 		break;
3828*7836SJohn.Forte@Sun.COM 	}
3829*7836SJohn.Forte@Sun.COM 	case M_PROTO:
3830*7836SJohn.Forte@Sun.COM 	case M_PCPROTO:
3831*7836SJohn.Forte@Sun.COM 		/*
3832*7836SJohn.Forte@Sun.COM 		 * to prevent recursive calls into fcip_proto
3833*7836SJohn.Forte@Sun.COM 		 * (PROTO and PCPROTO messages are handled by fcip_proto)
3834*7836SJohn.Forte@Sun.COM 		 * let the service procedure handle these messages by
3835*7836SJohn.Forte@Sun.COM 		 * calling putq here.
3836*7836SJohn.Forte@Sun.COM 		 */
3837*7836SJohn.Forte@Sun.COM 		(void) putq(wq, mp);
3838*7836SJohn.Forte@Sun.COM 		qenable(wq);
3839*7836SJohn.Forte@Sun.COM 		break;
3840*7836SJohn.Forte@Sun.COM 
3841*7836SJohn.Forte@Sun.COM 	case M_IOCTL:
3842*7836SJohn.Forte@Sun.COM 		fcip_ioctl(wq, mp);
3843*7836SJohn.Forte@Sun.COM 		break;
3844*7836SJohn.Forte@Sun.COM 
3845*7836SJohn.Forte@Sun.COM 	case M_FLUSH:
3846*7836SJohn.Forte@Sun.COM 		if (*mp->b_rptr & FLUSHW) {
3847*7836SJohn.Forte@Sun.COM 			flushq(wq, FLUSHALL);
3848*7836SJohn.Forte@Sun.COM 			*mp->b_rptr &= ~FLUSHW;
3849*7836SJohn.Forte@Sun.COM 		}
3850*7836SJohn.Forte@Sun.COM 		/*
3851*7836SJohn.Forte@Sun.COM 		 * we have both FLUSHW and FLUSHR set with FLUSHRW
3852*7836SJohn.Forte@Sun.COM 		 */
3853*7836SJohn.Forte@Sun.COM 		if (*mp->b_rptr & FLUSHR) {
3854*7836SJohn.Forte@Sun.COM 			/*
3855*7836SJohn.Forte@Sun.COM 			 * send msg back upstream. qreply() takes care
3856*7836SJohn.Forte@Sun.COM 			 * of using the RD(wq) queue on its reply
3857*7836SJohn.Forte@Sun.COM 			 */
3858*7836SJohn.Forte@Sun.COM 			qreply(wq, mp);
3859*7836SJohn.Forte@Sun.COM 		} else {
3860*7836SJohn.Forte@Sun.COM 			freemsg(mp);
3861*7836SJohn.Forte@Sun.COM 		}
3862*7836SJohn.Forte@Sun.COM 		break;
3863*7836SJohn.Forte@Sun.COM 
3864*7836SJohn.Forte@Sun.COM 	default:
3865*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
3866*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "default msg type: %x", DB_TYPE(mp)));
3867*7836SJohn.Forte@Sun.COM 		freemsg(mp);
3868*7836SJohn.Forte@Sun.COM 		break;
3869*7836SJohn.Forte@Sun.COM 	}
3870*7836SJohn.Forte@Sun.COM 	return (0);
3871*7836SJohn.Forte@Sun.COM }
3872*7836SJohn.Forte@Sun.COM 
3873*7836SJohn.Forte@Sun.COM 
3874*7836SJohn.Forte@Sun.COM /*
3875*7836SJohn.Forte@Sun.COM  * Handle M_PROTO and M_PCPROTO messages
3876*7836SJohn.Forte@Sun.COM  */
3877*7836SJohn.Forte@Sun.COM /* ARGSUSED */
3878*7836SJohn.Forte@Sun.COM static void
fcip_proto(queue_t * wq,mblk_t * mp)3879*7836SJohn.Forte@Sun.COM fcip_proto(queue_t *wq, mblk_t *mp)
3880*7836SJohn.Forte@Sun.COM {
3881*7836SJohn.Forte@Sun.COM 	union DL_primitives	*dlp;
3882*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
3883*7836SJohn.Forte@Sun.COM 	t_uscalar_t		prim;
3884*7836SJohn.Forte@Sun.COM 
3885*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
3886*7836SJohn.Forte@Sun.COM 	dlp = (union DL_primitives *)mp->b_rptr;
3887*7836SJohn.Forte@Sun.COM 	prim = dlp->dl_primitive;		/* the DLPI command */
3888*7836SJohn.Forte@Sun.COM 
3889*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_5((fcip_proto, "fcip io", /* CSTYLED */,
3890*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter",
3891*7836SJohn.Forte@Sun.COM 		tnf_opaque, wq, wq,
3892*7836SJohn.Forte@Sun.COM 		tnf_opaque, mp, mp,
3893*7836SJohn.Forte@Sun.COM 		tnf_opaque, MP_DB_TYPE, DB_TYPE(mp),
3894*7836SJohn.Forte@Sun.COM 		tnf_opaque, dl_primitive, dlp->dl_primitive));
3895*7836SJohn.Forte@Sun.COM 
3896*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_NOTE, "dl_primitve : %x", prim));
3897*7836SJohn.Forte@Sun.COM 
3898*7836SJohn.Forte@Sun.COM 	mutex_enter(&slp->sl_lock);
3899*7836SJohn.Forte@Sun.COM 
3900*7836SJohn.Forte@Sun.COM 	switch (prim) {
3901*7836SJohn.Forte@Sun.COM 	case DL_UNITDATA_REQ:
3902*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3903*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "unit data request"));
3904*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "unit data request"));
3905*7836SJohn.Forte@Sun.COM 		fcip_udreq(wq, mp);
3906*7836SJohn.Forte@Sun.COM 		break;
3907*7836SJohn.Forte@Sun.COM 
3908*7836SJohn.Forte@Sun.COM 	case DL_ATTACH_REQ:
3909*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3910*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Attach request"));
3911*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "Attach request"));
3912*7836SJohn.Forte@Sun.COM 		fcip_areq(wq, mp);
3913*7836SJohn.Forte@Sun.COM 		break;
3914*7836SJohn.Forte@Sun.COM 
3915*7836SJohn.Forte@Sun.COM 	case DL_DETACH_REQ:
3916*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3917*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Detach request"));
3918*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "Detach request"));
3919*7836SJohn.Forte@Sun.COM 		fcip_dreq(wq, mp);
3920*7836SJohn.Forte@Sun.COM 		break;
3921*7836SJohn.Forte@Sun.COM 
3922*7836SJohn.Forte@Sun.COM 	case DL_BIND_REQ:
3923*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "Bind request"));
3924*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3925*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Bind request"));
3926*7836SJohn.Forte@Sun.COM 		fcip_breq(wq, mp);
3927*7836SJohn.Forte@Sun.COM 		break;
3928*7836SJohn.Forte@Sun.COM 
3929*7836SJohn.Forte@Sun.COM 	case DL_UNBIND_REQ:
3930*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3931*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "unbind request"));
3932*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "unbind request"));
3933*7836SJohn.Forte@Sun.COM 		fcip_ubreq(wq, mp);
3934*7836SJohn.Forte@Sun.COM 		break;
3935*7836SJohn.Forte@Sun.COM 
3936*7836SJohn.Forte@Sun.COM 	case DL_INFO_REQ:
3937*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3938*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Info request"));
3939*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "Info request"));
3940*7836SJohn.Forte@Sun.COM 		fcip_ireq(wq, mp);
3941*7836SJohn.Forte@Sun.COM 		break;
3942*7836SJohn.Forte@Sun.COM 
3943*7836SJohn.Forte@Sun.COM 	case DL_SET_PHYS_ADDR_REQ:
3944*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3945*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "set phy addr request"));
3946*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
3947*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "set phy addr request"));
3948*7836SJohn.Forte@Sun.COM 		fcip_spareq(wq, mp);
3949*7836SJohn.Forte@Sun.COM 		break;
3950*7836SJohn.Forte@Sun.COM 
3951*7836SJohn.Forte@Sun.COM 	case DL_PHYS_ADDR_REQ:
3952*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3953*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "phy addr request"));
3954*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "phy addr request"));
3955*7836SJohn.Forte@Sun.COM 		fcip_pareq(wq, mp);
3956*7836SJohn.Forte@Sun.COM 		break;
3957*7836SJohn.Forte@Sun.COM 
3958*7836SJohn.Forte@Sun.COM 	case DL_ENABMULTI_REQ:
3959*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3960*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Enable Multicast request"));
3961*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
3962*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Enable Multicast request"));
3963*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
3964*7836SJohn.Forte@Sun.COM 		break;
3965*7836SJohn.Forte@Sun.COM 
3966*7836SJohn.Forte@Sun.COM 	case DL_DISABMULTI_REQ:
3967*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3968*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Disable Multicast request"));
3969*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
3970*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Disable Multicast request"));
3971*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
3972*7836SJohn.Forte@Sun.COM 		break;
3973*7836SJohn.Forte@Sun.COM 
3974*7836SJohn.Forte@Sun.COM 	case DL_PROMISCON_REQ:
3975*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3976*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Promiscuous mode ON request"));
3977*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
3978*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Promiscuous mode ON request"));
3979*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
3980*7836SJohn.Forte@Sun.COM 		break;
3981*7836SJohn.Forte@Sun.COM 
3982*7836SJohn.Forte@Sun.COM 	case DL_PROMISCOFF_REQ:
3983*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3984*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Promiscuous mode OFF request"));
3985*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
3986*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Promiscuous mode OFF request"));
3987*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
3988*7836SJohn.Forte@Sun.COM 		break;
3989*7836SJohn.Forte@Sun.COM 
3990*7836SJohn.Forte@Sun.COM 	default:
3991*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_proto, "fcip io", /* CSTYLED */,
3992*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "Unsupported request"));
3993*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, prim, DL_UNSUPPORTED, 0);
3994*7836SJohn.Forte@Sun.COM 		break;
3995*7836SJohn.Forte@Sun.COM 	}
3996*7836SJohn.Forte@Sun.COM 	mutex_exit(&slp->sl_lock);
3997*7836SJohn.Forte@Sun.COM }
3998*7836SJohn.Forte@Sun.COM 
3999*7836SJohn.Forte@Sun.COM /*
4000*7836SJohn.Forte@Sun.COM  * Always enqueue M_PROTO and M_PCPROTO messages pn the wq and M_DATA
4001*7836SJohn.Forte@Sun.COM  * messages sometimes. Processing of M_PROTO and M_PCPROTO messages
4002*7836SJohn.Forte@Sun.COM  * require us to hold fcip's internal locks across (upstream) putnext
4003*7836SJohn.Forte@Sun.COM  * calls. Specifically fcip_intr could hold fcip_intrlock and fcipstruplock
4004*7836SJohn.Forte@Sun.COM  * when it calls putnext(). That thread could loop back around to call
4005*7836SJohn.Forte@Sun.COM  * fcip_wput and eventually fcip_init() to cause a recursive mutex panic
4006*7836SJohn.Forte@Sun.COM  *
4007*7836SJohn.Forte@Sun.COM  * M_DATA messages are enqueued only if we are out of xmit resources. Once
4008*7836SJohn.Forte@Sun.COM  * the transmit resources are available the service procedure is enabled
4009*7836SJohn.Forte@Sun.COM  * and an attempt is made to xmit all messages on the wq.
4010*7836SJohn.Forte@Sun.COM  */
4011*7836SJohn.Forte@Sun.COM /* ARGSUSED */
4012*7836SJohn.Forte@Sun.COM static int
fcip_wsrv(queue_t * wq)4013*7836SJohn.Forte@Sun.COM fcip_wsrv(queue_t *wq)
4014*7836SJohn.Forte@Sun.COM {
4015*7836SJohn.Forte@Sun.COM 	mblk_t		*mp;
4016*7836SJohn.Forte@Sun.COM 	struct fcipstr	*slp;
4017*7836SJohn.Forte@Sun.COM 	struct fcip	*fptr;
4018*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp;
4019*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t *headerp;
4020*7836SJohn.Forte@Sun.COM 
4021*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
4022*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
4023*7836SJohn.Forte@Sun.COM 
4024*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_wsrv, "fcip io", /* CSTYLED */,
4025*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter",
4026*7836SJohn.Forte@Sun.COM 		tnf_opaque, wq, wq));
4027*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "fcip wsrv"));
4028*7836SJohn.Forte@Sun.COM 
4029*7836SJohn.Forte@Sun.COM 	while (mp = getq(wq)) {
4030*7836SJohn.Forte@Sun.COM 		switch (DB_TYPE(mp)) {
4031*7836SJohn.Forte@Sun.COM 		case M_DATA:
4032*7836SJohn.Forte@Sun.COM 			if (fptr && mp) {
4033*7836SJohn.Forte@Sun.COM 				headerp = (fcph_network_hdr_t *)mp->b_rptr;
4034*7836SJohn.Forte@Sun.COM 				fdestp = fcip_get_dest(fptr,
4035*7836SJohn.Forte@Sun.COM 				    &headerp->net_dest_addr);
4036*7836SJohn.Forte@Sun.COM 				if (fdestp == NULL) {
4037*7836SJohn.Forte@Sun.COM 					freemsg(mp);
4038*7836SJohn.Forte@Sun.COM 					goto done;
4039*7836SJohn.Forte@Sun.COM 				}
4040*7836SJohn.Forte@Sun.COM 				if (fcip_start(wq, mp, fptr, fdestp,
4041*7836SJohn.Forte@Sun.COM 				    KM_SLEEP)) {
4042*7836SJohn.Forte@Sun.COM 					goto done;
4043*7836SJohn.Forte@Sun.COM 				}
4044*7836SJohn.Forte@Sun.COM 			} else {
4045*7836SJohn.Forte@Sun.COM 				freemsg(mp);
4046*7836SJohn.Forte@Sun.COM 			}
4047*7836SJohn.Forte@Sun.COM 			break;
4048*7836SJohn.Forte@Sun.COM 
4049*7836SJohn.Forte@Sun.COM 		case M_PROTO:
4050*7836SJohn.Forte@Sun.COM 		case M_PCPROTO:
4051*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
4052*7836SJohn.Forte@Sun.COM 			    (CE_NOTE, "PROT msg in wsrv"));
4053*7836SJohn.Forte@Sun.COM 			fcip_proto(wq, mp);
4054*7836SJohn.Forte@Sun.COM 			break;
4055*7836SJohn.Forte@Sun.COM 		default:
4056*7836SJohn.Forte@Sun.COM 			break;
4057*7836SJohn.Forte@Sun.COM 		}
4058*7836SJohn.Forte@Sun.COM 	}
4059*7836SJohn.Forte@Sun.COM done:
4060*7836SJohn.Forte@Sun.COM 	return (0);
4061*7836SJohn.Forte@Sun.COM }
4062*7836SJohn.Forte@Sun.COM 
4063*7836SJohn.Forte@Sun.COM 
4064*7836SJohn.Forte@Sun.COM /*
4065*7836SJohn.Forte@Sun.COM  * This routine is called from fcip_wsrv to send a message downstream
4066*7836SJohn.Forte@Sun.COM  * on the fibre towards its destination. This routine performs the
4067*7836SJohn.Forte@Sun.COM  * actual WWN to D_ID mapping by looking up the routing and destination
4068*7836SJohn.Forte@Sun.COM  * tables.
4069*7836SJohn.Forte@Sun.COM  */
4070*7836SJohn.Forte@Sun.COM /* ARGSUSED */
4071*7836SJohn.Forte@Sun.COM static int
fcip_start(queue_t * wq,mblk_t * mp,struct fcip * fptr,struct fcip_dest * fdestp,int flags)4072*7836SJohn.Forte@Sun.COM fcip_start(queue_t *wq, mblk_t *mp, struct fcip *fptr,
4073*7836SJohn.Forte@Sun.COM     struct fcip_dest *fdestp, int flags)
4074*7836SJohn.Forte@Sun.COM {
4075*7836SJohn.Forte@Sun.COM 	int			rval;
4076*7836SJohn.Forte@Sun.COM 	int			free;
4077*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt;
4078*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
4079*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
4080*7836SJohn.Forte@Sun.COM 	size_t			datalen;
4081*7836SJohn.Forte@Sun.COM 
4082*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_4((fcip_start, "fcip io", /* CSTYLED */,
4083*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "enter", tnf_opaque, wq, wq,
4084*7836SJohn.Forte@Sun.COM 	    tnf_opaque, mp, mp,
4085*7836SJohn.Forte@Sun.COM 	    tnf_opaque, MP_DB_TYPE, DB_TYPE(mp)));
4086*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "in fcipstart"));
4087*7836SJohn.Forte@Sun.COM 
4088*7836SJohn.Forte@Sun.COM 	ASSERT(fdestp != NULL);
4089*7836SJohn.Forte@Sun.COM 
4090*7836SJohn.Forte@Sun.COM 	/*
4091*7836SJohn.Forte@Sun.COM 	 * Only return if port has gone offline and not come back online
4092*7836SJohn.Forte@Sun.COM 	 * in a while
4093*7836SJohn.Forte@Sun.COM 	 */
4094*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_flags & FCIP_LINK_DOWN) {
4095*7836SJohn.Forte@Sun.COM 		freemsg(mp);
4096*7836SJohn.Forte@Sun.COM 		return (0);
4097*7836SJohn.Forte@Sun.COM 	}
4098*7836SJohn.Forte@Sun.COM 
4099*7836SJohn.Forte@Sun.COM 	/*
4100*7836SJohn.Forte@Sun.COM 	 * The message block coming in here already has the network and
4101*7836SJohn.Forte@Sun.COM 	 * llc_snap hdr stuffed in
4102*7836SJohn.Forte@Sun.COM 	 */
4103*7836SJohn.Forte@Sun.COM 	/*
4104*7836SJohn.Forte@Sun.COM 	 * Traditionally ethernet drivers at sun handle 3 cases here -
4105*7836SJohn.Forte@Sun.COM 	 * 1. messages with one mblk
4106*7836SJohn.Forte@Sun.COM 	 * 2. messages with 2 mblks
4107*7836SJohn.Forte@Sun.COM 	 * 3. messages with >2 mblks
4108*7836SJohn.Forte@Sun.COM 	 * For now lets handle all the 3 cases in a single case where we
4109*7836SJohn.Forte@Sun.COM 	 * put them together in one mblk that has all the data
4110*7836SJohn.Forte@Sun.COM 	 */
4111*7836SJohn.Forte@Sun.COM 
4112*7836SJohn.Forte@Sun.COM 	if (mp->b_cont != NULL) {
4113*7836SJohn.Forte@Sun.COM 		if (!pullupmsg(mp, -1)) {
4114*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
4115*7836SJohn.Forte@Sun.COM 			    (CE_WARN, "failed to concat message"));
4116*7836SJohn.Forte@Sun.COM 			freemsg(mp);
4117*7836SJohn.Forte@Sun.COM 			return (1);
4118*7836SJohn.Forte@Sun.COM 		}
4119*7836SJohn.Forte@Sun.COM 	}
4120*7836SJohn.Forte@Sun.COM 
4121*7836SJohn.Forte@Sun.COM 	datalen = msgsize(mp);
4122*7836SJohn.Forte@Sun.COM 
4123*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE,
4124*7836SJohn.Forte@Sun.COM 	    "msgsize with nhdr & llcsnap hdr in fcip_pkt_alloc 0x%lx",
4125*7836SJohn.Forte@Sun.COM 	    datalen));
4126*7836SJohn.Forte@Sun.COM 
4127*7836SJohn.Forte@Sun.COM 	/*
4128*7836SJohn.Forte@Sun.COM 	 * We cannot have requests larger than FCIPMTU+Headers
4129*7836SJohn.Forte@Sun.COM 	 */
4130*7836SJohn.Forte@Sun.COM 	if (datalen > (FCIPMTU + sizeof (llc_snap_hdr_t) +
4131*7836SJohn.Forte@Sun.COM 		sizeof (fcph_network_hdr_t))) {
4132*7836SJohn.Forte@Sun.COM 		freemsg(mp);
4133*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE,
4134*7836SJohn.Forte@Sun.COM 		    "fcip_pkt_alloc: datalen is larger than "
4135*7836SJohn.Forte@Sun.COM 		    "max possible size."));
4136*7836SJohn.Forte@Sun.COM 		return (1);
4137*7836SJohn.Forte@Sun.COM 	}
4138*7836SJohn.Forte@Sun.COM 
4139*7836SJohn.Forte@Sun.COM 	fcip_pkt = fcip_pkt_alloc(fptr, mp, flags, datalen);
4140*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
4141*7836SJohn.Forte@Sun.COM 		(void) putbq(wq, mp);
4142*7836SJohn.Forte@Sun.COM 		return (1);
4143*7836SJohn.Forte@Sun.COM 	}
4144*7836SJohn.Forte@Sun.COM 
4145*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_mp = mp;
4146*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_wq = wq;
4147*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
4148*7836SJohn.Forte@Sun.COM 
4149*7836SJohn.Forte@Sun.COM 	mutex_enter(&fdestp->fcipd_mutex);
4150*7836SJohn.Forte@Sun.COM 	/*
4151*7836SJohn.Forte@Sun.COM 	 * If the device dynamically disappeared, just fail the request.
4152*7836SJohn.Forte@Sun.COM 	 */
4153*7836SJohn.Forte@Sun.COM 	if (fdestp->fcipd_rtable == NULL) {
4154*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
4155*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, 1);
4156*7836SJohn.Forte@Sun.COM 		return (1);
4157*7836SJohn.Forte@Sun.COM 	}
4158*7836SJohn.Forte@Sun.COM 
4159*7836SJohn.Forte@Sun.COM 	/*
4160*7836SJohn.Forte@Sun.COM 	 * Now that we've assigned pkt_pd, we can call fc_ulp_init_packet
4161*7836SJohn.Forte@Sun.COM 	 */
4162*7836SJohn.Forte@Sun.COM 
4163*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_pd = fdestp->fcipd_pd;
4164*7836SJohn.Forte@Sun.COM 
4165*7836SJohn.Forte@Sun.COM 	if (fc_ulp_init_packet((opaque_t)fport->fcipp_handle,
4166*7836SJohn.Forte@Sun.COM 	    fc_pkt, flags) != FC_SUCCESS) {
4167*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
4168*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, 1);
4169*7836SJohn.Forte@Sun.COM 		return (1);
4170*7836SJohn.Forte@Sun.COM 	}
4171*7836SJohn.Forte@Sun.COM 
4172*7836SJohn.Forte@Sun.COM 	fcip_fdestp_enqueue_pkt(fdestp, fcip_pkt);
4173*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dest = fdestp;
4174*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_fca_device = fdestp->fcipd_fca_dev;
4175*7836SJohn.Forte@Sun.COM 
4176*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE,
4177*7836SJohn.Forte@Sun.COM 	    "setting cmdlen to 0x%x: rsp 0x%x : data 0x%x",
4178*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_cmdlen, fc_pkt->pkt_rsplen, fc_pkt->pkt_datalen));
4179*7836SJohn.Forte@Sun.COM 
4180*7836SJohn.Forte@Sun.COM 	fcip_init_unicast_pkt(fcip_pkt, fport->fcipp_sid,
4181*7836SJohn.Forte@Sun.COM 	    fdestp->fcipd_did, fcip_pkt_callback);
4182*7836SJohn.Forte@Sun.COM 
4183*7836SJohn.Forte@Sun.COM 	fdestp->fcipd_ncmds++;
4184*7836SJohn.Forte@Sun.COM 
4185*7836SJohn.Forte@Sun.COM 	mutex_exit(&fdestp->fcipd_mutex);
4186*7836SJohn.Forte@Sun.COM 	if ((rval = fcip_transport(fcip_pkt)) == FC_SUCCESS) {
4187*7836SJohn.Forte@Sun.COM 		fptr->fcip_opackets++;
4188*7836SJohn.Forte@Sun.COM 		return (0);
4189*7836SJohn.Forte@Sun.COM 	}
4190*7836SJohn.Forte@Sun.COM 
4191*7836SJohn.Forte@Sun.COM 	free = (rval == FC_STATEC_BUSY || rval == FC_OFFLINE ||
4192*7836SJohn.Forte@Sun.COM 	    rval == FC_TRAN_BUSY) ? 0 : 1;
4193*7836SJohn.Forte@Sun.COM 
4194*7836SJohn.Forte@Sun.COM 	mutex_enter(&fdestp->fcipd_mutex);
4195*7836SJohn.Forte@Sun.COM 	rval = fcip_fdestp_dequeue_pkt(fdestp, fcip_pkt);
4196*7836SJohn.Forte@Sun.COM 
4197*7836SJohn.Forte@Sun.COM 	if (!rval) {
4198*7836SJohn.Forte@Sun.COM 		fcip_pkt = NULL;
4199*7836SJohn.Forte@Sun.COM 	} else {
4200*7836SJohn.Forte@Sun.COM 		fdestp->fcipd_ncmds--;
4201*7836SJohn.Forte@Sun.COM 	}
4202*7836SJohn.Forte@Sun.COM 	mutex_exit(&fdestp->fcipd_mutex);
4203*7836SJohn.Forte@Sun.COM 
4204*7836SJohn.Forte@Sun.COM 	if (fcip_pkt != NULL) {
4205*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, free);
4206*7836SJohn.Forte@Sun.COM 	}
4207*7836SJohn.Forte@Sun.COM 
4208*7836SJohn.Forte@Sun.COM 	if (!free) {
4209*7836SJohn.Forte@Sun.COM 		(void) putbq(wq, mp);
4210*7836SJohn.Forte@Sun.COM 	}
4211*7836SJohn.Forte@Sun.COM 
4212*7836SJohn.Forte@Sun.COM 	return (1);
4213*7836SJohn.Forte@Sun.COM }
4214*7836SJohn.Forte@Sun.COM 
4215*7836SJohn.Forte@Sun.COM 
4216*7836SJohn.Forte@Sun.COM /*
4217*7836SJohn.Forte@Sun.COM  * This routine enqueus a packet marked to be issued to the
4218*7836SJohn.Forte@Sun.COM  * transport in the dest structure. This enables us to timeout any
4219*7836SJohn.Forte@Sun.COM  * request stuck with the FCA/transport for long periods of time
4220*7836SJohn.Forte@Sun.COM  * without a response. fcip_pkt_timeout will attempt to clean up
4221*7836SJohn.Forte@Sun.COM  * any packets hung in this state of limbo.
4222*7836SJohn.Forte@Sun.COM  */
4223*7836SJohn.Forte@Sun.COM static void
fcip_fdestp_enqueue_pkt(struct fcip_dest * fdestp,fcip_pkt_t * fcip_pkt)4224*7836SJohn.Forte@Sun.COM fcip_fdestp_enqueue_pkt(struct fcip_dest *fdestp, fcip_pkt_t *fcip_pkt)
4225*7836SJohn.Forte@Sun.COM {
4226*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fdestp->fcipd_mutex));
4227*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_fdestp_enqueue_pkt, "fcip io", /* CSTYLED */,
4228*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "destp enq pkt"));
4229*7836SJohn.Forte@Sun.COM 
4230*7836SJohn.Forte@Sun.COM 	/*
4231*7836SJohn.Forte@Sun.COM 	 * Just hang it off the head of packet list
4232*7836SJohn.Forte@Sun.COM 	 */
4233*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_next = fdestp->fcipd_head;
4234*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_prev = NULL;
4235*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags |= FCIP_PKT_IN_LIST;
4236*7836SJohn.Forte@Sun.COM 
4237*7836SJohn.Forte@Sun.COM 	if (fdestp->fcipd_head != NULL) {
4238*7836SJohn.Forte@Sun.COM 		ASSERT(fdestp->fcipd_head->fcip_pkt_prev == NULL);
4239*7836SJohn.Forte@Sun.COM 		fdestp->fcipd_head->fcip_pkt_prev = fcip_pkt;
4240*7836SJohn.Forte@Sun.COM 	}
4241*7836SJohn.Forte@Sun.COM 
4242*7836SJohn.Forte@Sun.COM 	fdestp->fcipd_head = fcip_pkt;
4243*7836SJohn.Forte@Sun.COM }
4244*7836SJohn.Forte@Sun.COM 
4245*7836SJohn.Forte@Sun.COM 
4246*7836SJohn.Forte@Sun.COM /*
4247*7836SJohn.Forte@Sun.COM  * dequeues any packets after the transport/FCA tells us it has
4248*7836SJohn.Forte@Sun.COM  * been successfully sent on its way. Ofcourse it doesn't mean that
4249*7836SJohn.Forte@Sun.COM  * the packet will actually reach its destination but its atleast
4250*7836SJohn.Forte@Sun.COM  * a step closer in that direction
4251*7836SJohn.Forte@Sun.COM  */
4252*7836SJohn.Forte@Sun.COM static int
fcip_fdestp_dequeue_pkt(struct fcip_dest * fdestp,fcip_pkt_t * fcip_pkt)4253*7836SJohn.Forte@Sun.COM fcip_fdestp_dequeue_pkt(struct fcip_dest *fdestp, fcip_pkt_t *fcip_pkt)
4254*7836SJohn.Forte@Sun.COM {
4255*7836SJohn.Forte@Sun.COM 	fcip_pkt_t	*fcipd_pkt;
4256*7836SJohn.Forte@Sun.COM 
4257*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fdestp->fcipd_mutex));
4258*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_flags & FCIP_PKT_IN_TIMEOUT) {
4259*7836SJohn.Forte@Sun.COM 		fcipd_pkt = fdestp->fcipd_head;
4260*7836SJohn.Forte@Sun.COM 		while (fcipd_pkt) {
4261*7836SJohn.Forte@Sun.COM 			if (fcipd_pkt == fcip_pkt) {
4262*7836SJohn.Forte@Sun.COM 				fcip_pkt_t	*pptr = NULL;
4263*7836SJohn.Forte@Sun.COM 
4264*7836SJohn.Forte@Sun.COM 				if (fcipd_pkt == fdestp->fcipd_head) {
4265*7836SJohn.Forte@Sun.COM 					ASSERT(fcipd_pkt->fcip_pkt_prev ==
4266*7836SJohn.Forte@Sun.COM 					    NULL);
4267*7836SJohn.Forte@Sun.COM 					fdestp->fcipd_head =
4268*7836SJohn.Forte@Sun.COM 					    fcipd_pkt->fcip_pkt_next;
4269*7836SJohn.Forte@Sun.COM 				} else {
4270*7836SJohn.Forte@Sun.COM 					pptr = fcipd_pkt->fcip_pkt_prev;
4271*7836SJohn.Forte@Sun.COM 					ASSERT(pptr != NULL);
4272*7836SJohn.Forte@Sun.COM 					pptr->fcip_pkt_next =
4273*7836SJohn.Forte@Sun.COM 					    fcipd_pkt->fcip_pkt_next;
4274*7836SJohn.Forte@Sun.COM 				}
4275*7836SJohn.Forte@Sun.COM 				if (fcipd_pkt->fcip_pkt_next) {
4276*7836SJohn.Forte@Sun.COM 					pptr = fcipd_pkt->fcip_pkt_next;
4277*7836SJohn.Forte@Sun.COM 					pptr->fcip_pkt_prev =
4278*7836SJohn.Forte@Sun.COM 					    fcipd_pkt->fcip_pkt_prev;
4279*7836SJohn.Forte@Sun.COM 				}
4280*7836SJohn.Forte@Sun.COM 				fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_LIST;
4281*7836SJohn.Forte@Sun.COM 				break;
4282*7836SJohn.Forte@Sun.COM 			}
4283*7836SJohn.Forte@Sun.COM 			fcipd_pkt = fcipd_pkt->fcip_pkt_next;
4284*7836SJohn.Forte@Sun.COM 		}
4285*7836SJohn.Forte@Sun.COM 	} else {
4286*7836SJohn.Forte@Sun.COM 		if (fcip_pkt->fcip_pkt_prev == NULL) {
4287*7836SJohn.Forte@Sun.COM 			ASSERT(fdestp->fcipd_head == fcip_pkt);
4288*7836SJohn.Forte@Sun.COM 			fdestp->fcipd_head = fcip_pkt->fcip_pkt_next;
4289*7836SJohn.Forte@Sun.COM 		} else {
4290*7836SJohn.Forte@Sun.COM 			fcip_pkt->fcip_pkt_prev->fcip_pkt_next =
4291*7836SJohn.Forte@Sun.COM 			    fcip_pkt->fcip_pkt_next;
4292*7836SJohn.Forte@Sun.COM 		}
4293*7836SJohn.Forte@Sun.COM 
4294*7836SJohn.Forte@Sun.COM 		if (fcip_pkt->fcip_pkt_next) {
4295*7836SJohn.Forte@Sun.COM 			fcip_pkt->fcip_pkt_next->fcip_pkt_prev =
4296*7836SJohn.Forte@Sun.COM 			    fcip_pkt->fcip_pkt_prev;
4297*7836SJohn.Forte@Sun.COM 		}
4298*7836SJohn.Forte@Sun.COM 
4299*7836SJohn.Forte@Sun.COM 		fcipd_pkt = fcip_pkt;
4300*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_LIST;
4301*7836SJohn.Forte@Sun.COM 	}
4302*7836SJohn.Forte@Sun.COM 
4303*7836SJohn.Forte@Sun.COM 	return (fcipd_pkt == fcip_pkt);
4304*7836SJohn.Forte@Sun.COM }
4305*7836SJohn.Forte@Sun.COM 
4306*7836SJohn.Forte@Sun.COM /*
4307*7836SJohn.Forte@Sun.COM  * The transport routine - this is the routine that actually calls
4308*7836SJohn.Forte@Sun.COM  * into the FCA driver (through the transport ofcourse) to transmit a
4309*7836SJohn.Forte@Sun.COM  * datagram on the fibre. The dest struct assoicated with the port to
4310*7836SJohn.Forte@Sun.COM  * which the data is intended is already bound to the packet, this routine
4311*7836SJohn.Forte@Sun.COM  * only takes care of marking the packet a broadcast packet if it is
4312*7836SJohn.Forte@Sun.COM  * intended to be a broadcast request. This permits the transport to send
4313*7836SJohn.Forte@Sun.COM  * the packet down on the wire even if it doesn't have an entry for the
4314*7836SJohn.Forte@Sun.COM  * D_ID in its d_id hash tables.
4315*7836SJohn.Forte@Sun.COM  */
4316*7836SJohn.Forte@Sun.COM static int
fcip_transport(fcip_pkt_t * fcip_pkt)4317*7836SJohn.Forte@Sun.COM fcip_transport(fcip_pkt_t *fcip_pkt)
4318*7836SJohn.Forte@Sun.COM {
4319*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
4320*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
4321*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
4322*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp;
4323*7836SJohn.Forte@Sun.COM 	uint32_t		did;
4324*7836SJohn.Forte@Sun.COM 	int			rval = FC_FAILURE;
4325*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table *frp = NULL;
4326*7836SJohn.Forte@Sun.COM 
4327*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_transport, "fcip io", /* CSTYLED */,
4328*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
4329*7836SJohn.Forte@Sun.COM 
4330*7836SJohn.Forte@Sun.COM 	fptr = fcip_pkt->fcip_pkt_fptr;
4331*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
4332*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
4333*7836SJohn.Forte@Sun.COM 	fdestp = fcip_pkt->fcip_pkt_dest;
4334*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_WARN, "fcip_transport called"));
4335*7836SJohn.Forte@Sun.COM 
4336*7836SJohn.Forte@Sun.COM 	did = fptr->fcip_broadcast_did;
4337*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_cmd_fhdr.d_id == did &&
4338*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_tran_type != FC_PKT_BROADCAST) {
4339*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
4340*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "trantype set to BROADCAST"));
4341*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_tran_type = FC_PKT_BROADCAST;
4342*7836SJohn.Forte@Sun.COM 	}
4343*7836SJohn.Forte@Sun.COM 
4344*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
4345*7836SJohn.Forte@Sun.COM 	if ((fc_pkt->pkt_tran_type != FC_PKT_BROADCAST) &&
4346*7836SJohn.Forte@Sun.COM 	    (fc_pkt->pkt_pd == NULL)) {
4347*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4348*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_transport, "fcip io", /* CSTYLED */,
4349*7836SJohn.Forte@Sun.COM 		    tnf_string, msg, "fcip transport no pd"));
4350*7836SJohn.Forte@Sun.COM 		return (rval);
4351*7836SJohn.Forte@Sun.COM 	} else if (fptr->fcip_port_state == FCIP_PORT_OFFLINE) {
4352*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4353*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_transport, "fcip io", /* CSTYLED */,
4354*7836SJohn.Forte@Sun.COM 		    tnf_string, msg, "fcip transport port offline"));
4355*7836SJohn.Forte@Sun.COM 		return (FC_TRAN_BUSY);
4356*7836SJohn.Forte@Sun.COM 	}
4357*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
4358*7836SJohn.Forte@Sun.COM 
4359*7836SJohn.Forte@Sun.COM 	if (fdestp) {
4360*7836SJohn.Forte@Sun.COM 		struct fcip_routing_table 	*frp;
4361*7836SJohn.Forte@Sun.COM 
4362*7836SJohn.Forte@Sun.COM 		frp = fdestp->fcipd_rtable;
4363*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
4364*7836SJohn.Forte@Sun.COM 		mutex_enter(&fdestp->fcipd_mutex);
4365*7836SJohn.Forte@Sun.COM 		if (fc_pkt->pkt_pd != NULL) {
4366*7836SJohn.Forte@Sun.COM 			if ((frp == NULL) ||
4367*7836SJohn.Forte@Sun.COM 			    (frp && FCIP_RTE_UNAVAIL(frp->fcipr_state))) {
4368*7836SJohn.Forte@Sun.COM 				mutex_exit(&fdestp->fcipd_mutex);
4369*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_rt_mutex);
4370*7836SJohn.Forte@Sun.COM 				if (frp &&
4371*7836SJohn.Forte@Sun.COM 				    (frp->fcipr_state == FCIP_RT_INVALID)) {
4372*7836SJohn.Forte@Sun.COM 					FCIP_TNF_PROBE_1((fcip_transport,
4373*7836SJohn.Forte@Sun.COM 					    "fcip io", /* CSTYLED */,
4374*7836SJohn.Forte@Sun.COM 					    tnf_string, msg,
4375*7836SJohn.Forte@Sun.COM 					    "fcip transport - TRANBUSY"));
4376*7836SJohn.Forte@Sun.COM 					return (FC_TRAN_BUSY);
4377*7836SJohn.Forte@Sun.COM 				} else {
4378*7836SJohn.Forte@Sun.COM 					FCIP_TNF_PROBE_1((fcip_transport,
4379*7836SJohn.Forte@Sun.COM 					    "fcip io", /* CSTYLED */,
4380*7836SJohn.Forte@Sun.COM 					    tnf_string, msg,
4381*7836SJohn.Forte@Sun.COM 					    "fcip transport: frp unavailable"));
4382*7836SJohn.Forte@Sun.COM 					return (rval);
4383*7836SJohn.Forte@Sun.COM 				}
4384*7836SJohn.Forte@Sun.COM 			}
4385*7836SJohn.Forte@Sun.COM 		}
4386*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
4387*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
4388*7836SJohn.Forte@Sun.COM 		ASSERT(fcip_pkt->fcip_pkt_flags & FCIP_PKT_IN_LIST);
4389*7836SJohn.Forte@Sun.COM 	}
4390*7836SJohn.Forte@Sun.COM 
4391*7836SJohn.Forte@Sun.COM 	/* Explicitly invalidate this field till fcip decides to use it */
4392*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_rscn_infop = NULL;
4393*7836SJohn.Forte@Sun.COM 
4394*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_transport(fport->fcipp_handle, fc_pkt);
4395*7836SJohn.Forte@Sun.COM 	if (rval == FC_STATEC_BUSY || rval == FC_OFFLINE) {
4396*7836SJohn.Forte@Sun.COM 		/*
4397*7836SJohn.Forte@Sun.COM 		 * Need to queue up the command for retry
4398*7836SJohn.Forte@Sun.COM 		 */
4399*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
4400*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "ulp_transport failed: 0x%x", rval));
4401*7836SJohn.Forte@Sun.COM 	} else if (rval == FC_LOGINREQ && (frp != NULL)) {
4402*7836SJohn.Forte@Sun.COM 		(void) fcip_do_plogi(fptr, frp);
4403*7836SJohn.Forte@Sun.COM 	} else if (rval == FC_BADPACKET && (frp != NULL)) {
4404*7836SJohn.Forte@Sun.COM 		/*
4405*7836SJohn.Forte@Sun.COM 		 * There is a distinct possiblity in our scheme of things
4406*7836SJohn.Forte@Sun.COM 		 * that we have a routing table entry with a NULL pd struct.
4407*7836SJohn.Forte@Sun.COM 		 * Mark the routing table entry for removal if it is not a
4408*7836SJohn.Forte@Sun.COM 		 * broadcast entry
4409*7836SJohn.Forte@Sun.COM 		 */
4410*7836SJohn.Forte@Sun.COM 		if ((frp->fcipr_d_id.port_id != 0x0) &&
4411*7836SJohn.Forte@Sun.COM 		    (frp->fcipr_d_id.port_id != 0xffffff)) {
4412*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_rt_mutex);
4413*7836SJohn.Forte@Sun.COM 			frp->fcipr_pd = NULL;
4414*7836SJohn.Forte@Sun.COM 			frp->fcipr_state = PORT_DEVICE_INVALID;
4415*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_rt_mutex);
4416*7836SJohn.Forte@Sun.COM 		}
4417*7836SJohn.Forte@Sun.COM 	}
4418*7836SJohn.Forte@Sun.COM 
4419*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_transport, "fcip io", /* CSTYLED */,
4420*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip transport done"));
4421*7836SJohn.Forte@Sun.COM 	return (rval);
4422*7836SJohn.Forte@Sun.COM }
4423*7836SJohn.Forte@Sun.COM 
4424*7836SJohn.Forte@Sun.COM /*
4425*7836SJohn.Forte@Sun.COM  * Call back routine. Called by the FCA/transport when the messages
4426*7836SJohn.Forte@Sun.COM  * has been put onto the wire towards its intended destination. We can
4427*7836SJohn.Forte@Sun.COM  * now free the fc_packet associated with the message
4428*7836SJohn.Forte@Sun.COM  */
4429*7836SJohn.Forte@Sun.COM static void
fcip_pkt_callback(fc_packet_t * fc_pkt)4430*7836SJohn.Forte@Sun.COM fcip_pkt_callback(fc_packet_t *fc_pkt)
4431*7836SJohn.Forte@Sun.COM {
4432*7836SJohn.Forte@Sun.COM 	int			rval;
4433*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt;
4434*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp;
4435*7836SJohn.Forte@Sun.COM 
4436*7836SJohn.Forte@Sun.COM 	fcip_pkt = (fcip_pkt_t *)fc_pkt->pkt_ulp_private;
4437*7836SJohn.Forte@Sun.COM 	fdestp = fcip_pkt->fcip_pkt_dest;
4438*7836SJohn.Forte@Sun.COM 
4439*7836SJohn.Forte@Sun.COM 	/*
4440*7836SJohn.Forte@Sun.COM 	 * take the lock early so that we don't have a race condition
4441*7836SJohn.Forte@Sun.COM 	 * with fcip_timeout
4442*7836SJohn.Forte@Sun.COM 	 *
4443*7836SJohn.Forte@Sun.COM 	 * fdestp->fcipd_mutex isn't really intended to lock per
4444*7836SJohn.Forte@Sun.COM 	 * packet struct - see bug 5105592 for permanent solution
4445*7836SJohn.Forte@Sun.COM 	 */
4446*7836SJohn.Forte@Sun.COM 	mutex_enter(&fdestp->fcipd_mutex);
4447*7836SJohn.Forte@Sun.COM 
4448*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags |= FCIP_PKT_RETURNED;
4449*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_ABORT;
4450*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_flags & FCIP_PKT_IN_TIMEOUT) {
4451*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
4452*7836SJohn.Forte@Sun.COM 		return;
4453*7836SJohn.Forte@Sun.COM 	}
4454*7836SJohn.Forte@Sun.COM 
4455*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "pkt callback"));
4456*7836SJohn.Forte@Sun.COM 
4457*7836SJohn.Forte@Sun.COM 	ASSERT(fdestp->fcipd_rtable != NULL);
4458*7836SJohn.Forte@Sun.COM 	ASSERT(fcip_pkt->fcip_pkt_flags & FCIP_PKT_IN_LIST);
4459*7836SJohn.Forte@Sun.COM 	rval = fcip_fdestp_dequeue_pkt(fdestp, fcip_pkt);
4460*7836SJohn.Forte@Sun.COM 	fdestp->fcipd_ncmds--;
4461*7836SJohn.Forte@Sun.COM 	mutex_exit(&fdestp->fcipd_mutex);
4462*7836SJohn.Forte@Sun.COM 
4463*7836SJohn.Forte@Sun.COM 	if (rval) {
4464*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, 1);
4465*7836SJohn.Forte@Sun.COM 	}
4466*7836SJohn.Forte@Sun.COM 
4467*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_pkt_callback, "fcip io", /* CSTYLED */,
4468*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "pkt callback done"));
4469*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_NOTE, "pkt callback done"));
4470*7836SJohn.Forte@Sun.COM }
4471*7836SJohn.Forte@Sun.COM 
4472*7836SJohn.Forte@Sun.COM /*
4473*7836SJohn.Forte@Sun.COM  * Return 1 if the topology is supported, else return 0.
4474*7836SJohn.Forte@Sun.COM  * Topology support is consistent with what the whole
4475*7836SJohn.Forte@Sun.COM  * stack supports together.
4476*7836SJohn.Forte@Sun.COM  */
4477*7836SJohn.Forte@Sun.COM static int
fcip_is_supported_fc_topology(int fc_topology)4478*7836SJohn.Forte@Sun.COM fcip_is_supported_fc_topology(int fc_topology)
4479*7836SJohn.Forte@Sun.COM {
4480*7836SJohn.Forte@Sun.COM 	switch (fc_topology) {
4481*7836SJohn.Forte@Sun.COM 
4482*7836SJohn.Forte@Sun.COM 	case FC_TOP_PRIVATE_LOOP :
4483*7836SJohn.Forte@Sun.COM 	case FC_TOP_PUBLIC_LOOP :
4484*7836SJohn.Forte@Sun.COM 	case FC_TOP_FABRIC :
4485*7836SJohn.Forte@Sun.COM 	case FC_TOP_NO_NS :
4486*7836SJohn.Forte@Sun.COM 		return (1);
4487*7836SJohn.Forte@Sun.COM 	default :
4488*7836SJohn.Forte@Sun.COM 		return (0);
4489*7836SJohn.Forte@Sun.COM 	}
4490*7836SJohn.Forte@Sun.COM }
4491*7836SJohn.Forte@Sun.COM 
4492*7836SJohn.Forte@Sun.COM /*
4493*7836SJohn.Forte@Sun.COM  * handle any topology specific initializations here
4494*7836SJohn.Forte@Sun.COM  * this routine must be called while holding fcip_mutex
4495*7836SJohn.Forte@Sun.COM  */
4496*7836SJohn.Forte@Sun.COM /* ARGSUSED */
4497*7836SJohn.Forte@Sun.COM static void
fcip_handle_topology(struct fcip * fptr)4498*7836SJohn.Forte@Sun.COM fcip_handle_topology(struct fcip *fptr)
4499*7836SJohn.Forte@Sun.COM {
4500*7836SJohn.Forte@Sun.COM 
4501*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
4502*7836SJohn.Forte@Sun.COM 
4503*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_mutex));
4504*7836SJohn.Forte@Sun.COM 
4505*7836SJohn.Forte@Sun.COM 	/*
4506*7836SJohn.Forte@Sun.COM 	 * Since we know the port's topology - handle topology
4507*7836SJohn.Forte@Sun.COM 	 * specific details here. In Point to Point and Private Loop
4508*7836SJohn.Forte@Sun.COM 	 * topologies - we would probably not have a name server
4509*7836SJohn.Forte@Sun.COM 	 */
4510*7836SJohn.Forte@Sun.COM 
4511*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_3((fcip_handle_topology, "fcip io", /* CSTYLED */,
4512*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter",
4513*7836SJohn.Forte@Sun.COM 		tnf_uint, port_state, fport->fcipp_pstate,
4514*7836SJohn.Forte@Sun.COM 		tnf_uint, topology, fport->fcipp_topology));
4515*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_NOTE, "port state: %x, topology %x",
4516*7836SJohn.Forte@Sun.COM 		fport->fcipp_pstate, fport->fcipp_topology));
4517*7836SJohn.Forte@Sun.COM 
4518*7836SJohn.Forte@Sun.COM 	fptr->fcip_broadcast_did = fcip_get_broadcast_did(fptr);
4519*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
4520*7836SJohn.Forte@Sun.COM 	(void) fcip_dest_add_broadcast_entry(fptr, 0);
4521*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
4522*7836SJohn.Forte@Sun.COM 
4523*7836SJohn.Forte@Sun.COM 	if (!fcip_is_supported_fc_topology(fport->fcipp_topology)) {
4524*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4525*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "fcip(0x%x): Unsupported port topology (0x%x)",
4526*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance, fport->fcipp_topology));
4527*7836SJohn.Forte@Sun.COM 		return;
4528*7836SJohn.Forte@Sun.COM 	}
4529*7836SJohn.Forte@Sun.COM 
4530*7836SJohn.Forte@Sun.COM 	switch (fport->fcipp_topology) {
4531*7836SJohn.Forte@Sun.COM 	case FC_TOP_PRIVATE_LOOP: {
4532*7836SJohn.Forte@Sun.COM 
4533*7836SJohn.Forte@Sun.COM 		fc_portmap_t		*port_map;
4534*7836SJohn.Forte@Sun.COM 		uint32_t		listlen, alloclen;
4535*7836SJohn.Forte@Sun.COM 		/*
4536*7836SJohn.Forte@Sun.COM 		 * we may have to maintain routing. Get a list of
4537*7836SJohn.Forte@Sun.COM 		 * all devices on this port that the transport layer is
4538*7836SJohn.Forte@Sun.COM 		 * aware of. Check if any of them is a IS8802 type port,
4539*7836SJohn.Forte@Sun.COM 		 * if yes get its WWN and DID mapping and cache it in
4540*7836SJohn.Forte@Sun.COM 		 * the purport routing table. Since there is no
4541*7836SJohn.Forte@Sun.COM 		 * State Change notification for private loop/point_point
4542*7836SJohn.Forte@Sun.COM 		 * topologies - this table may not be accurate. The static
4543*7836SJohn.Forte@Sun.COM 		 * routing table is updated on a state change callback.
4544*7836SJohn.Forte@Sun.COM 		 */
4545*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_WARN, "port state valid!!"));
4546*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_ONLINE;
4547*7836SJohn.Forte@Sun.COM 		listlen = alloclen = FCIP_MAX_PORTS;
4548*7836SJohn.Forte@Sun.COM 		port_map = (fc_portmap_t *)
4549*7836SJohn.Forte@Sun.COM 		    kmem_zalloc((FCIP_MAX_PORTS * sizeof (fc_portmap_t)),
4550*7836SJohn.Forte@Sun.COM 		    KM_SLEEP);
4551*7836SJohn.Forte@Sun.COM 		if (fc_ulp_getportmap(fport->fcipp_handle, &port_map,
4552*7836SJohn.Forte@Sun.COM 		    &listlen, FC_ULP_PLOGI_PRESERVE) == FC_SUCCESS) {
4553*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
4554*7836SJohn.Forte@Sun.COM 			fcip_rt_update(fptr, port_map, listlen);
4555*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_mutex);
4556*7836SJohn.Forte@Sun.COM 		}
4557*7836SJohn.Forte@Sun.COM 		if (listlen > alloclen) {
4558*7836SJohn.Forte@Sun.COM 			alloclen = listlen;
4559*7836SJohn.Forte@Sun.COM 		}
4560*7836SJohn.Forte@Sun.COM 		kmem_free(port_map, (alloclen * sizeof (fc_portmap_t)));
4561*7836SJohn.Forte@Sun.COM 		/*
4562*7836SJohn.Forte@Sun.COM 		 * Now fall through and register with the transport
4563*7836SJohn.Forte@Sun.COM 		 * that this port is IP capable
4564*7836SJohn.Forte@Sun.COM 		 */
4565*7836SJohn.Forte@Sun.COM 	}
4566*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
4567*7836SJohn.Forte@Sun.COM 	case FC_TOP_NO_NS:
4568*7836SJohn.Forte@Sun.COM 		/*
4569*7836SJohn.Forte@Sun.COM 		 * If we don't have a nameserver, lets wait until we
4570*7836SJohn.Forte@Sun.COM 		 * have to send out a packet to a remote port and then
4571*7836SJohn.Forte@Sun.COM 		 * try and discover the port using ARP/FARP.
4572*7836SJohn.Forte@Sun.COM 		 */
4573*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
4574*7836SJohn.Forte@Sun.COM 	case FC_TOP_PUBLIC_LOOP:
4575*7836SJohn.Forte@Sun.COM 	case FC_TOP_FABRIC: {
4576*7836SJohn.Forte@Sun.COM 		fc_portmap_t	*port_map;
4577*7836SJohn.Forte@Sun.COM 		uint32_t	listlen, alloclen;
4578*7836SJohn.Forte@Sun.COM 
4579*7836SJohn.Forte@Sun.COM 		/* FC_TYPE of 0x05 goes to word 0, LSB */
4580*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_ONLINE;
4581*7836SJohn.Forte@Sun.COM 
4582*7836SJohn.Forte@Sun.COM 		if (!(fptr->fcip_flags & FCIP_REG_INPROGRESS)) {
4583*7836SJohn.Forte@Sun.COM 			fptr->fcip_flags |= FCIP_REG_INPROGRESS;
4584*7836SJohn.Forte@Sun.COM 			if (taskq_dispatch(fptr->fcip_tq, fcip_port_ns,
4585*7836SJohn.Forte@Sun.COM 			    fptr, KM_NOSLEEP) == 0) {
4586*7836SJohn.Forte@Sun.COM 				fptr->fcip_flags &= ~FCIP_REG_INPROGRESS;
4587*7836SJohn.Forte@Sun.COM 			}
4588*7836SJohn.Forte@Sun.COM 		}
4589*7836SJohn.Forte@Sun.COM 
4590*7836SJohn.Forte@Sun.COM 		/*
4591*7836SJohn.Forte@Sun.COM 		 * If fcip_create_nodes_on_demand is overridden to force
4592*7836SJohn.Forte@Sun.COM 		 * discovery of all nodes in Fabric/Public loop topologies
4593*7836SJohn.Forte@Sun.COM 		 * we need to query for and obtain all nodes and log into
4594*7836SJohn.Forte@Sun.COM 		 * them as with private loop devices
4595*7836SJohn.Forte@Sun.COM 		 */
4596*7836SJohn.Forte@Sun.COM 		if (!fcip_create_nodes_on_demand) {
4597*7836SJohn.Forte@Sun.COM 			fptr->fcip_port_state = FCIP_PORT_ONLINE;
4598*7836SJohn.Forte@Sun.COM 			listlen = alloclen = FCIP_MAX_PORTS;
4599*7836SJohn.Forte@Sun.COM 			port_map = (fc_portmap_t *)
4600*7836SJohn.Forte@Sun.COM 			    kmem_zalloc((FCIP_MAX_PORTS *
4601*7836SJohn.Forte@Sun.COM 			    sizeof (fc_portmap_t)), KM_SLEEP);
4602*7836SJohn.Forte@Sun.COM 			if (fc_ulp_getportmap(fport->fcipp_handle, &port_map,
4603*7836SJohn.Forte@Sun.COM 			    &listlen, FC_ULP_PLOGI_PRESERVE) == FC_SUCCESS) {
4604*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_mutex);
4605*7836SJohn.Forte@Sun.COM 				fcip_rt_update(fptr, port_map, listlen);
4606*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_mutex);
4607*7836SJohn.Forte@Sun.COM 			}
4608*7836SJohn.Forte@Sun.COM 			if (listlen > alloclen) {
4609*7836SJohn.Forte@Sun.COM 				alloclen = listlen;
4610*7836SJohn.Forte@Sun.COM 			}
4611*7836SJohn.Forte@Sun.COM 			kmem_free(port_map,
4612*7836SJohn.Forte@Sun.COM 			    (alloclen * sizeof (fc_portmap_t)));
4613*7836SJohn.Forte@Sun.COM 		}
4614*7836SJohn.Forte@Sun.COM 		break;
4615*7836SJohn.Forte@Sun.COM 	}
4616*7836SJohn.Forte@Sun.COM 
4617*7836SJohn.Forte@Sun.COM 	default:
4618*7836SJohn.Forte@Sun.COM 		break;
4619*7836SJohn.Forte@Sun.COM 	}
4620*7836SJohn.Forte@Sun.COM }
4621*7836SJohn.Forte@Sun.COM 
4622*7836SJohn.Forte@Sun.COM static void
fcip_port_ns(void * arg)4623*7836SJohn.Forte@Sun.COM fcip_port_ns(void *arg)
4624*7836SJohn.Forte@Sun.COM {
4625*7836SJohn.Forte@Sun.COM 	struct	fcip		*fptr = (struct fcip *)arg;
4626*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
4627*7836SJohn.Forte@Sun.COM 	fc_ns_cmd_t		ns_cmd;
4628*7836SJohn.Forte@Sun.COM 	uint32_t		types[8];
4629*7836SJohn.Forte@Sun.COM 	ns_rfc_type_t		rfc;
4630*7836SJohn.Forte@Sun.COM 
4631*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
4632*7836SJohn.Forte@Sun.COM 	if ((fptr->fcip_flags & (FCIP_DETACHING | FCIP_DETACHED)) ||
4633*7836SJohn.Forte@Sun.COM 	    (fptr->fcip_flags & (FCIP_SUSPENDED | FCIP_POWER_DOWN))) {
4634*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags &= ~FCIP_REG_INPROGRESS;
4635*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4636*7836SJohn.Forte@Sun.COM 		return;
4637*7836SJohn.Forte@Sun.COM 	}
4638*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
4639*7836SJohn.Forte@Sun.COM 
4640*7836SJohn.Forte@Sun.COM 	/*
4641*7836SJohn.Forte@Sun.COM 	 * Prepare the Name server structure to
4642*7836SJohn.Forte@Sun.COM 	 * register with the transport in case of
4643*7836SJohn.Forte@Sun.COM 	 * Fabric configuration.
4644*7836SJohn.Forte@Sun.COM 	 */
4645*7836SJohn.Forte@Sun.COM 	bzero(&rfc, sizeof (rfc));
4646*7836SJohn.Forte@Sun.COM 	bzero(types, sizeof (types));
4647*7836SJohn.Forte@Sun.COM 
4648*7836SJohn.Forte@Sun.COM 	types[FC4_TYPE_WORD_POS(FC_TYPE_IS8802_SNAP)] = (1 <<
4649*7836SJohn.Forte@Sun.COM 	    FC4_TYPE_BIT_POS(FC_TYPE_IS8802_SNAP));
4650*7836SJohn.Forte@Sun.COM 
4651*7836SJohn.Forte@Sun.COM 	rfc.rfc_port_id.port_id = fport->fcipp_sid.port_id;
4652*7836SJohn.Forte@Sun.COM 	bcopy(types, rfc.rfc_types, sizeof (types));
4653*7836SJohn.Forte@Sun.COM 
4654*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_flags = 0;
4655*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_cmd = NS_RFT_ID;
4656*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_req_len = sizeof (rfc);
4657*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_req_payload = (caddr_t)&rfc;
4658*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_resp_len = 0;
4659*7836SJohn.Forte@Sun.COM 	ns_cmd.ns_resp_payload = NULL;
4660*7836SJohn.Forte@Sun.COM 
4661*7836SJohn.Forte@Sun.COM 	/*
4662*7836SJohn.Forte@Sun.COM 	 * Perform the Name Server Registration for FC IS8802_SNAP Type.
4663*7836SJohn.Forte@Sun.COM 	 * We don't expect a reply for registering port type
4664*7836SJohn.Forte@Sun.COM 	 */
4665*7836SJohn.Forte@Sun.COM 	(void) fc_ulp_port_ns(fptr->fcip_port_info->fcipp_handle,
4666*7836SJohn.Forte@Sun.COM 		(opaque_t)0, &ns_cmd);
4667*7836SJohn.Forte@Sun.COM 
4668*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
4669*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~FCIP_REG_INPROGRESS;
4670*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
4671*7836SJohn.Forte@Sun.COM }
4672*7836SJohn.Forte@Sun.COM 
4673*7836SJohn.Forte@Sun.COM /*
4674*7836SJohn.Forte@Sun.COM  * setup this instance of fcip. This routine inits kstats, allocates
4675*7836SJohn.Forte@Sun.COM  * unsolicited buffers, determines' this port's siblings and handles
4676*7836SJohn.Forte@Sun.COM  * topology specific details which includes registering with the name
4677*7836SJohn.Forte@Sun.COM  * server and also setting up the routing table for this port for
4678*7836SJohn.Forte@Sun.COM  * private loops and point to point topologies
4679*7836SJohn.Forte@Sun.COM  */
4680*7836SJohn.Forte@Sun.COM static int
fcip_init_port(struct fcip * fptr)4681*7836SJohn.Forte@Sun.COM fcip_init_port(struct fcip *fptr)
4682*7836SJohn.Forte@Sun.COM {
4683*7836SJohn.Forte@Sun.COM 	int rval = FC_SUCCESS;
4684*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
4685*7836SJohn.Forte@Sun.COM 	static char buf[64];
4686*7836SJohn.Forte@Sun.COM 	size_t	tok_buf_size;
4687*7836SJohn.Forte@Sun.COM 
4688*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
4689*7836SJohn.Forte@Sun.COM 
4690*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_init_port, "fcip io", /* CSTYLED */,
4691*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
4692*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
4693*7836SJohn.Forte@Sun.COM 
4694*7836SJohn.Forte@Sun.COM 	/*
4695*7836SJohn.Forte@Sun.COM 	 * setup mac address for this port. Don't be too worried if
4696*7836SJohn.Forte@Sun.COM 	 * the WWN is zero, there is probably nothing attached to
4697*7836SJohn.Forte@Sun.COM 	 * to the port. There is no point allocating unsolicited buffers
4698*7836SJohn.Forte@Sun.COM 	 * for an unused port so return success if we don't have a MAC
4699*7836SJohn.Forte@Sun.COM 	 * address. Do the port init on a state change notification.
4700*7836SJohn.Forte@Sun.COM 	 */
4701*7836SJohn.Forte@Sun.COM 	if (fcip_setup_mac_addr(fptr) == FCIP_INVALID_WWN) {
4702*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_OFFLINE;
4703*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
4704*7836SJohn.Forte@Sun.COM 		goto done;
4705*7836SJohn.Forte@Sun.COM 	}
4706*7836SJohn.Forte@Sun.COM 
4707*7836SJohn.Forte@Sun.COM 	/*
4708*7836SJohn.Forte@Sun.COM 	 * clear routing table hash list for this port
4709*7836SJohn.Forte@Sun.COM 	 */
4710*7836SJohn.Forte@Sun.COM 	fcip_rt_flush(fptr);
4711*7836SJohn.Forte@Sun.COM 
4712*7836SJohn.Forte@Sun.COM 	/*
4713*7836SJohn.Forte@Sun.COM 	 * init kstats for this instance
4714*7836SJohn.Forte@Sun.COM 	 */
4715*7836SJohn.Forte@Sun.COM 	fcip_kstat_init(fptr);
4716*7836SJohn.Forte@Sun.COM 
4717*7836SJohn.Forte@Sun.COM 	/*
4718*7836SJohn.Forte@Sun.COM 	 * Allocate unsolicited buffers
4719*7836SJohn.Forte@Sun.COM 	 */
4720*7836SJohn.Forte@Sun.COM 	fptr->fcip_ub_nbufs = fcip_ub_nbufs;
4721*7836SJohn.Forte@Sun.COM 	tok_buf_size = sizeof (*fptr->fcip_ub_tokens) * fcip_ub_nbufs;
4722*7836SJohn.Forte@Sun.COM 
4723*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_init_port, "fcip io", /* CSTYLED */,
4724*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "debug",
4725*7836SJohn.Forte@Sun.COM 		tnf_int, tokBufsize, tok_buf_size));
4726*7836SJohn.Forte@Sun.COM 
4727*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_INIT,
4728*7836SJohn.Forte@Sun.COM 	    (CE_WARN, "tokBufsize: 0x%lx", tok_buf_size));
4729*7836SJohn.Forte@Sun.COM 
4730*7836SJohn.Forte@Sun.COM 	fptr->fcip_ub_tokens = kmem_zalloc(tok_buf_size, KM_SLEEP);
4731*7836SJohn.Forte@Sun.COM 
4732*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_ub_tokens == NULL) {
4733*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4734*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4735*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "fcip(%d): failed to allocate unsol buf",
4736*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance));
4737*7836SJohn.Forte@Sun.COM 		goto done;
4738*7836SJohn.Forte@Sun.COM 	}
4739*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_uballoc(fport->fcipp_handle, &fptr->fcip_ub_nbufs,
4740*7836SJohn.Forte@Sun.COM 		fcip_ub_size, FC_TYPE_IS8802_SNAP, fptr->fcip_ub_tokens);
4741*7836SJohn.Forte@Sun.COM 
4742*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
4743*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4744*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "fcip(%d): fc_ulp_uballoc failed with 0x%x!!",
4745*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance, rval));
4746*7836SJohn.Forte@Sun.COM 	}
4747*7836SJohn.Forte@Sun.COM 
4748*7836SJohn.Forte@Sun.COM 	switch (rval) {
4749*7836SJohn.Forte@Sun.COM 	case FC_SUCCESS:
4750*7836SJohn.Forte@Sun.COM 		break;
4751*7836SJohn.Forte@Sun.COM 
4752*7836SJohn.Forte@Sun.COM 	case FC_OFFLINE:
4753*7836SJohn.Forte@Sun.COM 		fptr->fcip_port_state = FCIP_PORT_OFFLINE;
4754*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4755*7836SJohn.Forte@Sun.COM 		goto done;
4756*7836SJohn.Forte@Sun.COM 
4757*7836SJohn.Forte@Sun.COM 	case FC_UB_ERROR:
4758*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_1((fcip_init_port, "fcip io", /* CSTYLED */,
4759*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "invalid ub alloc request"));
4760*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4761*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "invalid ub alloc request !!"));
4762*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4763*7836SJohn.Forte@Sun.COM 		goto done;
4764*7836SJohn.Forte@Sun.COM 
4765*7836SJohn.Forte@Sun.COM 	case FC_FAILURE:
4766*7836SJohn.Forte@Sun.COM 		/*
4767*7836SJohn.Forte@Sun.COM 		 * requested bytes could not be alloced
4768*7836SJohn.Forte@Sun.COM 		 */
4769*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_ub_nbufs != fcip_ub_nbufs) {
4770*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN,
4771*7836SJohn.Forte@Sun.COM 			    "!fcip(0x%x): Failed to alloc unsolicited bufs",
4772*7836SJohn.Forte@Sun.COM 			    ddi_get_instance(fport->fcipp_dip));
4773*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
4774*7836SJohn.Forte@Sun.COM 			goto done;
4775*7836SJohn.Forte@Sun.COM 		}
4776*7836SJohn.Forte@Sun.COM 		break;
4777*7836SJohn.Forte@Sun.COM 
4778*7836SJohn.Forte@Sun.COM 	default:
4779*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4780*7836SJohn.Forte@Sun.COM 		break;
4781*7836SJohn.Forte@Sun.COM 	}
4782*7836SJohn.Forte@Sun.COM 
4783*7836SJohn.Forte@Sun.COM 	/*
4784*7836SJohn.Forte@Sun.COM 	 * Preallocate a Cache of fcip packets for transmit and receive
4785*7836SJohn.Forte@Sun.COM 	 * We don't want to be holding on to unsolicited buffers while
4786*7836SJohn.Forte@Sun.COM 	 * we transmit the message upstream
4787*7836SJohn.Forte@Sun.COM 	 */
4788*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_NOTE, "allocating fcip_pkt cache"));
4789*7836SJohn.Forte@Sun.COM 
4790*7836SJohn.Forte@Sun.COM 	(void) sprintf(buf, "fcip%d_cache", fptr->fcip_instance);
4791*7836SJohn.Forte@Sun.COM 	fptr->fcip_xmit_cache = kmem_cache_create(buf,
4792*7836SJohn.Forte@Sun.COM 		(fport->fcipp_fca_pkt_size + sizeof (fcip_pkt_t)),
4793*7836SJohn.Forte@Sun.COM 		8, fcip_cache_constructor, fcip_cache_destructor,
4794*7836SJohn.Forte@Sun.COM 		NULL, (void *)fport, NULL, 0);
4795*7836SJohn.Forte@Sun.COM 
4796*7836SJohn.Forte@Sun.COM 	(void) sprintf(buf, "fcip%d_sendup_cache", fptr->fcip_instance);
4797*7836SJohn.Forte@Sun.COM 	fptr->fcip_sendup_cache = kmem_cache_create(buf,
4798*7836SJohn.Forte@Sun.COM 		sizeof (struct fcip_sendup_elem),
4799*7836SJohn.Forte@Sun.COM 		8, fcip_sendup_constructor, NULL, NULL, (void *)fport, NULL, 0);
4800*7836SJohn.Forte@Sun.COM 
4801*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_xmit_cache == NULL) {
4802*7836SJohn.Forte@Sun.COM 		FCIP_TNF_PROBE_2((fcip_init_port, "fcip io", /* CSTYLED */,
4803*7836SJohn.Forte@Sun.COM 			tnf_string, msg, "unable to allocate xmit cache",
4804*7836SJohn.Forte@Sun.COM 			tnf_int, instance, fptr->fcip_instance));
4805*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4806*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "fcip%d unable to allocate xmit cache",
4807*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance));
4808*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4809*7836SJohn.Forte@Sun.COM 		goto done;
4810*7836SJohn.Forte@Sun.COM 	}
4811*7836SJohn.Forte@Sun.COM 
4812*7836SJohn.Forte@Sun.COM 	/*
4813*7836SJohn.Forte@Sun.COM 	 * We may need to handle routing tables for point to point and
4814*7836SJohn.Forte@Sun.COM 	 * fcal topologies and register with NameServer for Fabric
4815*7836SJohn.Forte@Sun.COM 	 * topologies.
4816*7836SJohn.Forte@Sun.COM 	 */
4817*7836SJohn.Forte@Sun.COM 	fcip_handle_topology(fptr);
4818*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
4819*7836SJohn.Forte@Sun.COM 	if (fcip_dest_add_broadcast_entry(fptr, 1) != FC_SUCCESS) {
4820*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4821*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "fcip(0x%x):add broadcast entry failed!!",
4822*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance));
4823*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
4824*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
4825*7836SJohn.Forte@Sun.COM 		goto done;
4826*7836SJohn.Forte@Sun.COM 	}
4827*7836SJohn.Forte@Sun.COM 
4828*7836SJohn.Forte@Sun.COM 	rval = FC_SUCCESS;
4829*7836SJohn.Forte@Sun.COM 	return (rval);
4830*7836SJohn.Forte@Sun.COM 
4831*7836SJohn.Forte@Sun.COM done:
4832*7836SJohn.Forte@Sun.COM 	/*
4833*7836SJohn.Forte@Sun.COM 	 * we don't always come here from port_attach - so cleanup
4834*7836SJohn.Forte@Sun.COM 	 * anything done in the init_port routine
4835*7836SJohn.Forte@Sun.COM 	 */
4836*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_kstatp) {
4837*7836SJohn.Forte@Sun.COM 		kstat_delete(fptr->fcip_kstatp);
4838*7836SJohn.Forte@Sun.COM 		fptr->fcip_kstatp = NULL;
4839*7836SJohn.Forte@Sun.COM 	}
4840*7836SJohn.Forte@Sun.COM 
4841*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_xmit_cache) {
4842*7836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fptr->fcip_xmit_cache);
4843*7836SJohn.Forte@Sun.COM 		fptr->fcip_xmit_cache = NULL;
4844*7836SJohn.Forte@Sun.COM 	}
4845*7836SJohn.Forte@Sun.COM 
4846*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_sendup_cache) {
4847*7836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fptr->fcip_sendup_cache);
4848*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_cache = NULL;
4849*7836SJohn.Forte@Sun.COM 	}
4850*7836SJohn.Forte@Sun.COM 
4851*7836SJohn.Forte@Sun.COM 	/* release unsolicited buffers */
4852*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_ub_tokens) {
4853*7836SJohn.Forte@Sun.COM 		uint64_t	*tokens = fptr->fcip_ub_tokens;
4854*7836SJohn.Forte@Sun.COM 		fptr->fcip_ub_tokens = NULL;
4855*7836SJohn.Forte@Sun.COM 
4856*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4857*7836SJohn.Forte@Sun.COM 		(void) fc_ulp_ubfree(fport->fcipp_handle, fptr->fcip_ub_nbufs,
4858*7836SJohn.Forte@Sun.COM 			tokens);
4859*7836SJohn.Forte@Sun.COM 		kmem_free(tokens, tok_buf_size);
4860*7836SJohn.Forte@Sun.COM 
4861*7836SJohn.Forte@Sun.COM 	} else {
4862*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4863*7836SJohn.Forte@Sun.COM 	}
4864*7836SJohn.Forte@Sun.COM 
4865*7836SJohn.Forte@Sun.COM 	return (rval);
4866*7836SJohn.Forte@Sun.COM }
4867*7836SJohn.Forte@Sun.COM 
4868*7836SJohn.Forte@Sun.COM /*
4869*7836SJohn.Forte@Sun.COM  * Sets up a port's MAC address from its WWN
4870*7836SJohn.Forte@Sun.COM  */
4871*7836SJohn.Forte@Sun.COM static int
fcip_setup_mac_addr(struct fcip * fptr)4872*7836SJohn.Forte@Sun.COM fcip_setup_mac_addr(struct fcip *fptr)
4873*7836SJohn.Forte@Sun.COM {
4874*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
4875*7836SJohn.Forte@Sun.COM 
4876*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_mutex));
4877*7836SJohn.Forte@Sun.COM 
4878*7836SJohn.Forte@Sun.COM 	fptr->fcip_addrflags = 0;
4879*7836SJohn.Forte@Sun.COM 
4880*7836SJohn.Forte@Sun.COM 	/*
4881*7836SJohn.Forte@Sun.COM 	 * we cannot choose a MAC address for our interface - we have
4882*7836SJohn.Forte@Sun.COM 	 * to live with whatever node WWN we get (minus the top two
4883*7836SJohn.Forte@Sun.COM 	 * MSbytes for the MAC address) from the transport layer. We will
4884*7836SJohn.Forte@Sun.COM 	 * treat the WWN as our factory MAC address.
4885*7836SJohn.Forte@Sun.COM 	 */
4886*7836SJohn.Forte@Sun.COM 
4887*7836SJohn.Forte@Sun.COM 	if ((fport->fcipp_nwwn.w.wwn_hi != 0) ||
4888*7836SJohn.Forte@Sun.COM 	    (fport->fcipp_nwwn.w.wwn_lo != 0)) {
4889*7836SJohn.Forte@Sun.COM 		char		etherstr[ETHERSTRL];
4890*7836SJohn.Forte@Sun.COM 
4891*7836SJohn.Forte@Sun.COM 		wwn_to_ether(&fport->fcipp_nwwn, &fptr->fcip_macaddr);
4892*7836SJohn.Forte@Sun.COM 		fcip_ether_to_str(&fptr->fcip_macaddr, etherstr);
4893*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4894*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "setupmacaddr ouraddr %s", etherstr));
4895*7836SJohn.Forte@Sun.COM 
4896*7836SJohn.Forte@Sun.COM 		fptr->fcip_addrflags = (FCIP_FACTADDR_PRESENT |
4897*7836SJohn.Forte@Sun.COM 						FCIP_FACTADDR_USE);
4898*7836SJohn.Forte@Sun.COM 	} else {
4899*7836SJohn.Forte@Sun.COM 		/*
4900*7836SJohn.Forte@Sun.COM 		 * No WWN - just return failure - there's not much
4901*7836SJohn.Forte@Sun.COM 		 * we can do since we cannot set the WWN.
4902*7836SJohn.Forte@Sun.COM 		 */
4903*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT,
4904*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "Port does not have a valid WWN"));
4905*7836SJohn.Forte@Sun.COM 		return (FCIP_INVALID_WWN);
4906*7836SJohn.Forte@Sun.COM 	}
4907*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
4908*7836SJohn.Forte@Sun.COM }
4909*7836SJohn.Forte@Sun.COM 
4910*7836SJohn.Forte@Sun.COM 
4911*7836SJohn.Forte@Sun.COM /*
4912*7836SJohn.Forte@Sun.COM  * flush routing table entries
4913*7836SJohn.Forte@Sun.COM  */
4914*7836SJohn.Forte@Sun.COM static void
fcip_rt_flush(struct fcip * fptr)4915*7836SJohn.Forte@Sun.COM fcip_rt_flush(struct fcip *fptr)
4916*7836SJohn.Forte@Sun.COM {
4917*7836SJohn.Forte@Sun.COM 	int index;
4918*7836SJohn.Forte@Sun.COM 
4919*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
4920*7836SJohn.Forte@Sun.COM 	for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
4921*7836SJohn.Forte@Sun.COM 		struct fcip_routing_table 	*frtp, *frtp_next;
4922*7836SJohn.Forte@Sun.COM 		frtp = fptr->fcip_rtable[index];
4923*7836SJohn.Forte@Sun.COM 		while (frtp) {
4924*7836SJohn.Forte@Sun.COM 			frtp_next = frtp->fcipr_next;
4925*7836SJohn.Forte@Sun.COM 			kmem_free(frtp, sizeof (struct fcip_routing_table));
4926*7836SJohn.Forte@Sun.COM 			frtp = frtp_next;
4927*7836SJohn.Forte@Sun.COM 		}
4928*7836SJohn.Forte@Sun.COM 		fptr->fcip_rtable[index] = NULL;
4929*7836SJohn.Forte@Sun.COM 	}
4930*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
4931*7836SJohn.Forte@Sun.COM }
4932*7836SJohn.Forte@Sun.COM 
4933*7836SJohn.Forte@Sun.COM /*
4934*7836SJohn.Forte@Sun.COM  * Free up the fcip softstate and all allocated resources for the
4935*7836SJohn.Forte@Sun.COM  * fcip instance assoicated with a given port driver instance
4936*7836SJohn.Forte@Sun.COM  *
4937*7836SJohn.Forte@Sun.COM  * Given that the list of structures pointed to by fcip_port_head,
4938*7836SJohn.Forte@Sun.COM  * this function is called from multiple sources, and the
4939*7836SJohn.Forte@Sun.COM  * fcip_global_mutex that protects fcip_port_head must be dropped,
4940*7836SJohn.Forte@Sun.COM  * our best solution is to return a value that indicates the next
4941*7836SJohn.Forte@Sun.COM  * port in the list.  This way the caller doesn't need to worry
4942*7836SJohn.Forte@Sun.COM  * about the race condition where he saves off a pointer to the
4943*7836SJohn.Forte@Sun.COM  * next structure in the list and by the time this routine returns,
4944*7836SJohn.Forte@Sun.COM  * that next structure has already been freed.
4945*7836SJohn.Forte@Sun.COM  */
4946*7836SJohn.Forte@Sun.COM static fcip_port_info_t *
fcip_softstate_free(fcip_port_info_t * fport)4947*7836SJohn.Forte@Sun.COM fcip_softstate_free(fcip_port_info_t *fport)
4948*7836SJohn.Forte@Sun.COM {
4949*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr = NULL;
4950*7836SJohn.Forte@Sun.COM 	int 			instance;
4951*7836SJohn.Forte@Sun.COM 	timeout_id_t		tid;
4952*7836SJohn.Forte@Sun.COM 	opaque_t		phandle = NULL;
4953*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*prev_fport, *cur_fport, *next_fport = NULL;
4954*7836SJohn.Forte@Sun.COM 
4955*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fcip_global_mutex));
4956*7836SJohn.Forte@Sun.COM 
4957*7836SJohn.Forte@Sun.COM 	if (fport) {
4958*7836SJohn.Forte@Sun.COM 		phandle = fport->fcipp_handle;
4959*7836SJohn.Forte@Sun.COM 		fptr = fport->fcipp_fcip;
4960*7836SJohn.Forte@Sun.COM 	} else {
4961*7836SJohn.Forte@Sun.COM 		return (next_fport);
4962*7836SJohn.Forte@Sun.COM 	}
4963*7836SJohn.Forte@Sun.COM 
4964*7836SJohn.Forte@Sun.COM 	if (fptr) {
4965*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
4966*7836SJohn.Forte@Sun.COM 		instance = ddi_get_instance(fptr->fcip_dip);
4967*7836SJohn.Forte@Sun.COM 
4968*7836SJohn.Forte@Sun.COM 		/*
4969*7836SJohn.Forte@Sun.COM 		 * dismantle timeout thread for this instance of fcip
4970*7836SJohn.Forte@Sun.COM 		 */
4971*7836SJohn.Forte@Sun.COM 		tid = fptr->fcip_timeout_id;
4972*7836SJohn.Forte@Sun.COM 		fptr->fcip_timeout_id = NULL;
4973*7836SJohn.Forte@Sun.COM 
4974*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
4975*7836SJohn.Forte@Sun.COM 		(void) untimeout(tid);
4976*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
4977*7836SJohn.Forte@Sun.COM 
4978*7836SJohn.Forte@Sun.COM 		ASSERT(fcip_num_instances >= 0);
4979*7836SJohn.Forte@Sun.COM 		fcip_num_instances--;
4980*7836SJohn.Forte@Sun.COM 
4981*7836SJohn.Forte@Sun.COM 		/*
4982*7836SJohn.Forte@Sun.COM 		 * stop sendup thread
4983*7836SJohn.Forte@Sun.COM 		 */
4984*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_sendup_mutex);
4985*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_sendup_thr_initted) {
4986*7836SJohn.Forte@Sun.COM 			fptr->fcip_sendup_thr_initted = 0;
4987*7836SJohn.Forte@Sun.COM 			cv_signal(&fptr->fcip_sendup_cv);
4988*7836SJohn.Forte@Sun.COM 			cv_wait(&fptr->fcip_sendup_cv,
4989*7836SJohn.Forte@Sun.COM 			    &fptr->fcip_sendup_mutex);
4990*7836SJohn.Forte@Sun.COM 		}
4991*7836SJohn.Forte@Sun.COM 		ASSERT(fptr->fcip_sendup_head == NULL);
4992*7836SJohn.Forte@Sun.COM 		fptr->fcip_sendup_head = fptr->fcip_sendup_tail = NULL;
4993*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_sendup_mutex);
4994*7836SJohn.Forte@Sun.COM 
4995*7836SJohn.Forte@Sun.COM 		/*
4996*7836SJohn.Forte@Sun.COM 		 * dismantle taskq
4997*7836SJohn.Forte@Sun.COM 		 */
4998*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_tq) {
4999*7836SJohn.Forte@Sun.COM 			taskq_t	*tq = fptr->fcip_tq;
5000*7836SJohn.Forte@Sun.COM 
5001*7836SJohn.Forte@Sun.COM 			fptr->fcip_tq = NULL;
5002*7836SJohn.Forte@Sun.COM 
5003*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
5004*7836SJohn.Forte@Sun.COM 			taskq_destroy(tq);
5005*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_mutex);
5006*7836SJohn.Forte@Sun.COM 		}
5007*7836SJohn.Forte@Sun.COM 
5008*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_kstatp) {
5009*7836SJohn.Forte@Sun.COM 			kstat_delete(fptr->fcip_kstatp);
5010*7836SJohn.Forte@Sun.COM 			fptr->fcip_kstatp = NULL;
5011*7836SJohn.Forte@Sun.COM 		}
5012*7836SJohn.Forte@Sun.COM 
5013*7836SJohn.Forte@Sun.COM 		/* flush the routing table entries */
5014*7836SJohn.Forte@Sun.COM 		fcip_rt_flush(fptr);
5015*7836SJohn.Forte@Sun.COM 
5016*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_xmit_cache) {
5017*7836SJohn.Forte@Sun.COM 			kmem_cache_destroy(fptr->fcip_xmit_cache);
5018*7836SJohn.Forte@Sun.COM 			fptr->fcip_xmit_cache = NULL;
5019*7836SJohn.Forte@Sun.COM 		}
5020*7836SJohn.Forte@Sun.COM 
5021*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_sendup_cache) {
5022*7836SJohn.Forte@Sun.COM 			kmem_cache_destroy(fptr->fcip_sendup_cache);
5023*7836SJohn.Forte@Sun.COM 			fptr->fcip_sendup_cache = NULL;
5024*7836SJohn.Forte@Sun.COM 		}
5025*7836SJohn.Forte@Sun.COM 
5026*7836SJohn.Forte@Sun.COM 		fcip_cleanup_dest(fptr);
5027*7836SJohn.Forte@Sun.COM 
5028*7836SJohn.Forte@Sun.COM 		/* release unsolicited buffers */
5029*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_ub_tokens) {
5030*7836SJohn.Forte@Sun.COM 			uint64_t	*tokens = fptr->fcip_ub_tokens;
5031*7836SJohn.Forte@Sun.COM 
5032*7836SJohn.Forte@Sun.COM 			fptr->fcip_ub_tokens = NULL;
5033*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
5034*7836SJohn.Forte@Sun.COM 			if (phandle) {
5035*7836SJohn.Forte@Sun.COM 				/*
5036*7836SJohn.Forte@Sun.COM 				 * release the global mutex here to
5037*7836SJohn.Forte@Sun.COM 				 * permit any data pending callbacks to
5038*7836SJohn.Forte@Sun.COM 				 * complete. Else we will deadlock in the
5039*7836SJohn.Forte@Sun.COM 				 * FCA waiting for all unsol buffers to be
5040*7836SJohn.Forte@Sun.COM 				 * returned.
5041*7836SJohn.Forte@Sun.COM 				 */
5042*7836SJohn.Forte@Sun.COM 				mutex_exit(&fcip_global_mutex);
5043*7836SJohn.Forte@Sun.COM 				(void) fc_ulp_ubfree(phandle,
5044*7836SJohn.Forte@Sun.COM 				    fptr->fcip_ub_nbufs, tokens);
5045*7836SJohn.Forte@Sun.COM 				mutex_enter(&fcip_global_mutex);
5046*7836SJohn.Forte@Sun.COM 			}
5047*7836SJohn.Forte@Sun.COM 			kmem_free(tokens, (sizeof (*tokens) * fcip_ub_nbufs));
5048*7836SJohn.Forte@Sun.COM 		} else {
5049*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_mutex);
5050*7836SJohn.Forte@Sun.COM 		}
5051*7836SJohn.Forte@Sun.COM 
5052*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fptr->fcip_mutex);
5053*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fptr->fcip_ub_mutex);
5054*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fptr->fcip_rt_mutex);
5055*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fptr->fcip_dest_mutex);
5056*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fptr->fcip_sendup_mutex);
5057*7836SJohn.Forte@Sun.COM 		cv_destroy(&fptr->fcip_farp_cv);
5058*7836SJohn.Forte@Sun.COM 		cv_destroy(&fptr->fcip_sendup_cv);
5059*7836SJohn.Forte@Sun.COM 		cv_destroy(&fptr->fcip_ub_cv);
5060*7836SJohn.Forte@Sun.COM 
5061*7836SJohn.Forte@Sun.COM 		ddi_soft_state_free(fcip_softp, instance);
5062*7836SJohn.Forte@Sun.COM 	}
5063*7836SJohn.Forte@Sun.COM 
5064*7836SJohn.Forte@Sun.COM 	/*
5065*7836SJohn.Forte@Sun.COM 	 * Now dequeue the fcip_port_info from the port list
5066*7836SJohn.Forte@Sun.COM 	 */
5067*7836SJohn.Forte@Sun.COM 	cur_fport = fcip_port_head;
5068*7836SJohn.Forte@Sun.COM 	prev_fport = NULL;
5069*7836SJohn.Forte@Sun.COM 	while (cur_fport != NULL) {
5070*7836SJohn.Forte@Sun.COM 		if (cur_fport == fport) {
5071*7836SJohn.Forte@Sun.COM 			break;
5072*7836SJohn.Forte@Sun.COM 		}
5073*7836SJohn.Forte@Sun.COM 		prev_fport = cur_fport;
5074*7836SJohn.Forte@Sun.COM 		cur_fport = cur_fport->fcipp_next;
5075*7836SJohn.Forte@Sun.COM 	}
5076*7836SJohn.Forte@Sun.COM 
5077*7836SJohn.Forte@Sun.COM 	/*
5078*7836SJohn.Forte@Sun.COM 	 * Assert that we found a port in our port list
5079*7836SJohn.Forte@Sun.COM 	 */
5080*7836SJohn.Forte@Sun.COM 	ASSERT(cur_fport == fport);
5081*7836SJohn.Forte@Sun.COM 
5082*7836SJohn.Forte@Sun.COM 	if (prev_fport) {
5083*7836SJohn.Forte@Sun.COM 		/*
5084*7836SJohn.Forte@Sun.COM 		 * Not the first port in the port list
5085*7836SJohn.Forte@Sun.COM 		 */
5086*7836SJohn.Forte@Sun.COM 		prev_fport->fcipp_next = fport->fcipp_next;
5087*7836SJohn.Forte@Sun.COM 	} else {
5088*7836SJohn.Forte@Sun.COM 		/*
5089*7836SJohn.Forte@Sun.COM 		 * first port
5090*7836SJohn.Forte@Sun.COM 		 */
5091*7836SJohn.Forte@Sun.COM 		fcip_port_head = fport->fcipp_next;
5092*7836SJohn.Forte@Sun.COM 	}
5093*7836SJohn.Forte@Sun.COM 	next_fport = fport->fcipp_next;
5094*7836SJohn.Forte@Sun.COM 	kmem_free(fport, sizeof (fcip_port_info_t));
5095*7836SJohn.Forte@Sun.COM 
5096*7836SJohn.Forte@Sun.COM 	return (next_fport);
5097*7836SJohn.Forte@Sun.COM }
5098*7836SJohn.Forte@Sun.COM 
5099*7836SJohn.Forte@Sun.COM 
5100*7836SJohn.Forte@Sun.COM /*
5101*7836SJohn.Forte@Sun.COM  * This is called by transport for any ioctl operations performed
5102*7836SJohn.Forte@Sun.COM  * on the devctl or other transport minor nodes. It is currently
5103*7836SJohn.Forte@Sun.COM  * unused for fcip
5104*7836SJohn.Forte@Sun.COM  */
5105*7836SJohn.Forte@Sun.COM /* ARGSUSED */
5106*7836SJohn.Forte@Sun.COM static int
fcip_port_ioctl(opaque_t ulp_handle,opaque_t port_handle,dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval,uint32_t claimed)5107*7836SJohn.Forte@Sun.COM fcip_port_ioctl(opaque_t ulp_handle,  opaque_t port_handle, dev_t dev,
5108*7836SJohn.Forte@Sun.COM 	int cmd, intptr_t data, int mode, cred_t *credp, int *rval,
5109*7836SJohn.Forte@Sun.COM 	uint32_t claimed)
5110*7836SJohn.Forte@Sun.COM {
5111*7836SJohn.Forte@Sun.COM 	return (FC_UNCLAIMED);
5112*7836SJohn.Forte@Sun.COM }
5113*7836SJohn.Forte@Sun.COM 
5114*7836SJohn.Forte@Sun.COM /*
5115*7836SJohn.Forte@Sun.COM  * DL_INFO_REQ - returns information about the DLPI stream to the DLS user
5116*7836SJohn.Forte@Sun.COM  * requesting information about this interface
5117*7836SJohn.Forte@Sun.COM  */
5118*7836SJohn.Forte@Sun.COM static void
fcip_ireq(queue_t * wq,mblk_t * mp)5119*7836SJohn.Forte@Sun.COM fcip_ireq(queue_t *wq, mblk_t *mp)
5120*7836SJohn.Forte@Sun.COM {
5121*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5122*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5123*7836SJohn.Forte@Sun.COM 	dl_info_ack_t		*dlip;
5124*7836SJohn.Forte@Sun.COM 	struct fcipdladdr	*dlap;
5125*7836SJohn.Forte@Sun.COM 	la_wwn_t		*ep;
5126*7836SJohn.Forte@Sun.COM 	int 			size;
5127*7836SJohn.Forte@Sun.COM 	char			etherstr[ETHERSTRL];
5128*7836SJohn.Forte@Sun.COM 
5129*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5130*7836SJohn.Forte@Sun.COM 
5131*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
5132*7836SJohn.Forte@Sun.COM 
5133*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI,
5134*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "fcip_ireq: info request req rcvd"));
5135*7836SJohn.Forte@Sun.COM 
5136*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_ireq, "fcip io", /* CSTYLED */,
5137*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip ireq entered"));
5138*7836SJohn.Forte@Sun.COM 
5139*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_INFO_REQ_SIZE) {
5140*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0);
5141*7836SJohn.Forte@Sun.COM 		return;
5142*7836SJohn.Forte@Sun.COM 	}
5143*7836SJohn.Forte@Sun.COM 
5144*7836SJohn.Forte@Sun.COM 	/*
5145*7836SJohn.Forte@Sun.COM 	 * Exchange current message for a DL_INFO_ACK
5146*7836SJohn.Forte@Sun.COM 	 */
5147*7836SJohn.Forte@Sun.COM 	size = sizeof (dl_info_ack_t) + FCIPADDRL + ETHERADDRL;
5148*7836SJohn.Forte@Sun.COM 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) {
5149*7836SJohn.Forte@Sun.COM 		return;
5150*7836SJohn.Forte@Sun.COM 	}
5151*7836SJohn.Forte@Sun.COM 
5152*7836SJohn.Forte@Sun.COM 	/*
5153*7836SJohn.Forte@Sun.COM 	 * FILL in the DL_INFO_ACK fields and reply
5154*7836SJohn.Forte@Sun.COM 	 */
5155*7836SJohn.Forte@Sun.COM 	dlip = (dl_info_ack_t *)mp->b_rptr;
5156*7836SJohn.Forte@Sun.COM 	*dlip = fcip_infoack;
5157*7836SJohn.Forte@Sun.COM 	dlip->dl_current_state = slp->sl_state;
5158*7836SJohn.Forte@Sun.COM 	dlap = (struct fcipdladdr *)(mp->b_rptr + dlip->dl_addr_offset);
5159*7836SJohn.Forte@Sun.COM 	dlap->dl_sap = slp->sl_sap;
5160*7836SJohn.Forte@Sun.COM 
5161*7836SJohn.Forte@Sun.COM 
5162*7836SJohn.Forte@Sun.COM 	if (fptr) {
5163*7836SJohn.Forte@Sun.COM 		fcip_ether_to_str(&fptr->fcip_macaddr, etherstr);
5164*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5165*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "ireq - our mac: %s", etherstr));
5166*7836SJohn.Forte@Sun.COM 		ether_bcopy(&fptr->fcip_macaddr, &dlap->dl_phys);
5167*7836SJohn.Forte@Sun.COM 	} else {
5168*7836SJohn.Forte@Sun.COM 		bzero((caddr_t)&dlap->dl_phys, ETHERADDRL);
5169*7836SJohn.Forte@Sun.COM 	}
5170*7836SJohn.Forte@Sun.COM 
5171*7836SJohn.Forte@Sun.COM 	ep = (la_wwn_t *)(mp->b_rptr + dlip->dl_brdcst_addr_offset);
5172*7836SJohn.Forte@Sun.COM 	ether_bcopy(&fcip_arpbroadcast_addr, ep);
5173*7836SJohn.Forte@Sun.COM 
5174*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "sending back info req.."));
5175*7836SJohn.Forte@Sun.COM 	qreply(wq, mp);
5176*7836SJohn.Forte@Sun.COM }
5177*7836SJohn.Forte@Sun.COM 
5178*7836SJohn.Forte@Sun.COM 
5179*7836SJohn.Forte@Sun.COM /*
5180*7836SJohn.Forte@Sun.COM  * To handle DL_UNITDATA_REQ requests.
5181*7836SJohn.Forte@Sun.COM  */
5182*7836SJohn.Forte@Sun.COM 
5183*7836SJohn.Forte@Sun.COM static void
fcip_udreq(queue_t * wq,mblk_t * mp)5184*7836SJohn.Forte@Sun.COM fcip_udreq(queue_t *wq, mblk_t *mp)
5185*7836SJohn.Forte@Sun.COM {
5186*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5187*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5188*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
5189*7836SJohn.Forte@Sun.COM 	dl_unitdata_req_t	*dludp;
5190*7836SJohn.Forte@Sun.COM 	mblk_t			*nmp;
5191*7836SJohn.Forte@Sun.COM 	struct fcipdladdr	*dlap;
5192*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t 	*headerp;
5193*7836SJohn.Forte@Sun.COM 	llc_snap_hdr_t		*lsnap;
5194*7836SJohn.Forte@Sun.COM 	t_uscalar_t		off, len;
5195*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp;
5196*7836SJohn.Forte@Sun.COM 	la_wwn_t		wwn;
5197*7836SJohn.Forte@Sun.COM 	int			hdr_size;
5198*7836SJohn.Forte@Sun.COM 
5199*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "inside fcip_udreq"));
5200*7836SJohn.Forte@Sun.COM 
5201*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_udreq, "fcip io", /* CSTYLED */,
5202*7836SJohn.Forte@Sun.COM 	    tnf_string, msg, "fcip udreq entered"));
5203*7836SJohn.Forte@Sun.COM 
5204*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5205*7836SJohn.Forte@Sun.COM 
5206*7836SJohn.Forte@Sun.COM 	if (slp->sl_state != DL_IDLE) {
5207*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
5208*7836SJohn.Forte@Sun.COM 		return;
5209*7836SJohn.Forte@Sun.COM 	}
5210*7836SJohn.Forte@Sun.COM 
5211*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
5212*7836SJohn.Forte@Sun.COM 
5213*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
5214*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
5215*7836SJohn.Forte@Sun.COM 		return;
5216*7836SJohn.Forte@Sun.COM 	}
5217*7836SJohn.Forte@Sun.COM 
5218*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
5219*7836SJohn.Forte@Sun.COM 
5220*7836SJohn.Forte@Sun.COM 	dludp = (dl_unitdata_req_t *)mp->b_rptr;
5221*7836SJohn.Forte@Sun.COM 	off = dludp->dl_dest_addr_offset;
5222*7836SJohn.Forte@Sun.COM 	len = dludp->dl_dest_addr_length;
5223*7836SJohn.Forte@Sun.COM 
5224*7836SJohn.Forte@Sun.COM 	/*
5225*7836SJohn.Forte@Sun.COM 	 * Validate destination address format
5226*7836SJohn.Forte@Sun.COM 	 */
5227*7836SJohn.Forte@Sun.COM 	if (!MBLKIN(mp, off, len) || (len != FCIPADDRL)) {
5228*7836SJohn.Forte@Sun.COM 		dluderrorind(wq, mp, (mp->b_rptr + off), len, DL_BADADDR, 0);
5229*7836SJohn.Forte@Sun.COM 		return;
5230*7836SJohn.Forte@Sun.COM 	}
5231*7836SJohn.Forte@Sun.COM 
5232*7836SJohn.Forte@Sun.COM 	/*
5233*7836SJohn.Forte@Sun.COM 	 * Error if no M_DATA follows
5234*7836SJohn.Forte@Sun.COM 	 */
5235*7836SJohn.Forte@Sun.COM 	nmp = mp->b_cont;
5236*7836SJohn.Forte@Sun.COM 	if (nmp == NULL) {
5237*7836SJohn.Forte@Sun.COM 		dluderrorind(wq, mp, (mp->b_rptr + off), len, DL_BADDATA, 0);
5238*7836SJohn.Forte@Sun.COM 		return;
5239*7836SJohn.Forte@Sun.COM 	}
5240*7836SJohn.Forte@Sun.COM 	dlap = (struct fcipdladdr *)(mp->b_rptr + off);
5241*7836SJohn.Forte@Sun.COM 
5242*7836SJohn.Forte@Sun.COM 	/*
5243*7836SJohn.Forte@Sun.COM 	 * Now get the destination structure for the remote NPORT
5244*7836SJohn.Forte@Sun.COM 	 */
5245*7836SJohn.Forte@Sun.COM 	ether_to_wwn(&dlap->dl_phys, &wwn);
5246*7836SJohn.Forte@Sun.COM 	fdestp = fcip_get_dest(fptr, &wwn);
5247*7836SJohn.Forte@Sun.COM 
5248*7836SJohn.Forte@Sun.COM 	if (fdestp == NULL) {
5249*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE,
5250*7836SJohn.Forte@Sun.COM 		    "udreq - couldn't find dest struct for remote port");
5251*7836SJohn.Forte@Sun.COM 		dluderrorind(wq, mp, (mp->b_rptr + off), len, DL_BADDATA, 0));
5252*7836SJohn.Forte@Sun.COM 		return;
5253*7836SJohn.Forte@Sun.COM 	}
5254*7836SJohn.Forte@Sun.COM 
5255*7836SJohn.Forte@Sun.COM 	/*
5256*7836SJohn.Forte@Sun.COM 	 * Network header + SAP
5257*7836SJohn.Forte@Sun.COM 	 */
5258*7836SJohn.Forte@Sun.COM 	hdr_size = sizeof (fcph_network_hdr_t) + sizeof (llc_snap_hdr_t);
5259*7836SJohn.Forte@Sun.COM 
5260*7836SJohn.Forte@Sun.COM 	/* DB_REF gives the no. of msgs pointing to this block */
5261*7836SJohn.Forte@Sun.COM 	if ((DB_REF(nmp) == 1) &&
5262*7836SJohn.Forte@Sun.COM 	    (MBLKHEAD(nmp) >= hdr_size) &&
5263*7836SJohn.Forte@Sun.COM 	    (((uintptr_t)mp->b_rptr & 0x1) == 0)) {
5264*7836SJohn.Forte@Sun.COM 		la_wwn_t wwn;
5265*7836SJohn.Forte@Sun.COM 		nmp->b_rptr -= hdr_size;
5266*7836SJohn.Forte@Sun.COM 
5267*7836SJohn.Forte@Sun.COM 		/* first put the network header */
5268*7836SJohn.Forte@Sun.COM 		headerp = (fcph_network_hdr_t *)nmp->b_rptr;
5269*7836SJohn.Forte@Sun.COM 		if (ether_cmp(&dlap->dl_phys, &fcip_arpbroadcast_addr) == 0) {
5270*7836SJohn.Forte@Sun.COM 			ether_to_wwn(&fcipnhbroadcastaddr, &wwn);
5271*7836SJohn.Forte@Sun.COM 		} else {
5272*7836SJohn.Forte@Sun.COM 			ether_to_wwn(&dlap->dl_phys, &wwn);
5273*7836SJohn.Forte@Sun.COM 		}
5274*7836SJohn.Forte@Sun.COM 		bcopy(&wwn, &headerp->net_dest_addr, sizeof (la_wwn_t));
5275*7836SJohn.Forte@Sun.COM 		ether_to_wwn(&fptr->fcip_macaddr, &wwn);
5276*7836SJohn.Forte@Sun.COM 		bcopy(&wwn, &headerp->net_src_addr, sizeof (la_wwn_t));
5277*7836SJohn.Forte@Sun.COM 
5278*7836SJohn.Forte@Sun.COM 		/* Now the snap header */
5279*7836SJohn.Forte@Sun.COM 		lsnap = (llc_snap_hdr_t *)(nmp->b_rptr +
5280*7836SJohn.Forte@Sun.COM 		    sizeof (fcph_network_hdr_t));
5281*7836SJohn.Forte@Sun.COM 		lsnap->dsap = 0xAA;
5282*7836SJohn.Forte@Sun.COM 		lsnap->ssap = 0xAA;
5283*7836SJohn.Forte@Sun.COM 		lsnap->ctrl = 0x03;
5284*7836SJohn.Forte@Sun.COM 		lsnap->oui[0] = 0x00;
5285*7836SJohn.Forte@Sun.COM 		lsnap->oui[1] = 0x00; 	/* 80 */
5286*7836SJohn.Forte@Sun.COM 		lsnap->oui[2] = 0x00;	/* C2 */
5287*7836SJohn.Forte@Sun.COM 		lsnap->pid = BE_16((dlap->dl_sap));
5288*7836SJohn.Forte@Sun.COM 
5289*7836SJohn.Forte@Sun.COM 		freeb(mp);
5290*7836SJohn.Forte@Sun.COM 		mp = nmp;
5291*7836SJohn.Forte@Sun.COM 
5292*7836SJohn.Forte@Sun.COM 	} else {
5293*7836SJohn.Forte@Sun.COM 		la_wwn_t wwn;
5294*7836SJohn.Forte@Sun.COM 
5295*7836SJohn.Forte@Sun.COM 		DB_TYPE(mp) = M_DATA;
5296*7836SJohn.Forte@Sun.COM 		headerp = (fcph_network_hdr_t *)mp->b_rptr;
5297*7836SJohn.Forte@Sun.COM 
5298*7836SJohn.Forte@Sun.COM 		/*
5299*7836SJohn.Forte@Sun.COM 		 * Only fill in the low 48bits of WWN for now - we can
5300*7836SJohn.Forte@Sun.COM 		 * fill in the NAA_ID after we find the port in the
5301*7836SJohn.Forte@Sun.COM 		 * routing tables
5302*7836SJohn.Forte@Sun.COM 		 */
5303*7836SJohn.Forte@Sun.COM 		if (ether_cmp(&dlap->dl_phys, &fcip_arpbroadcast_addr) == 0) {
5304*7836SJohn.Forte@Sun.COM 			ether_to_wwn(&fcipnhbroadcastaddr, &wwn);
5305*7836SJohn.Forte@Sun.COM 		} else {
5306*7836SJohn.Forte@Sun.COM 			ether_to_wwn(&dlap->dl_phys, &wwn);
5307*7836SJohn.Forte@Sun.COM 		}
5308*7836SJohn.Forte@Sun.COM 		bcopy(&wwn, &headerp->net_dest_addr, sizeof (la_wwn_t));
5309*7836SJohn.Forte@Sun.COM 		/* need to send our PWWN */
5310*7836SJohn.Forte@Sun.COM 		bcopy(&fport->fcipp_pwwn, &headerp->net_src_addr,
5311*7836SJohn.Forte@Sun.COM 		    sizeof (la_wwn_t));
5312*7836SJohn.Forte@Sun.COM 
5313*7836SJohn.Forte@Sun.COM 		lsnap = (llc_snap_hdr_t *)(nmp->b_rptr +
5314*7836SJohn.Forte@Sun.COM 		    sizeof (fcph_network_hdr_t));
5315*7836SJohn.Forte@Sun.COM 		lsnap->dsap = 0xAA;
5316*7836SJohn.Forte@Sun.COM 		lsnap->ssap = 0xAA;
5317*7836SJohn.Forte@Sun.COM 		lsnap->ctrl = 0x03;
5318*7836SJohn.Forte@Sun.COM 		lsnap->oui[0] = 0x00;
5319*7836SJohn.Forte@Sun.COM 		lsnap->oui[1] = 0x00;
5320*7836SJohn.Forte@Sun.COM 		lsnap->oui[2] = 0x00;
5321*7836SJohn.Forte@Sun.COM 		lsnap->pid = BE_16(dlap->dl_sap);
5322*7836SJohn.Forte@Sun.COM 
5323*7836SJohn.Forte@Sun.COM 		mp->b_wptr = mp->b_rptr + hdr_size;
5324*7836SJohn.Forte@Sun.COM 	}
5325*7836SJohn.Forte@Sun.COM 
5326*7836SJohn.Forte@Sun.COM 	/*
5327*7836SJohn.Forte@Sun.COM 	 * Ethernet drivers have a lot of gunk here to put the Type
5328*7836SJohn.Forte@Sun.COM 	 * information (for Ethernet encapsulation (RFC 894) or the
5329*7836SJohn.Forte@Sun.COM 	 * Length (for 802.2/802.3) - I guess we'll just ignore that
5330*7836SJohn.Forte@Sun.COM 	 * here.
5331*7836SJohn.Forte@Sun.COM 	 */
5332*7836SJohn.Forte@Sun.COM 
5333*7836SJohn.Forte@Sun.COM 	/*
5334*7836SJohn.Forte@Sun.COM 	 * Start the I/O on this port. If fcip_start failed for some reason
5335*7836SJohn.Forte@Sun.COM 	 * we call putbq in fcip_start so we don't need to check the
5336*7836SJohn.Forte@Sun.COM 	 * return value from fcip_start
5337*7836SJohn.Forte@Sun.COM 	 */
5338*7836SJohn.Forte@Sun.COM 	(void) fcip_start(wq, mp, fptr, fdestp, KM_SLEEP);
5339*7836SJohn.Forte@Sun.COM }
5340*7836SJohn.Forte@Sun.COM 
5341*7836SJohn.Forte@Sun.COM /*
5342*7836SJohn.Forte@Sun.COM  * DL_ATTACH_REQ: attaches a PPA with a stream. ATTACH requets are needed
5343*7836SJohn.Forte@Sun.COM  * for style 2 DLS providers to identify the physical medium through which
5344*7836SJohn.Forte@Sun.COM  * the streams communication will happen
5345*7836SJohn.Forte@Sun.COM  */
5346*7836SJohn.Forte@Sun.COM static void
fcip_areq(queue_t * wq,mblk_t * mp)5347*7836SJohn.Forte@Sun.COM fcip_areq(queue_t *wq, mblk_t *mp)
5348*7836SJohn.Forte@Sun.COM {
5349*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5350*7836SJohn.Forte@Sun.COM 	union DL_primitives	*dlp;
5351*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
5352*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5353*7836SJohn.Forte@Sun.COM 	int			ppa;
5354*7836SJohn.Forte@Sun.COM 
5355*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5356*7836SJohn.Forte@Sun.COM 	dlp = (union DL_primitives *)mp->b_rptr;
5357*7836SJohn.Forte@Sun.COM 
5358*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) {
5359*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0);
5360*7836SJohn.Forte@Sun.COM 		return;
5361*7836SJohn.Forte@Sun.COM 	}
5362*7836SJohn.Forte@Sun.COM 
5363*7836SJohn.Forte@Sun.COM 	if (slp->sl_state != DL_UNATTACHED) {
5364*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0);
5365*7836SJohn.Forte@Sun.COM 		return;
5366*7836SJohn.Forte@Sun.COM 	}
5367*7836SJohn.Forte@Sun.COM 
5368*7836SJohn.Forte@Sun.COM 	ppa = dlp->attach_req.dl_ppa;
5369*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "attach req: ppa %x", ppa));
5370*7836SJohn.Forte@Sun.COM 
5371*7836SJohn.Forte@Sun.COM 	/*
5372*7836SJohn.Forte@Sun.COM 	 * check if the PPA is valid
5373*7836SJohn.Forte@Sun.COM 	 */
5374*7836SJohn.Forte@Sun.COM 
5375*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
5376*7836SJohn.Forte@Sun.COM 
5377*7836SJohn.Forte@Sun.COM 	for (fport = fcip_port_head; fport; fport = fport->fcipp_next) {
5378*7836SJohn.Forte@Sun.COM 		if ((fptr = fport->fcipp_fcip) == NULL) {
5379*7836SJohn.Forte@Sun.COM 			continue;
5380*7836SJohn.Forte@Sun.COM 		}
5381*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "ppa %x, inst %x", ppa,
5382*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(fptr->fcip_dip)));
5383*7836SJohn.Forte@Sun.COM 
5384*7836SJohn.Forte@Sun.COM 		if (ppa == ddi_get_instance(fptr->fcip_dip)) {
5385*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_DLPI,
5386*7836SJohn.Forte@Sun.COM 			    (CE_NOTE, "ppa found %x", ppa));
5387*7836SJohn.Forte@Sun.COM 			break;
5388*7836SJohn.Forte@Sun.COM 		}
5389*7836SJohn.Forte@Sun.COM 	}
5390*7836SJohn.Forte@Sun.COM 
5391*7836SJohn.Forte@Sun.COM 	if (fport == NULL) {
5392*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5393*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "dlerrorack coz fport==NULL"));
5394*7836SJohn.Forte@Sun.COM 
5395*7836SJohn.Forte@Sun.COM 		mutex_exit(&fcip_global_mutex);
5396*7836SJohn.Forte@Sun.COM 
5397*7836SJohn.Forte@Sun.COM 		if (fc_ulp_get_port_handle(ppa) == NULL) {
5398*7836SJohn.Forte@Sun.COM 			dlerrorack(wq, mp, DL_ATTACH_REQ, DL_BADPPA, 0);
5399*7836SJohn.Forte@Sun.COM 			return;
5400*7836SJohn.Forte@Sun.COM 		}
5401*7836SJohn.Forte@Sun.COM 
5402*7836SJohn.Forte@Sun.COM 		/*
5403*7836SJohn.Forte@Sun.COM 		 * Wait for Port attach callback to trigger.  If port_detach
5404*7836SJohn.Forte@Sun.COM 		 * got in while we were waiting, then ddi_get_soft_state
5405*7836SJohn.Forte@Sun.COM 		 * will return NULL, and we'll return error.
5406*7836SJohn.Forte@Sun.COM 		 */
5407*7836SJohn.Forte@Sun.COM 
5408*7836SJohn.Forte@Sun.COM 		delay(drv_usectohz(FCIP_INIT_DELAY));
5409*7836SJohn.Forte@Sun.COM 		mutex_enter(&fcip_global_mutex);
5410*7836SJohn.Forte@Sun.COM 
5411*7836SJohn.Forte@Sun.COM 		fptr = ddi_get_soft_state(fcip_softp, ppa);
5412*7836SJohn.Forte@Sun.COM 		if (fptr == NULL) {
5413*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
5414*7836SJohn.Forte@Sun.COM 			dlerrorack(wq, mp, DL_ATTACH_REQ, DL_BADPPA, 0);
5415*7836SJohn.Forte@Sun.COM 			return;
5416*7836SJohn.Forte@Sun.COM 		}
5417*7836SJohn.Forte@Sun.COM 	}
5418*7836SJohn.Forte@Sun.COM 
5419*7836SJohn.Forte@Sun.COM 	/*
5420*7836SJohn.Forte@Sun.COM 	 * set link to device and update our state
5421*7836SJohn.Forte@Sun.COM 	 */
5422*7836SJohn.Forte@Sun.COM 	slp->sl_fcip = fptr;
5423*7836SJohn.Forte@Sun.COM 	slp->sl_state = DL_UNBOUND;
5424*7836SJohn.Forte@Sun.COM 
5425*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
5426*7836SJohn.Forte@Sun.COM 
5427*7836SJohn.Forte@Sun.COM #ifdef DEBUG
5428*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
5429*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_flags & FCIP_LINK_DOWN) {
5430*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_WARN, "port not online yet"));
5431*7836SJohn.Forte@Sun.COM 	}
5432*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
5433*7836SJohn.Forte@Sun.COM #endif
5434*7836SJohn.Forte@Sun.COM 
5435*7836SJohn.Forte@Sun.COM 	dlokack(wq, mp, DL_ATTACH_REQ);
5436*7836SJohn.Forte@Sun.COM }
5437*7836SJohn.Forte@Sun.COM 
5438*7836SJohn.Forte@Sun.COM 
5439*7836SJohn.Forte@Sun.COM /*
5440*7836SJohn.Forte@Sun.COM  * DL_DETACH request - detaches a PPA from a stream
5441*7836SJohn.Forte@Sun.COM  */
5442*7836SJohn.Forte@Sun.COM static void
fcip_dreq(queue_t * wq,mblk_t * mp)5443*7836SJohn.Forte@Sun.COM fcip_dreq(queue_t *wq, mblk_t *mp)
5444*7836SJohn.Forte@Sun.COM {
5445*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5446*7836SJohn.Forte@Sun.COM 
5447*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5448*7836SJohn.Forte@Sun.COM 
5449*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_DETACH_REQ_SIZE) {
5450*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0);
5451*7836SJohn.Forte@Sun.COM 		return;
5452*7836SJohn.Forte@Sun.COM 	}
5453*7836SJohn.Forte@Sun.COM 
5454*7836SJohn.Forte@Sun.COM 	if (slp->sl_state != DL_UNBOUND) {
5455*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0);
5456*7836SJohn.Forte@Sun.COM 		return;
5457*7836SJohn.Forte@Sun.COM 	}
5458*7836SJohn.Forte@Sun.COM 
5459*7836SJohn.Forte@Sun.COM 	fcip_dodetach(slp);
5460*7836SJohn.Forte@Sun.COM 	dlokack(wq, mp, DL_DETACH_REQ);
5461*7836SJohn.Forte@Sun.COM }
5462*7836SJohn.Forte@Sun.COM 
5463*7836SJohn.Forte@Sun.COM /*
5464*7836SJohn.Forte@Sun.COM  * DL_BIND request: requests a DLS provider to bind a DLSAP to the stream.
5465*7836SJohn.Forte@Sun.COM  * DLS users communicate with a physical interface through DLSAPs. Multiple
5466*7836SJohn.Forte@Sun.COM  * DLSAPs can be bound to the same stream (PPA)
5467*7836SJohn.Forte@Sun.COM  */
5468*7836SJohn.Forte@Sun.COM static void
fcip_breq(queue_t * wq,mblk_t * mp)5469*7836SJohn.Forte@Sun.COM fcip_breq(queue_t *wq, mblk_t *mp)
5470*7836SJohn.Forte@Sun.COM {
5471*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5472*7836SJohn.Forte@Sun.COM 	union DL_primitives	*dlp;
5473*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5474*7836SJohn.Forte@Sun.COM 	struct fcipdladdr	fcipaddr;
5475*7836SJohn.Forte@Sun.COM 	t_uscalar_t		sap;
5476*7836SJohn.Forte@Sun.COM 	int			xidtest;
5477*7836SJohn.Forte@Sun.COM 
5478*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5479*7836SJohn.Forte@Sun.COM 
5480*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
5481*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
5482*7836SJohn.Forte@Sun.COM 		return;
5483*7836SJohn.Forte@Sun.COM 	}
5484*7836SJohn.Forte@Sun.COM 
5485*7836SJohn.Forte@Sun.COM 	if (slp->sl_state != DL_UNBOUND) {
5486*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
5487*7836SJohn.Forte@Sun.COM 		return;
5488*7836SJohn.Forte@Sun.COM 	}
5489*7836SJohn.Forte@Sun.COM 
5490*7836SJohn.Forte@Sun.COM 	dlp = (union DL_primitives *)mp->b_rptr;
5491*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
5492*7836SJohn.Forte@Sun.COM 
5493*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
5494*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
5495*7836SJohn.Forte@Sun.COM 		return;
5496*7836SJohn.Forte@Sun.COM 	}
5497*7836SJohn.Forte@Sun.COM 
5498*7836SJohn.Forte@Sun.COM 	sap = dlp->bind_req.dl_sap;
5499*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "fcip_breq - sap: %x", sap));
5500*7836SJohn.Forte@Sun.COM 	xidtest = dlp->bind_req.dl_xidtest_flg;
5501*7836SJohn.Forte@Sun.COM 
5502*7836SJohn.Forte@Sun.COM 	if (xidtest) {
5503*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0);
5504*7836SJohn.Forte@Sun.COM 		return;
5505*7836SJohn.Forte@Sun.COM 	}
5506*7836SJohn.Forte@Sun.COM 
5507*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DLPI, (CE_NOTE, "DLBIND: sap : %x", sap));
5508*7836SJohn.Forte@Sun.COM 
5509*7836SJohn.Forte@Sun.COM 	if (sap > ETHERTYPE_MAX) {
5510*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, dlp->dl_primitive, DL_BADSAP, 0);
5511*7836SJohn.Forte@Sun.COM 		return;
5512*7836SJohn.Forte@Sun.COM 	}
5513*7836SJohn.Forte@Sun.COM 	/*
5514*7836SJohn.Forte@Sun.COM 	 * save SAP for this stream and change the link state
5515*7836SJohn.Forte@Sun.COM 	 */
5516*7836SJohn.Forte@Sun.COM 	slp->sl_sap = sap;
5517*7836SJohn.Forte@Sun.COM 	slp->sl_state = DL_IDLE;
5518*7836SJohn.Forte@Sun.COM 
5519*7836SJohn.Forte@Sun.COM 	fcipaddr.dl_sap = sap;
5520*7836SJohn.Forte@Sun.COM 	ether_bcopy(&fptr->fcip_macaddr, &fcipaddr.dl_phys);
5521*7836SJohn.Forte@Sun.COM 	dlbindack(wq, mp, sap, &fcipaddr, FCIPADDRL, 0, 0);
5522*7836SJohn.Forte@Sun.COM 
5523*7836SJohn.Forte@Sun.COM 	fcip_setipq(fptr);
5524*7836SJohn.Forte@Sun.COM }
5525*7836SJohn.Forte@Sun.COM 
5526*7836SJohn.Forte@Sun.COM /*
5527*7836SJohn.Forte@Sun.COM  * DL_UNBIND request to unbind a previously bound DLSAP, from this stream
5528*7836SJohn.Forte@Sun.COM  */
5529*7836SJohn.Forte@Sun.COM static void
fcip_ubreq(queue_t * wq,mblk_t * mp)5530*7836SJohn.Forte@Sun.COM fcip_ubreq(queue_t *wq, mblk_t *mp)
5531*7836SJohn.Forte@Sun.COM {
5532*7836SJohn.Forte@Sun.COM 	struct fcipstr	*slp;
5533*7836SJohn.Forte@Sun.COM 
5534*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5535*7836SJohn.Forte@Sun.COM 
5536*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
5537*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0);
5538*7836SJohn.Forte@Sun.COM 		return;
5539*7836SJohn.Forte@Sun.COM 	}
5540*7836SJohn.Forte@Sun.COM 
5541*7836SJohn.Forte@Sun.COM 	if (slp->sl_state != DL_IDLE) {
5542*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
5543*7836SJohn.Forte@Sun.COM 		return;
5544*7836SJohn.Forte@Sun.COM 	}
5545*7836SJohn.Forte@Sun.COM 
5546*7836SJohn.Forte@Sun.COM 	slp->sl_state = DL_UNBOUND;
5547*7836SJohn.Forte@Sun.COM 	slp->sl_sap = 0;
5548*7836SJohn.Forte@Sun.COM 
5549*7836SJohn.Forte@Sun.COM 	(void) putnextctl1(RD(wq), M_FLUSH, FLUSHRW);
5550*7836SJohn.Forte@Sun.COM 	dlokack(wq, mp, DL_UNBIND_REQ);
5551*7836SJohn.Forte@Sun.COM 
5552*7836SJohn.Forte@Sun.COM 	fcip_setipq(slp->sl_fcip);
5553*7836SJohn.Forte@Sun.COM }
5554*7836SJohn.Forte@Sun.COM 
5555*7836SJohn.Forte@Sun.COM /*
5556*7836SJohn.Forte@Sun.COM  * Return our physical address
5557*7836SJohn.Forte@Sun.COM  */
5558*7836SJohn.Forte@Sun.COM static void
fcip_pareq(queue_t * wq,mblk_t * mp)5559*7836SJohn.Forte@Sun.COM fcip_pareq(queue_t *wq, mblk_t *mp)
5560*7836SJohn.Forte@Sun.COM {
5561*7836SJohn.Forte@Sun.COM 	struct fcipstr 		*slp;
5562*7836SJohn.Forte@Sun.COM 	union DL_primitives	*dlp;
5563*7836SJohn.Forte@Sun.COM 	int			type;
5564*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5565*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
5566*7836SJohn.Forte@Sun.COM 	struct ether_addr	addr;
5567*7836SJohn.Forte@Sun.COM 
5568*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5569*7836SJohn.Forte@Sun.COM 
5570*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) {
5571*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
5572*7836SJohn.Forte@Sun.COM 		return;
5573*7836SJohn.Forte@Sun.COM 	}
5574*7836SJohn.Forte@Sun.COM 
5575*7836SJohn.Forte@Sun.COM 	dlp = (union DL_primitives *)mp->b_rptr;
5576*7836SJohn.Forte@Sun.COM 	type = dlp->physaddr_req.dl_addr_type;
5577*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
5578*7836SJohn.Forte@Sun.COM 
5579*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
5580*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
5581*7836SJohn.Forte@Sun.COM 		return;
5582*7836SJohn.Forte@Sun.COM 	}
5583*7836SJohn.Forte@Sun.COM 
5584*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
5585*7836SJohn.Forte@Sun.COM 
5586*7836SJohn.Forte@Sun.COM 	switch (type) {
5587*7836SJohn.Forte@Sun.COM 	case DL_FACT_PHYS_ADDR:
5588*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5589*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "returning factory phys addr"));
5590*7836SJohn.Forte@Sun.COM 		wwn_to_ether(&fport->fcipp_pwwn, &addr);
5591*7836SJohn.Forte@Sun.COM 		break;
5592*7836SJohn.Forte@Sun.COM 
5593*7836SJohn.Forte@Sun.COM 	case DL_CURR_PHYS_ADDR:
5594*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5595*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "returning current phys addr"));
5596*7836SJohn.Forte@Sun.COM 		ether_bcopy(&fptr->fcip_macaddr, &addr);
5597*7836SJohn.Forte@Sun.COM 		break;
5598*7836SJohn.Forte@Sun.COM 
5599*7836SJohn.Forte@Sun.COM 	default:
5600*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5601*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "Not known cmd type in phys addr"));
5602*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_NOTSUPPORTED, 0);
5603*7836SJohn.Forte@Sun.COM 		return;
5604*7836SJohn.Forte@Sun.COM 	}
5605*7836SJohn.Forte@Sun.COM 	dlphysaddrack(wq, mp, &addr, ETHERADDRL);
5606*7836SJohn.Forte@Sun.COM }
5607*7836SJohn.Forte@Sun.COM 
5608*7836SJohn.Forte@Sun.COM /*
5609*7836SJohn.Forte@Sun.COM  * Set physical address DLPI request
5610*7836SJohn.Forte@Sun.COM  */
5611*7836SJohn.Forte@Sun.COM static void
fcip_spareq(queue_t * wq,mblk_t * mp)5612*7836SJohn.Forte@Sun.COM fcip_spareq(queue_t *wq, mblk_t *mp)
5613*7836SJohn.Forte@Sun.COM {
5614*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5615*7836SJohn.Forte@Sun.COM 	union DL_primitives	*dlp;
5616*7836SJohn.Forte@Sun.COM 	t_uscalar_t		off, len;
5617*7836SJohn.Forte@Sun.COM 	struct ether_addr	*addrp;
5618*7836SJohn.Forte@Sun.COM 	la_wwn_t		wwn;
5619*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5620*7836SJohn.Forte@Sun.COM 	fc_ns_cmd_t		fcip_ns_cmd;
5621*7836SJohn.Forte@Sun.COM 
5622*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5623*7836SJohn.Forte@Sun.COM 
5624*7836SJohn.Forte@Sun.COM 	if (MBLKL(mp) < DL_SET_PHYS_ADDR_REQ_SIZE) {
5625*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0);
5626*7836SJohn.Forte@Sun.COM 		return;
5627*7836SJohn.Forte@Sun.COM 	}
5628*7836SJohn.Forte@Sun.COM 
5629*7836SJohn.Forte@Sun.COM 	dlp = (union DL_primitives *)mp->b_rptr;
5630*7836SJohn.Forte@Sun.COM 	len = dlp->set_physaddr_req.dl_addr_length;
5631*7836SJohn.Forte@Sun.COM 	off = dlp->set_physaddr_req.dl_addr_offset;
5632*7836SJohn.Forte@Sun.COM 
5633*7836SJohn.Forte@Sun.COM 	if (!MBLKIN(mp, off, len)) {
5634*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0);
5635*7836SJohn.Forte@Sun.COM 		return;
5636*7836SJohn.Forte@Sun.COM 	}
5637*7836SJohn.Forte@Sun.COM 
5638*7836SJohn.Forte@Sun.COM 	addrp = (struct ether_addr *)(mp->b_rptr + off);
5639*7836SJohn.Forte@Sun.COM 
5640*7836SJohn.Forte@Sun.COM 	/*
5641*7836SJohn.Forte@Sun.COM 	 * If the length of physical address is not correct or address
5642*7836SJohn.Forte@Sun.COM 	 * specified is a broadcast address or multicast addr -
5643*7836SJohn.Forte@Sun.COM 	 * return an error.
5644*7836SJohn.Forte@Sun.COM 	 */
5645*7836SJohn.Forte@Sun.COM 	if ((len != ETHERADDRL) ||
5646*7836SJohn.Forte@Sun.COM 	    ((addrp->ether_addr_octet[0] & 01) == 1) ||
5647*7836SJohn.Forte@Sun.COM 	    (ether_cmp(addrp, &fcip_arpbroadcast_addr) == 0)) {
5648*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0);
5649*7836SJohn.Forte@Sun.COM 		return;
5650*7836SJohn.Forte@Sun.COM 	}
5651*7836SJohn.Forte@Sun.COM 
5652*7836SJohn.Forte@Sun.COM 	/*
5653*7836SJohn.Forte@Sun.COM 	 * check if a stream is attached to this device. Else return an error
5654*7836SJohn.Forte@Sun.COM 	 */
5655*7836SJohn.Forte@Sun.COM 	if ((fptr = slp->sl_fcip) == NULL) {
5656*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
5657*7836SJohn.Forte@Sun.COM 		return;
5658*7836SJohn.Forte@Sun.COM 	}
5659*7836SJohn.Forte@Sun.COM 
5660*7836SJohn.Forte@Sun.COM 	/*
5661*7836SJohn.Forte@Sun.COM 	 * set the new interface local address. We request the transport
5662*7836SJohn.Forte@Sun.COM 	 * layer to change the Port WWN for this device - return an error
5663*7836SJohn.Forte@Sun.COM 	 * if we don't succeed.
5664*7836SJohn.Forte@Sun.COM 	 */
5665*7836SJohn.Forte@Sun.COM 
5666*7836SJohn.Forte@Sun.COM 	ether_to_wwn(addrp, &wwn);
5667*7836SJohn.Forte@Sun.COM 	if (fcip_set_wwn(&wwn) == FC_SUCCESS) {
5668*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5669*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "WWN changed in spareq"));
5670*7836SJohn.Forte@Sun.COM 	} else {
5671*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0);
5672*7836SJohn.Forte@Sun.COM 	}
5673*7836SJohn.Forte@Sun.COM 
5674*7836SJohn.Forte@Sun.COM 	/*
5675*7836SJohn.Forte@Sun.COM 	 * register The new Port WWN and Node WWN with the transport
5676*7836SJohn.Forte@Sun.COM 	 * and Nameserver. Hope the transport ensures all current I/O
5677*7836SJohn.Forte@Sun.COM 	 * has stopped before actually attempting to register a new
5678*7836SJohn.Forte@Sun.COM 	 * port and Node WWN else we are hosed. Maybe a Link reset
5679*7836SJohn.Forte@Sun.COM 	 * will get everyone's attention.
5680*7836SJohn.Forte@Sun.COM 	 */
5681*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_flags = 0;
5682*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_cmd = NS_RPN_ID;
5683*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_req_len = sizeof (la_wwn_t);
5684*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_req_payload = (caddr_t)&wwn.raw_wwn[0];
5685*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_resp_len = 0;
5686*7836SJohn.Forte@Sun.COM 	fcip_ns_cmd.ns_resp_payload = (caddr_t)0;
5687*7836SJohn.Forte@Sun.COM 	if (fc_ulp_port_ns(fptr->fcip_port_info->fcipp_handle,
5688*7836SJohn.Forte@Sun.COM 	    (opaque_t)0, &fcip_ns_cmd) != FC_SUCCESS) {
5689*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DLPI,
5690*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "setting Port WWN failed"));
5691*7836SJohn.Forte@Sun.COM 		dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0);
5692*7836SJohn.Forte@Sun.COM 		return;
5693*7836SJohn.Forte@Sun.COM 	}
5694*7836SJohn.Forte@Sun.COM 
5695*7836SJohn.Forte@Sun.COM 	dlokack(wq, mp, DL_SET_PHYS_ADDR_REQ);
5696*7836SJohn.Forte@Sun.COM }
5697*7836SJohn.Forte@Sun.COM 
5698*7836SJohn.Forte@Sun.COM /*
5699*7836SJohn.Forte@Sun.COM  * change our port's WWN if permitted by hardware
5700*7836SJohn.Forte@Sun.COM  */
5701*7836SJohn.Forte@Sun.COM /* ARGSUSED */
5702*7836SJohn.Forte@Sun.COM static int
fcip_set_wwn(la_wwn_t * pwwn)5703*7836SJohn.Forte@Sun.COM fcip_set_wwn(la_wwn_t *pwwn)
5704*7836SJohn.Forte@Sun.COM {
5705*7836SJohn.Forte@Sun.COM 	/*
5706*7836SJohn.Forte@Sun.COM 	 * We're usually not allowed to change the WWN of adapters
5707*7836SJohn.Forte@Sun.COM 	 * but some adapters do permit us to change the WWN - don't
5708*7836SJohn.Forte@Sun.COM 	 * permit setting of WWNs (yet?) - This behavior could be
5709*7836SJohn.Forte@Sun.COM 	 * modified if needed
5710*7836SJohn.Forte@Sun.COM 	 */
5711*7836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
5712*7836SJohn.Forte@Sun.COM }
5713*7836SJohn.Forte@Sun.COM 
5714*7836SJohn.Forte@Sun.COM 
5715*7836SJohn.Forte@Sun.COM /*
5716*7836SJohn.Forte@Sun.COM  * This routine fills in the header for fastpath data requests. What this
5717*7836SJohn.Forte@Sun.COM  * does in simple terms is, instead of sending all data through the Unitdata
5718*7836SJohn.Forte@Sun.COM  * request dlpi code paths (which will then append the protocol specific
5719*7836SJohn.Forte@Sun.COM  * header - network and snap headers in our case), the upper layers issue
5720*7836SJohn.Forte@Sun.COM  * a M_IOCTL with a DL_IOC_HDR_INFO request and ask the streams endpoint
5721*7836SJohn.Forte@Sun.COM  * driver to give the header it needs appended and the upper layer
5722*7836SJohn.Forte@Sun.COM  * allocates and fills in the header and calls our put routine
5723*7836SJohn.Forte@Sun.COM  */
5724*7836SJohn.Forte@Sun.COM static void
fcip_dl_ioc_hdr_info(queue_t * wq,mblk_t * mp)5725*7836SJohn.Forte@Sun.COM fcip_dl_ioc_hdr_info(queue_t *wq, mblk_t *mp)
5726*7836SJohn.Forte@Sun.COM {
5727*7836SJohn.Forte@Sun.COM 	mblk_t			*nmp;
5728*7836SJohn.Forte@Sun.COM 	struct fcipstr		*slp;
5729*7836SJohn.Forte@Sun.COM 	struct fcipdladdr	*dlap;
5730*7836SJohn.Forte@Sun.COM 	dl_unitdata_req_t	*dlup;
5731*7836SJohn.Forte@Sun.COM 	fcph_network_hdr_t	*headerp;
5732*7836SJohn.Forte@Sun.COM 	la_wwn_t		wwn;
5733*7836SJohn.Forte@Sun.COM 	llc_snap_hdr_t		*lsnap;
5734*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5735*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
5736*7836SJohn.Forte@Sun.COM 	t_uscalar_t		off, len;
5737*7836SJohn.Forte@Sun.COM 	size_t			hdrlen;
5738*7836SJohn.Forte@Sun.COM 	int 			error;
5739*7836SJohn.Forte@Sun.COM 
5740*7836SJohn.Forte@Sun.COM 	slp = (struct fcipstr *)wq->q_ptr;
5741*7836SJohn.Forte@Sun.COM 	fptr = slp->sl_fcip;
5742*7836SJohn.Forte@Sun.COM 	if (fptr == NULL) {
5743*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5744*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "dliochdr : returns EINVAL1"));
5745*7836SJohn.Forte@Sun.COM 		miocnak(wq, mp, 0, EINVAL);
5746*7836SJohn.Forte@Sun.COM 		return;
5747*7836SJohn.Forte@Sun.COM 	}
5748*7836SJohn.Forte@Sun.COM 
5749*7836SJohn.Forte@Sun.COM 	error = miocpullup(mp, sizeof (dl_unitdata_req_t) + FCIPADDRL);
5750*7836SJohn.Forte@Sun.COM 	if (error != 0) {
5751*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5752*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "dliochdr : returns %d", error));
5753*7836SJohn.Forte@Sun.COM 		miocnak(wq, mp, 0, error);
5754*7836SJohn.Forte@Sun.COM 		return;
5755*7836SJohn.Forte@Sun.COM 	}
5756*7836SJohn.Forte@Sun.COM 
5757*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
5758*7836SJohn.Forte@Sun.COM 
5759*7836SJohn.Forte@Sun.COM 	/*
5760*7836SJohn.Forte@Sun.COM 	 * check if the DL_UNITDATA_REQ destination addr has valid offset
5761*7836SJohn.Forte@Sun.COM 	 * and length values
5762*7836SJohn.Forte@Sun.COM 	 */
5763*7836SJohn.Forte@Sun.COM 	dlup = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
5764*7836SJohn.Forte@Sun.COM 	off = dlup->dl_dest_addr_offset;
5765*7836SJohn.Forte@Sun.COM 	len = dlup->dl_dest_addr_length;
5766*7836SJohn.Forte@Sun.COM 	if (dlup->dl_primitive != DL_UNITDATA_REQ ||
5767*7836SJohn.Forte@Sun.COM 	    !MBLKIN(mp->b_cont, off, len) || (len != FCIPADDRL)) {
5768*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5769*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "dliochdr : returns EINVAL2"));
5770*7836SJohn.Forte@Sun.COM 		miocnak(wq, mp, 0, EINVAL);
5771*7836SJohn.Forte@Sun.COM 		return;
5772*7836SJohn.Forte@Sun.COM 	}
5773*7836SJohn.Forte@Sun.COM 
5774*7836SJohn.Forte@Sun.COM 	dlap = (struct fcipdladdr *)(mp->b_cont->b_rptr + off);
5775*7836SJohn.Forte@Sun.COM 
5776*7836SJohn.Forte@Sun.COM 	/*
5777*7836SJohn.Forte@Sun.COM 	 * Allocate a new mblk to hold the ether header
5778*7836SJohn.Forte@Sun.COM 	 */
5779*7836SJohn.Forte@Sun.COM 
5780*7836SJohn.Forte@Sun.COM 	/*
5781*7836SJohn.Forte@Sun.COM 	 * setup space for network header
5782*7836SJohn.Forte@Sun.COM 	 */
5783*7836SJohn.Forte@Sun.COM 	hdrlen = (sizeof (llc_snap_hdr_t) + sizeof (fcph_network_hdr_t));
5784*7836SJohn.Forte@Sun.COM 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL) {
5785*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5786*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "dliochdr : returns ENOMEM"));
5787*7836SJohn.Forte@Sun.COM 		miocnak(wq, mp, 0, ENOMEM);
5788*7836SJohn.Forte@Sun.COM 		return;
5789*7836SJohn.Forte@Sun.COM 	}
5790*7836SJohn.Forte@Sun.COM 	nmp->b_wptr += hdrlen;
5791*7836SJohn.Forte@Sun.COM 
5792*7836SJohn.Forte@Sun.COM 	/*
5793*7836SJohn.Forte@Sun.COM 	 * Fill in the Network Hdr and LLC SNAP header;
5794*7836SJohn.Forte@Sun.COM 	 */
5795*7836SJohn.Forte@Sun.COM 	headerp = (fcph_network_hdr_t *)nmp->b_rptr;
5796*7836SJohn.Forte@Sun.COM 	/*
5797*7836SJohn.Forte@Sun.COM 	 * just fill in the Node WWN here - we can fill in the NAA_ID when
5798*7836SJohn.Forte@Sun.COM 	 * we search the routing table
5799*7836SJohn.Forte@Sun.COM 	 */
5800*7836SJohn.Forte@Sun.COM 	if (ether_cmp(&dlap->dl_phys, &fcip_arpbroadcast_addr) == 0) {
5801*7836SJohn.Forte@Sun.COM 		ether_to_wwn(&fcipnhbroadcastaddr, &wwn);
5802*7836SJohn.Forte@Sun.COM 	} else {
5803*7836SJohn.Forte@Sun.COM 		ether_to_wwn(&dlap->dl_phys, &wwn);
5804*7836SJohn.Forte@Sun.COM 	}
5805*7836SJohn.Forte@Sun.COM 	bcopy(&wwn, &headerp->net_dest_addr, sizeof (la_wwn_t));
5806*7836SJohn.Forte@Sun.COM 	bcopy(&fport->fcipp_pwwn, &headerp->net_src_addr, sizeof (la_wwn_t));
5807*7836SJohn.Forte@Sun.COM 	lsnap = (llc_snap_hdr_t *)(nmp->b_rptr + sizeof (fcph_network_hdr_t));
5808*7836SJohn.Forte@Sun.COM 	lsnap->dsap = 0xAA;
5809*7836SJohn.Forte@Sun.COM 	lsnap->ssap = 0xAA;
5810*7836SJohn.Forte@Sun.COM 	lsnap->ctrl = 0x03;
5811*7836SJohn.Forte@Sun.COM 	lsnap->oui[0] = 0x00;
5812*7836SJohn.Forte@Sun.COM 	lsnap->oui[1] = 0x00;
5813*7836SJohn.Forte@Sun.COM 	lsnap->oui[2] = 0x00;
5814*7836SJohn.Forte@Sun.COM 	lsnap->pid = BE_16(dlap->dl_sap);
5815*7836SJohn.Forte@Sun.COM 
5816*7836SJohn.Forte@Sun.COM 	/*
5817*7836SJohn.Forte@Sun.COM 	 * Link new mblk in after the "request" mblks.
5818*7836SJohn.Forte@Sun.COM 	 */
5819*7836SJohn.Forte@Sun.COM 	linkb(mp, nmp);
5820*7836SJohn.Forte@Sun.COM 
5821*7836SJohn.Forte@Sun.COM 	slp->sl_flags |= FCIP_SLFAST;
5822*7836SJohn.Forte@Sun.COM 
5823*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5824*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "dliochdr : returns success "));
5825*7836SJohn.Forte@Sun.COM 	miocack(wq, mp, msgsize(mp->b_cont), 0);
5826*7836SJohn.Forte@Sun.COM }
5827*7836SJohn.Forte@Sun.COM 
5828*7836SJohn.Forte@Sun.COM 
5829*7836SJohn.Forte@Sun.COM /*
5830*7836SJohn.Forte@Sun.COM  * Establish a kmem cache for fcip packets
5831*7836SJohn.Forte@Sun.COM  */
5832*7836SJohn.Forte@Sun.COM static int
fcip_cache_constructor(void * buf,void * arg,int flags)5833*7836SJohn.Forte@Sun.COM fcip_cache_constructor(void *buf, void *arg, int flags)
5834*7836SJohn.Forte@Sun.COM {
5835*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt = buf;
5836*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
5837*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = (fcip_port_info_t *)arg;
5838*7836SJohn.Forte@Sun.COM 	int			(*cb) (caddr_t);
5839*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5840*7836SJohn.Forte@Sun.COM 
5841*7836SJohn.Forte@Sun.COM 	cb = (flags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
5842*7836SJohn.Forte@Sun.COM 
5843*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
5844*7836SJohn.Forte@Sun.COM 
5845*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
5846*7836SJohn.Forte@Sun.COM 
5847*7836SJohn.Forte@Sun.COM 	/*
5848*7836SJohn.Forte@Sun.COM 	 * we allocated space for our private area at the end of the
5849*7836SJohn.Forte@Sun.COM 	 * fc packet. Make sure we point to it correctly. Ideally we
5850*7836SJohn.Forte@Sun.COM 	 * should just push fc_packet_private to the beginning or end
5851*7836SJohn.Forte@Sun.COM 	 * of the fc_packet structure
5852*7836SJohn.Forte@Sun.COM 	 */
5853*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_next = NULL;
5854*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_prev = NULL;
5855*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dest = NULL;
5856*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_state = 0;
5857*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_reason = 0;
5858*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags = 0;
5859*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_fptr = fptr;
5860*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dma_flags = 0;
5861*7836SJohn.Forte@Sun.COM 
5862*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
5863*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_rscn_infop = NULL;
5864*7836SJohn.Forte@Sun.COM 
5865*7836SJohn.Forte@Sun.COM 	/*
5866*7836SJohn.Forte@Sun.COM 	 * We use pkt_cmd_dma for OUTBOUND requests. We don't expect
5867*7836SJohn.Forte@Sun.COM 	 * any responses for outbound IP data so no need to setup
5868*7836SJohn.Forte@Sun.COM 	 * response or data dma handles.
5869*7836SJohn.Forte@Sun.COM 	 */
5870*7836SJohn.Forte@Sun.COM 	if (ddi_dma_alloc_handle(fport->fcipp_dip,
5871*7836SJohn.Forte@Sun.COM 	    &fport->fcipp_cmd_dma_attr, cb, NULL,
5872*7836SJohn.Forte@Sun.COM 	    &fc_pkt->pkt_cmd_dma) != DDI_SUCCESS) {
5873*7836SJohn.Forte@Sun.COM 		return (FCIP_FAILURE);
5874*7836SJohn.Forte@Sun.COM 	}
5875*7836SJohn.Forte@Sun.COM 
5876*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmd_acc = fc_pkt->pkt_resp_acc = NULL;
5877*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_fca_private = (opaque_t)((caddr_t)buf +
5878*7836SJohn.Forte@Sun.COM 	    sizeof (fcip_pkt_t));
5879*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_private = (opaque_t)fcip_pkt;
5880*7836SJohn.Forte@Sun.COM 
5881*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmd_cookie_cnt = fc_pkt->pkt_resp_cookie_cnt =
5882*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_data_cookie_cnt = 0;
5883*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmd_cookie = fc_pkt->pkt_resp_cookie =
5884*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_data_cookie = NULL;
5885*7836SJohn.Forte@Sun.COM 
5886*7836SJohn.Forte@Sun.COM 	return (FCIP_SUCCESS);
5887*7836SJohn.Forte@Sun.COM }
5888*7836SJohn.Forte@Sun.COM 
5889*7836SJohn.Forte@Sun.COM /*
5890*7836SJohn.Forte@Sun.COM  * destroy the fcip kmem cache
5891*7836SJohn.Forte@Sun.COM  */
5892*7836SJohn.Forte@Sun.COM static void
fcip_cache_destructor(void * buf,void * arg)5893*7836SJohn.Forte@Sun.COM fcip_cache_destructor(void *buf, void *arg)
5894*7836SJohn.Forte@Sun.COM {
5895*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt = (fcip_pkt_t *)buf;
5896*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
5897*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = (fcip_port_info_t *)arg;
5898*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
5899*7836SJohn.Forte@Sun.COM 
5900*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
5901*7836SJohn.Forte@Sun.COM 
5902*7836SJohn.Forte@Sun.COM 	fptr = fport->fcipp_fcip;
5903*7836SJohn.Forte@Sun.COM 
5904*7836SJohn.Forte@Sun.COM 	ASSERT(fptr == fcip_pkt->fcip_pkt_fptr);
5905*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
5906*7836SJohn.Forte@Sun.COM 
5907*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_cmd_dma) {
5908*7836SJohn.Forte@Sun.COM 		ddi_dma_free_handle(&fc_pkt->pkt_cmd_dma);
5909*7836SJohn.Forte@Sun.COM 	}
5910*7836SJohn.Forte@Sun.COM }
5911*7836SJohn.Forte@Sun.COM 
5912*7836SJohn.Forte@Sun.COM /*
5913*7836SJohn.Forte@Sun.COM  * the fcip destination structure is hashed on Node WWN assuming
5914*7836SJohn.Forte@Sun.COM  * a  NAA_ID of 0x1 (IEEE)
5915*7836SJohn.Forte@Sun.COM  */
5916*7836SJohn.Forte@Sun.COM static struct fcip_dest *
fcip_get_dest(struct fcip * fptr,la_wwn_t * pwwn)5917*7836SJohn.Forte@Sun.COM fcip_get_dest(struct fcip *fptr, la_wwn_t *pwwn)
5918*7836SJohn.Forte@Sun.COM {
5919*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp = NULL;
5920*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
5921*7836SJohn.Forte@Sun.COM 	int			hash_bucket;
5922*7836SJohn.Forte@Sun.COM 	opaque_t		pd;
5923*7836SJohn.Forte@Sun.COM 	int			rval;
5924*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table *frp;
5925*7836SJohn.Forte@Sun.COM 	la_wwn_t		twwn;
5926*7836SJohn.Forte@Sun.COM 	uint32_t		*twwnp = (uint32_t *)&twwn;
5927*7836SJohn.Forte@Sun.COM 
5928*7836SJohn.Forte@Sun.COM 	hash_bucket = FCIP_DEST_HASH(pwwn->raw_wwn);
5929*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5930*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "get dest hashbucket : 0x%x", hash_bucket));
5931*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5932*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
5933*7836SJohn.Forte@Sun.COM 	    pwwn->raw_wwn[2], pwwn->raw_wwn[3], pwwn->raw_wwn[4],
5934*7836SJohn.Forte@Sun.COM 	    pwwn->raw_wwn[5], pwwn->raw_wwn[6], pwwn->raw_wwn[7]));
5935*7836SJohn.Forte@Sun.COM 
5936*7836SJohn.Forte@Sun.COM 	ASSERT(hash_bucket < FCIP_DEST_HASH_ELEMS);
5937*7836SJohn.Forte@Sun.COM 
5938*7836SJohn.Forte@Sun.COM 	if (fcip_check_port_exists(fptr)) {
5939*7836SJohn.Forte@Sun.COM 		/* fptr is stale, return fdestp */
5940*7836SJohn.Forte@Sun.COM 		return (fdestp);
5941*7836SJohn.Forte@Sun.COM 	}
5942*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
5943*7836SJohn.Forte@Sun.COM 
5944*7836SJohn.Forte@Sun.COM 	/*
5945*7836SJohn.Forte@Sun.COM 	 * First check if we have active I/Os going on with the
5946*7836SJohn.Forte@Sun.COM 	 * destination port (an entry would exist in fcip_dest hash table)
5947*7836SJohn.Forte@Sun.COM 	 */
5948*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_dest_mutex);
5949*7836SJohn.Forte@Sun.COM 	fdestp = fptr->fcip_dest[hash_bucket];
5950*7836SJohn.Forte@Sun.COM 	while (fdestp != NULL) {
5951*7836SJohn.Forte@Sun.COM 		mutex_enter(&fdestp->fcipd_mutex);
5952*7836SJohn.Forte@Sun.COM 		if (fdestp->fcipd_rtable) {
5953*7836SJohn.Forte@Sun.COM 			if (fcip_wwn_compare(pwwn, &fdestp->fcipd_pwwn,
5954*7836SJohn.Forte@Sun.COM 			    FCIP_COMPARE_NWWN) == 0) {
5955*7836SJohn.Forte@Sun.COM 				FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
5956*7836SJohn.Forte@Sun.COM 				    (CE_NOTE, "found fdestp"));
5957*7836SJohn.Forte@Sun.COM 				mutex_exit(&fdestp->fcipd_mutex);
5958*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_dest_mutex);
5959*7836SJohn.Forte@Sun.COM 				return (fdestp);
5960*7836SJohn.Forte@Sun.COM 			}
5961*7836SJohn.Forte@Sun.COM 		}
5962*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
5963*7836SJohn.Forte@Sun.COM 		fdestp = fdestp->fcipd_next;
5964*7836SJohn.Forte@Sun.COM 	}
5965*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_dest_mutex);
5966*7836SJohn.Forte@Sun.COM 
5967*7836SJohn.Forte@Sun.COM 	/*
5968*7836SJohn.Forte@Sun.COM 	 * We did not find the destination port information in our
5969*7836SJohn.Forte@Sun.COM 	 * active port list so search for an entry in our routing
5970*7836SJohn.Forte@Sun.COM 	 * table.
5971*7836SJohn.Forte@Sun.COM 	 */
5972*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
5973*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, pwwn, FCIP_COMPARE_NWWN);
5974*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
5975*7836SJohn.Forte@Sun.COM 
5976*7836SJohn.Forte@Sun.COM 	if (frp == NULL || (frp && (!FCIP_RTE_UNAVAIL(frp->fcipr_state)) &&
5977*7836SJohn.Forte@Sun.COM 	    frp->fcipr_state != PORT_DEVICE_LOGGED_IN) ||
5978*7836SJohn.Forte@Sun.COM 	    (frp && frp->fcipr_pd == NULL)) {
5979*7836SJohn.Forte@Sun.COM 		/*
5980*7836SJohn.Forte@Sun.COM 		 * No entry for the destination port in our routing
5981*7836SJohn.Forte@Sun.COM 		 * table too. First query the transport to see if it
5982*7836SJohn.Forte@Sun.COM 		 * already has structures for the destination port in
5983*7836SJohn.Forte@Sun.COM 		 * its hash tables. This must be done for all topologies
5984*7836SJohn.Forte@Sun.COM 		 * since we could have retired entries in the hash tables
5985*7836SJohn.Forte@Sun.COM 		 * which may have to be re-added without a statechange
5986*7836SJohn.Forte@Sun.COM 		 * callback happening. Its better to try and get an entry
5987*7836SJohn.Forte@Sun.COM 		 * for the destination port rather than simply failing a
5988*7836SJohn.Forte@Sun.COM 		 * request though it may be an overkill in private loop
5989*7836SJohn.Forte@Sun.COM 		 * topologies.
5990*7836SJohn.Forte@Sun.COM 		 * If a entry for the remote port exists in the transport's
5991*7836SJohn.Forte@Sun.COM 		 * hash tables, we are fine and can add the entry to our
5992*7836SJohn.Forte@Sun.COM 		 * routing and dest hash lists, Else for fabric configs we
5993*7836SJohn.Forte@Sun.COM 		 * query the nameserver if one exists or issue FARP ELS.
5994*7836SJohn.Forte@Sun.COM 		 */
5995*7836SJohn.Forte@Sun.COM 
5996*7836SJohn.Forte@Sun.COM 		/*
5997*7836SJohn.Forte@Sun.COM 		 * We need to do a PortName based Nameserver
5998*7836SJohn.Forte@Sun.COM 		 * query operation. So get the right PortWWN
5999*7836SJohn.Forte@Sun.COM 		 * for the adapter.
6000*7836SJohn.Forte@Sun.COM 		 */
6001*7836SJohn.Forte@Sun.COM 		bcopy(pwwn, &twwn, sizeof (la_wwn_t));
6002*7836SJohn.Forte@Sun.COM 
6003*7836SJohn.Forte@Sun.COM 		/*
6004*7836SJohn.Forte@Sun.COM 		 * Try IEEE Name (Format 1) first, this is the default and
6005*7836SJohn.Forte@Sun.COM 		 * Emulex uses this format.
6006*7836SJohn.Forte@Sun.COM 		 */
6007*7836SJohn.Forte@Sun.COM 		pd = fc_ulp_get_remote_port(fport->fcipp_handle,
6008*7836SJohn.Forte@Sun.COM 					    &twwn, &rval, 1);
6009*7836SJohn.Forte@Sun.COM 
6010*7836SJohn.Forte@Sun.COM 		if (rval != FC_SUCCESS) {
6011*7836SJohn.Forte@Sun.COM 			/*
6012*7836SJohn.Forte@Sun.COM 			 * If IEEE Name (Format 1) query failed, try IEEE
6013*7836SJohn.Forte@Sun.COM 			 * Extended Name (Format 2) which Qlogic uses.
6014*7836SJohn.Forte@Sun.COM 			 * And try port 1 on Qlogic FC-HBA first.
6015*7836SJohn.Forte@Sun.COM 			 * Note: On x86, we need to byte swap the 32-bit
6016*7836SJohn.Forte@Sun.COM 			 * word first, after the modification, swap it back.
6017*7836SJohn.Forte@Sun.COM 			 */
6018*7836SJohn.Forte@Sun.COM 			*twwnp = BE_32(*twwnp);
6019*7836SJohn.Forte@Sun.COM 			twwn.w.nport_id = QLC_PORT_1_ID_BITS;
6020*7836SJohn.Forte@Sun.COM 			twwn.w.naa_id = QLC_PORT_NAA;
6021*7836SJohn.Forte@Sun.COM 			*twwnp = BE_32(*twwnp);
6022*7836SJohn.Forte@Sun.COM 			pd = fc_ulp_get_remote_port(fport->fcipp_handle,
6023*7836SJohn.Forte@Sun.COM 						    &twwn, &rval, 1);
6024*7836SJohn.Forte@Sun.COM 		}
6025*7836SJohn.Forte@Sun.COM 
6026*7836SJohn.Forte@Sun.COM 		if (rval != FC_SUCCESS) {
6027*7836SJohn.Forte@Sun.COM 			/* If still failed, try port 2 on Qlogic FC-HBA. */
6028*7836SJohn.Forte@Sun.COM 			*twwnp = BE_32(*twwnp);
6029*7836SJohn.Forte@Sun.COM 			twwn.w.nport_id = QLC_PORT_2_ID_BITS;
6030*7836SJohn.Forte@Sun.COM 			*twwnp = BE_32(*twwnp);
6031*7836SJohn.Forte@Sun.COM 			pd = fc_ulp_get_remote_port(fport->fcipp_handle,
6032*7836SJohn.Forte@Sun.COM 						    &twwn, &rval, 1);
6033*7836SJohn.Forte@Sun.COM 		}
6034*7836SJohn.Forte@Sun.COM 
6035*7836SJohn.Forte@Sun.COM 		if (rval == FC_SUCCESS) {
6036*7836SJohn.Forte@Sun.COM 			fc_portmap_t	map;
6037*7836SJohn.Forte@Sun.COM 			/*
6038*7836SJohn.Forte@Sun.COM 			 * Add the newly found destination structure
6039*7836SJohn.Forte@Sun.COM 			 * to our routing table. Create a map with
6040*7836SJohn.Forte@Sun.COM 			 * the device we found. We could ask the
6041*7836SJohn.Forte@Sun.COM 			 * transport to give us the list of all
6042*7836SJohn.Forte@Sun.COM 			 * devices connected to our port but we
6043*7836SJohn.Forte@Sun.COM 			 * probably don't need to know all the devices
6044*7836SJohn.Forte@Sun.COM 			 * so let us just constuct a list with only
6045*7836SJohn.Forte@Sun.COM 			 * one device instead.
6046*7836SJohn.Forte@Sun.COM 			 */
6047*7836SJohn.Forte@Sun.COM 
6048*7836SJohn.Forte@Sun.COM 			fc_ulp_copy_portmap(&map, pd);
6049*7836SJohn.Forte@Sun.COM 			fcip_rt_update(fptr, &map, 1);
6050*7836SJohn.Forte@Sun.COM 
6051*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_rt_mutex);
6052*7836SJohn.Forte@Sun.COM 			frp = fcip_lookup_rtable(fptr, pwwn,
6053*7836SJohn.Forte@Sun.COM 			    FCIP_COMPARE_NWWN);
6054*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_rt_mutex);
6055*7836SJohn.Forte@Sun.COM 
6056*7836SJohn.Forte@Sun.COM 			fdestp = fcip_add_dest(fptr, frp);
6057*7836SJohn.Forte@Sun.COM 		} else if (fcip_farp_supported &&
6058*7836SJohn.Forte@Sun.COM 			(FC_TOP_EXTERNAL(fport->fcipp_topology) ||
6059*7836SJohn.Forte@Sun.COM 			(fport->fcipp_topology == FC_TOP_PT_PT))) {
6060*7836SJohn.Forte@Sun.COM 			/*
6061*7836SJohn.Forte@Sun.COM 			 * The Name server request failed so
6062*7836SJohn.Forte@Sun.COM 			 * issue an FARP
6063*7836SJohn.Forte@Sun.COM 			 */
6064*7836SJohn.Forte@Sun.COM 			fdestp = fcip_do_farp(fptr, pwwn, NULL,
6065*7836SJohn.Forte@Sun.COM 				0, 0);
6066*7836SJohn.Forte@Sun.COM 		} else {
6067*7836SJohn.Forte@Sun.COM 		    fdestp = NULL;
6068*7836SJohn.Forte@Sun.COM 		}
6069*7836SJohn.Forte@Sun.COM 	} else if (frp && frp->fcipr_state == PORT_DEVICE_LOGGED_IN) {
6070*7836SJohn.Forte@Sun.COM 		/*
6071*7836SJohn.Forte@Sun.COM 		 * Prepare a dest structure to return to caller
6072*7836SJohn.Forte@Sun.COM 		 */
6073*7836SJohn.Forte@Sun.COM 		fdestp = fcip_add_dest(fptr, frp);
6074*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
6075*7836SJohn.Forte@Sun.COM 		    (CE_NOTE, "in fcip get dest non fabric"));
6076*7836SJohn.Forte@Sun.COM 	}
6077*7836SJohn.Forte@Sun.COM 	return (fdestp);
6078*7836SJohn.Forte@Sun.COM }
6079*7836SJohn.Forte@Sun.COM 
6080*7836SJohn.Forte@Sun.COM 
6081*7836SJohn.Forte@Sun.COM /*
6082*7836SJohn.Forte@Sun.COM  * Endian clean WWN compare.
6083*7836SJohn.Forte@Sun.COM  * Returns 0 if they compare OK, else return non zero value.
6084*7836SJohn.Forte@Sun.COM  * flag can be bitwise OR of FCIP_COMPARE_NWWN, FCIP_COMPARE_PWWN,
6085*7836SJohn.Forte@Sun.COM  * FCIP_COMPARE_BROADCAST.
6086*7836SJohn.Forte@Sun.COM  */
6087*7836SJohn.Forte@Sun.COM static int
fcip_wwn_compare(la_wwn_t * wwn1,la_wwn_t * wwn2,int flag)6088*7836SJohn.Forte@Sun.COM fcip_wwn_compare(la_wwn_t *wwn1, la_wwn_t *wwn2, int flag)
6089*7836SJohn.Forte@Sun.COM {
6090*7836SJohn.Forte@Sun.COM 	int rval = 0;
6091*7836SJohn.Forte@Sun.COM 	if ((wwn1->raw_wwn[2] != wwn2->raw_wwn[2]) ||
6092*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[3] != wwn2->raw_wwn[3]) ||
6093*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[4] != wwn2->raw_wwn[4]) ||
6094*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[5] != wwn2->raw_wwn[5]) ||
6095*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[6] != wwn2->raw_wwn[6]) ||
6096*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[7] != wwn2->raw_wwn[7])) {
6097*7836SJohn.Forte@Sun.COM 		rval = 1;
6098*7836SJohn.Forte@Sun.COM 	} else if ((flag == FCIP_COMPARE_PWWN) &&
6099*7836SJohn.Forte@Sun.COM 	    (((wwn1->raw_wwn[0] & 0xf0) != (wwn2->raw_wwn[0] & 0xf0)) ||
6100*7836SJohn.Forte@Sun.COM 	    (wwn1->raw_wwn[1] != wwn2->raw_wwn[1]))) {
6101*7836SJohn.Forte@Sun.COM 		rval = 1;
6102*7836SJohn.Forte@Sun.COM 	}
6103*7836SJohn.Forte@Sun.COM 	return (rval);
6104*7836SJohn.Forte@Sun.COM }
6105*7836SJohn.Forte@Sun.COM 
6106*7836SJohn.Forte@Sun.COM 
6107*7836SJohn.Forte@Sun.COM /*
6108*7836SJohn.Forte@Sun.COM  * Add an entry for a remote port in the dest hash table. Dest hash table
6109*7836SJohn.Forte@Sun.COM  * has entries for ports in the routing hash table with which we decide
6110*7836SJohn.Forte@Sun.COM  * to establish IP communication with. The no. of entries in the dest hash
6111*7836SJohn.Forte@Sun.COM  * table must always be less than or equal to the entries in the routing
6112*7836SJohn.Forte@Sun.COM  * hash table. Every entry in the dest hash table ofcourse must have a
6113*7836SJohn.Forte@Sun.COM  * corresponding entry in the routing hash table
6114*7836SJohn.Forte@Sun.COM  */
6115*7836SJohn.Forte@Sun.COM static struct fcip_dest *
fcip_add_dest(struct fcip * fptr,struct fcip_routing_table * frp)6116*7836SJohn.Forte@Sun.COM fcip_add_dest(struct fcip *fptr, struct fcip_routing_table *frp)
6117*7836SJohn.Forte@Sun.COM {
6118*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp = NULL;
6119*7836SJohn.Forte@Sun.COM 	la_wwn_t	*pwwn;
6120*7836SJohn.Forte@Sun.COM 	int hash_bucket;
6121*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdest_new;
6122*7836SJohn.Forte@Sun.COM 
6123*7836SJohn.Forte@Sun.COM 	if (frp == NULL) {
6124*7836SJohn.Forte@Sun.COM 		return (fdestp);
6125*7836SJohn.Forte@Sun.COM 	}
6126*7836SJohn.Forte@Sun.COM 
6127*7836SJohn.Forte@Sun.COM 	pwwn = &frp->fcipr_pwwn;
6128*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_dest_mutex);
6129*7836SJohn.Forte@Sun.COM 	hash_bucket = FCIP_DEST_HASH(pwwn->raw_wwn);
6130*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
6131*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "add dest hash_bucket: 0x%x", hash_bucket));
6132*7836SJohn.Forte@Sun.COM 
6133*7836SJohn.Forte@Sun.COM 	ASSERT(hash_bucket < FCIP_DEST_HASH_ELEMS);
6134*7836SJohn.Forte@Sun.COM 
6135*7836SJohn.Forte@Sun.COM 	fdestp = fptr->fcip_dest[hash_bucket];
6136*7836SJohn.Forte@Sun.COM 	while (fdestp != NULL) {
6137*7836SJohn.Forte@Sun.COM 		mutex_enter(&fdestp->fcipd_mutex);
6138*7836SJohn.Forte@Sun.COM 		if (fdestp->fcipd_rtable) {
6139*7836SJohn.Forte@Sun.COM 			if (fcip_wwn_compare(pwwn, &fdestp->fcipd_pwwn,
6140*7836SJohn.Forte@Sun.COM 			    FCIP_COMPARE_PWWN) == 0) {
6141*7836SJohn.Forte@Sun.COM 				mutex_exit(&fdestp->fcipd_mutex);
6142*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_dest_mutex);
6143*7836SJohn.Forte@Sun.COM 				return (fdestp);
6144*7836SJohn.Forte@Sun.COM 			}
6145*7836SJohn.Forte@Sun.COM 		}
6146*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
6147*7836SJohn.Forte@Sun.COM 		fdestp = fdestp->fcipd_next;
6148*7836SJohn.Forte@Sun.COM 	}
6149*7836SJohn.Forte@Sun.COM 
6150*7836SJohn.Forte@Sun.COM 	ASSERT(fdestp == NULL);
6151*7836SJohn.Forte@Sun.COM 
6152*7836SJohn.Forte@Sun.COM 	fdest_new = (struct fcip_dest *)
6153*7836SJohn.Forte@Sun.COM 			kmem_zalloc(sizeof (struct fcip_dest), KM_SLEEP);
6154*7836SJohn.Forte@Sun.COM 
6155*7836SJohn.Forte@Sun.COM 	mutex_init(&fdest_new->fcipd_mutex, NULL, MUTEX_DRIVER, NULL);
6156*7836SJohn.Forte@Sun.COM 	fdest_new->fcipd_next = fptr->fcip_dest[hash_bucket];
6157*7836SJohn.Forte@Sun.COM 	fdest_new->fcipd_refcnt = 0;
6158*7836SJohn.Forte@Sun.COM 	fdest_new->fcipd_rtable = frp;
6159*7836SJohn.Forte@Sun.COM 	fdest_new->fcipd_ncmds = 0;
6160*7836SJohn.Forte@Sun.COM 	fptr->fcip_dest[hash_bucket] = fdest_new;
6161*7836SJohn.Forte@Sun.COM 	fdest_new->fcipd_flags = FCIP_PORT_NOTLOGGED;
6162*7836SJohn.Forte@Sun.COM 
6163*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_dest_mutex);
6164*7836SJohn.Forte@Sun.COM 	return (fdest_new);
6165*7836SJohn.Forte@Sun.COM }
6166*7836SJohn.Forte@Sun.COM 
6167*7836SJohn.Forte@Sun.COM /*
6168*7836SJohn.Forte@Sun.COM  * Cleanup the dest hash table and remove all entries
6169*7836SJohn.Forte@Sun.COM  */
6170*7836SJohn.Forte@Sun.COM static void
fcip_cleanup_dest(struct fcip * fptr)6171*7836SJohn.Forte@Sun.COM fcip_cleanup_dest(struct fcip *fptr)
6172*7836SJohn.Forte@Sun.COM {
6173*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdestp = NULL;
6174*7836SJohn.Forte@Sun.COM 	struct fcip_dest *fdest_delp = NULL;
6175*7836SJohn.Forte@Sun.COM 	int i;
6176*7836SJohn.Forte@Sun.COM 
6177*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_dest_mutex);
6178*7836SJohn.Forte@Sun.COM 
6179*7836SJohn.Forte@Sun.COM 	for (i = 0; i < FCIP_DEST_HASH_ELEMS; i++) {
6180*7836SJohn.Forte@Sun.COM 		fdestp = fptr->fcip_dest[i];
6181*7836SJohn.Forte@Sun.COM 		while (fdestp != NULL) {
6182*7836SJohn.Forte@Sun.COM 			mutex_destroy(&fdestp->fcipd_mutex);
6183*7836SJohn.Forte@Sun.COM 			fdest_delp = fdestp;
6184*7836SJohn.Forte@Sun.COM 			fdestp = fdestp->fcipd_next;
6185*7836SJohn.Forte@Sun.COM 			kmem_free(fdest_delp, sizeof (struct fcip_dest));
6186*7836SJohn.Forte@Sun.COM 			fptr->fcip_dest[i] = NULL;
6187*7836SJohn.Forte@Sun.COM 		}
6188*7836SJohn.Forte@Sun.COM 	}
6189*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_dest_mutex);
6190*7836SJohn.Forte@Sun.COM }
6191*7836SJohn.Forte@Sun.COM 
6192*7836SJohn.Forte@Sun.COM 
6193*7836SJohn.Forte@Sun.COM /*
6194*7836SJohn.Forte@Sun.COM  * Send FARP requests for Fabric ports when we don't have the port
6195*7836SJohn.Forte@Sun.COM  * we wish to talk to in our routing hash table. FARP is specially required
6196*7836SJohn.Forte@Sun.COM  * to talk to FC switches for inband switch management. Most FC switches
6197*7836SJohn.Forte@Sun.COM  * today have a switch FC IP address for IP over FC inband switch management
6198*7836SJohn.Forte@Sun.COM  * but the WWN and Port_ID for this traffic is not available through the
6199*7836SJohn.Forte@Sun.COM  * Nameservers since the switch themeselves are transparent.
6200*7836SJohn.Forte@Sun.COM  */
6201*7836SJohn.Forte@Sun.COM /* ARGSUSED */
6202*7836SJohn.Forte@Sun.COM static struct fcip_dest *
fcip_do_farp(struct fcip * fptr,la_wwn_t * pwwn,char * ip_addr,size_t ip_addr_len,int flags)6203*7836SJohn.Forte@Sun.COM fcip_do_farp(struct fcip *fptr, la_wwn_t *pwwn, char *ip_addr,
6204*7836SJohn.Forte@Sun.COM     size_t ip_addr_len, int flags)
6205*7836SJohn.Forte@Sun.COM {
6206*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt;
6207*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6208*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6209*7836SJohn.Forte@Sun.COM 	la_els_farp_t		farp_cmd;
6210*7836SJohn.Forte@Sun.COM 	la_els_farp_t		*fcmd;
6211*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp = NULL;
6212*7836SJohn.Forte@Sun.COM 	int			rval;
6213*7836SJohn.Forte@Sun.COM 	clock_t			farp_lbolt;
6214*7836SJohn.Forte@Sun.COM 	la_wwn_t		broadcast_wwn;
6215*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*bdestp;
6216*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table 	*frp;
6217*7836SJohn.Forte@Sun.COM 
6218*7836SJohn.Forte@Sun.COM 	bdestp = fcip_get_dest(fptr, &broadcast_wwn);
6219*7836SJohn.Forte@Sun.COM 
6220*7836SJohn.Forte@Sun.COM 	if (bdestp == NULL) {
6221*7836SJohn.Forte@Sun.COM 		return (fdestp);
6222*7836SJohn.Forte@Sun.COM 	}
6223*7836SJohn.Forte@Sun.COM 
6224*7836SJohn.Forte@Sun.COM 	fcip_pkt = fcip_ipkt_alloc(fptr, sizeof (la_els_farp_t),
6225*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_farp_t), bdestp->fcipd_pd, KM_SLEEP);
6226*7836SJohn.Forte@Sun.COM 
6227*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
6228*7836SJohn.Forte@Sun.COM 		return (fdestp);
6229*7836SJohn.Forte@Sun.COM 	}
6230*7836SJohn.Forte@Sun.COM 
6231*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6232*7836SJohn.Forte@Sun.COM 	ether_to_wwn(&fcip_arpbroadcast_addr, &broadcast_wwn);
6233*7836SJohn.Forte@Sun.COM 
6234*7836SJohn.Forte@Sun.COM 	mutex_enter(&bdestp->fcipd_mutex);
6235*7836SJohn.Forte@Sun.COM 	if (bdestp->fcipd_rtable == NULL) {
6236*7836SJohn.Forte@Sun.COM 		mutex_exit(&bdestp->fcipd_mutex);
6237*7836SJohn.Forte@Sun.COM 		fcip_ipkt_free(fcip_pkt);
6238*7836SJohn.Forte@Sun.COM 		return (fdestp);
6239*7836SJohn.Forte@Sun.COM 	}
6240*7836SJohn.Forte@Sun.COM 
6241*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dest = bdestp;
6242*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_fca_device = bdestp->fcipd_fca_dev;
6243*7836SJohn.Forte@Sun.COM 
6244*7836SJohn.Forte@Sun.COM 	bdestp->fcipd_ncmds++;
6245*7836SJohn.Forte@Sun.COM 	mutex_exit(&bdestp->fcipd_mutex);
6246*7836SJohn.Forte@Sun.COM 
6247*7836SJohn.Forte@Sun.COM 	fcip_init_broadcast_pkt(fcip_pkt, NULL, 1);
6248*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags |= FCIP_PKT_IN_LIST;
6249*7836SJohn.Forte@Sun.COM 
6250*7836SJohn.Forte@Sun.COM 	/*
6251*7836SJohn.Forte@Sun.COM 	 * Now initialize the FARP payload itself
6252*7836SJohn.Forte@Sun.COM 	 */
6253*7836SJohn.Forte@Sun.COM 	fcmd = &farp_cmd;
6254*7836SJohn.Forte@Sun.COM 	fcmd->ls_code.ls_code = LA_ELS_FARP_REQ;
6255*7836SJohn.Forte@Sun.COM 	fcmd->ls_code.mbz = 0;
6256*7836SJohn.Forte@Sun.COM 	/*
6257*7836SJohn.Forte@Sun.COM 	 * for now just match the Port WWN since the other match addr
6258*7836SJohn.Forte@Sun.COM 	 * code points are optional. We can explore matching the IP address
6259*7836SJohn.Forte@Sun.COM 	 * if needed
6260*7836SJohn.Forte@Sun.COM 	 */
6261*7836SJohn.Forte@Sun.COM 	if (ip_addr) {
6262*7836SJohn.Forte@Sun.COM 		fcmd->match_addr = FARP_MATCH_WW_PN_IPv4;
6263*7836SJohn.Forte@Sun.COM 	} else {
6264*7836SJohn.Forte@Sun.COM 		fcmd->match_addr = FARP_MATCH_WW_PN;
6265*7836SJohn.Forte@Sun.COM 	}
6266*7836SJohn.Forte@Sun.COM 
6267*7836SJohn.Forte@Sun.COM 	/*
6268*7836SJohn.Forte@Sun.COM 	 * Request the responder port to log into us - that way
6269*7836SJohn.Forte@Sun.COM 	 * the Transport is aware of the remote port when we create
6270*7836SJohn.Forte@Sun.COM 	 * an entry for it in our tables
6271*7836SJohn.Forte@Sun.COM 	 */
6272*7836SJohn.Forte@Sun.COM 	fcmd->resp_flags = FARP_INIT_REPLY | FARP_INIT_P_LOGI;
6273*7836SJohn.Forte@Sun.COM 	fcmd->req_id = fport->fcipp_sid;
6274*7836SJohn.Forte@Sun.COM 	fcmd->dest_id.port_id = fc_pkt->pkt_cmd_fhdr.d_id;
6275*7836SJohn.Forte@Sun.COM 	bcopy(&fport->fcipp_pwwn, &fcmd->req_pwwn, sizeof (la_wwn_t));
6276*7836SJohn.Forte@Sun.COM 	bcopy(&fport->fcipp_nwwn, &fcmd->req_nwwn, sizeof (la_wwn_t));
6277*7836SJohn.Forte@Sun.COM 	bcopy(pwwn, &fcmd->resp_pwwn, sizeof (la_wwn_t));
6278*7836SJohn.Forte@Sun.COM 	/*
6279*7836SJohn.Forte@Sun.COM 	 * copy in source IP address if we get to know it
6280*7836SJohn.Forte@Sun.COM 	 */
6281*7836SJohn.Forte@Sun.COM 	if (ip_addr) {
6282*7836SJohn.Forte@Sun.COM 		bcopy(ip_addr, fcmd->resp_ip, ip_addr_len);
6283*7836SJohn.Forte@Sun.COM 	}
6284*7836SJohn.Forte@Sun.COM 
6285*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmdlen = sizeof (la_els_farp_t);
6286*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_rsplen = sizeof (la_els_farp_t);
6287*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6288*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_private = (opaque_t)fcip_pkt;
6289*7836SJohn.Forte@Sun.COM 
6290*7836SJohn.Forte@Sun.COM 	/*
6291*7836SJohn.Forte@Sun.COM 	 * Endian safe copy
6292*7836SJohn.Forte@Sun.COM 	 */
6293*7836SJohn.Forte@Sun.COM 	FCIP_CP_OUT(fcmd, fc_pkt->pkt_cmd, fc_pkt->pkt_cmd_acc,
6294*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_farp_t));
6295*7836SJohn.Forte@Sun.COM 
6296*7836SJohn.Forte@Sun.COM 	/*
6297*7836SJohn.Forte@Sun.COM 	 * send the packet in polled mode.
6298*7836SJohn.Forte@Sun.COM 	 */
6299*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_issue_els(fport->fcipp_handle, fc_pkt);
6300*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
6301*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_WARN,
6302*7836SJohn.Forte@Sun.COM 		    "fcip_transport of farp pkt failed 0x%x", rval));
6303*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_LIST;
6304*7836SJohn.Forte@Sun.COM 		fcip_ipkt_free(fcip_pkt);
6305*7836SJohn.Forte@Sun.COM 
6306*7836SJohn.Forte@Sun.COM 		mutex_enter(&bdestp->fcipd_mutex);
6307*7836SJohn.Forte@Sun.COM 		bdestp->fcipd_ncmds--;
6308*7836SJohn.Forte@Sun.COM 		mutex_exit(&bdestp->fcipd_mutex);
6309*7836SJohn.Forte@Sun.COM 
6310*7836SJohn.Forte@Sun.COM 		return (fdestp);
6311*7836SJohn.Forte@Sun.COM 	}
6312*7836SJohn.Forte@Sun.COM 
6313*7836SJohn.Forte@Sun.COM 	farp_lbolt = ddi_get_lbolt();
6314*7836SJohn.Forte@Sun.COM 	farp_lbolt += drv_usectohz(FCIP_FARP_TIMEOUT);
6315*7836SJohn.Forte@Sun.COM 
6316*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
6317*7836SJohn.Forte@Sun.COM 	fptr->fcip_farp_rsp_flag = 0;
6318*7836SJohn.Forte@Sun.COM 	while (!fptr->fcip_farp_rsp_flag) {
6319*7836SJohn.Forte@Sun.COM 		if (cv_timedwait(&fptr->fcip_farp_cv, &fptr->fcip_mutex,
6320*7836SJohn.Forte@Sun.COM 		    farp_lbolt) == -1) {
6321*7836SJohn.Forte@Sun.COM 			/*
6322*7836SJohn.Forte@Sun.COM 			 * No FARP response from any destination port
6323*7836SJohn.Forte@Sun.COM 			 * so bail out.
6324*7836SJohn.Forte@Sun.COM 			 */
6325*7836SJohn.Forte@Sun.COM 			fptr->fcip_farp_rsp_flag = 1;
6326*7836SJohn.Forte@Sun.COM 		} else {
6327*7836SJohn.Forte@Sun.COM 			/*
6328*7836SJohn.Forte@Sun.COM 			 * We received a FARP response - check to see if the
6329*7836SJohn.Forte@Sun.COM 			 * response was in reply to our FARP request.
6330*7836SJohn.Forte@Sun.COM 			 */
6331*7836SJohn.Forte@Sun.COM 
6332*7836SJohn.Forte@Sun.COM 			mutex_enter(&fptr->fcip_rt_mutex);
6333*7836SJohn.Forte@Sun.COM 			frp = fcip_lookup_rtable(fptr, pwwn, FCIP_COMPARE_NWWN);
6334*7836SJohn.Forte@Sun.COM 			mutex_exit(&fptr->fcip_rt_mutex);
6335*7836SJohn.Forte@Sun.COM 
6336*7836SJohn.Forte@Sun.COM 			if ((frp != NULL) &&
6337*7836SJohn.Forte@Sun.COM 			    !FCIP_RTE_UNAVAIL(frp->fcipr_state)) {
6338*7836SJohn.Forte@Sun.COM 				fdestp = fcip_get_dest(fptr, pwwn);
6339*7836SJohn.Forte@Sun.COM 			} else {
6340*7836SJohn.Forte@Sun.COM 				/*
6341*7836SJohn.Forte@Sun.COM 				 * Not our FARP response so go back and wait
6342*7836SJohn.Forte@Sun.COM 				 * again till FARP_TIMEOUT expires
6343*7836SJohn.Forte@Sun.COM 				 */
6344*7836SJohn.Forte@Sun.COM 				fptr->fcip_farp_rsp_flag = 0;
6345*7836SJohn.Forte@Sun.COM 			}
6346*7836SJohn.Forte@Sun.COM 		}
6347*7836SJohn.Forte@Sun.COM 	}
6348*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
6349*7836SJohn.Forte@Sun.COM 
6350*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags |= FCIP_PKT_IN_LIST;
6351*7836SJohn.Forte@Sun.COM 	fcip_ipkt_free(fcip_pkt);
6352*7836SJohn.Forte@Sun.COM 	mutex_enter(&bdestp->fcipd_mutex);
6353*7836SJohn.Forte@Sun.COM 	bdestp->fcipd_ncmds--;
6354*7836SJohn.Forte@Sun.COM 	mutex_exit(&bdestp->fcipd_mutex);
6355*7836SJohn.Forte@Sun.COM 	return (fdestp);
6356*7836SJohn.Forte@Sun.COM }
6357*7836SJohn.Forte@Sun.COM 
6358*7836SJohn.Forte@Sun.COM 
6359*7836SJohn.Forte@Sun.COM 
6360*7836SJohn.Forte@Sun.COM /*
6361*7836SJohn.Forte@Sun.COM  * Helper routine to PLOGI to a remote port we wish to talk to.
6362*7836SJohn.Forte@Sun.COM  * This may not be required since the port driver does logins anyway,
6363*7836SJohn.Forte@Sun.COM  * but this can be required in fabric cases since FARP requests/responses
6364*7836SJohn.Forte@Sun.COM  * don't require you to be logged in?
6365*7836SJohn.Forte@Sun.COM  */
6366*7836SJohn.Forte@Sun.COM 
6367*7836SJohn.Forte@Sun.COM /* ARGSUSED */
6368*7836SJohn.Forte@Sun.COM static int
fcip_do_plogi(struct fcip * fptr,struct fcip_routing_table * frp)6369*7836SJohn.Forte@Sun.COM fcip_do_plogi(struct fcip *fptr, struct fcip_routing_table *frp)
6370*7836SJohn.Forte@Sun.COM {
6371*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt;
6372*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6373*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6374*7836SJohn.Forte@Sun.COM 	la_els_logi_t		logi;
6375*7836SJohn.Forte@Sun.COM 	int			rval;
6376*7836SJohn.Forte@Sun.COM 	fc_frame_hdr_t		*fr_hdr;
6377*7836SJohn.Forte@Sun.COM 
6378*7836SJohn.Forte@Sun.COM 	/*
6379*7836SJohn.Forte@Sun.COM 	 * Don't bother to login for broadcast RTE entries
6380*7836SJohn.Forte@Sun.COM 	 */
6381*7836SJohn.Forte@Sun.COM 	if ((frp->fcipr_d_id.port_id == 0x0) ||
6382*7836SJohn.Forte@Sun.COM 	    (frp->fcipr_d_id.port_id == 0xffffff)) {
6383*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
6384*7836SJohn.Forte@Sun.COM 	}
6385*7836SJohn.Forte@Sun.COM 
6386*7836SJohn.Forte@Sun.COM 	/*
6387*7836SJohn.Forte@Sun.COM 	 * We shouldn't pound in too many logins here
6388*7836SJohn.Forte@Sun.COM 	 *
6389*7836SJohn.Forte@Sun.COM 	 */
6390*7836SJohn.Forte@Sun.COM 	if (frp->fcipr_state == FCIP_RT_LOGIN_PROGRESS ||
6391*7836SJohn.Forte@Sun.COM 	    frp->fcipr_state == PORT_DEVICE_LOGGED_IN) {
6392*7836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
6393*7836SJohn.Forte@Sun.COM 	}
6394*7836SJohn.Forte@Sun.COM 
6395*7836SJohn.Forte@Sun.COM 	fcip_pkt = fcip_ipkt_alloc(fptr, sizeof (la_els_logi_t),
6396*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_logi_t), frp->fcipr_pd, KM_SLEEP);
6397*7836SJohn.Forte@Sun.COM 
6398*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
6399*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
6400*7836SJohn.Forte@Sun.COM 	}
6401*7836SJohn.Forte@Sun.COM 
6402*7836SJohn.Forte@Sun.COM 	/*
6403*7836SJohn.Forte@Sun.COM 	 * Update back pointer for login state update
6404*7836SJohn.Forte@Sun.COM 	 */
6405*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_frp = frp;
6406*7836SJohn.Forte@Sun.COM 	frp->fcipr_state = FCIP_RT_LOGIN_PROGRESS;
6407*7836SJohn.Forte@Sun.COM 
6408*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6409*7836SJohn.Forte@Sun.COM 
6410*7836SJohn.Forte@Sun.COM 	/*
6411*7836SJohn.Forte@Sun.COM 	 * Initialize frame header for ELS
6412*7836SJohn.Forte@Sun.COM 	 */
6413*7836SJohn.Forte@Sun.COM 	fr_hdr = &fc_pkt->pkt_cmd_fhdr;
6414*7836SJohn.Forte@Sun.COM 	fr_hdr->r_ctl = R_CTL_ELS_REQ;
6415*7836SJohn.Forte@Sun.COM 	fr_hdr->type = FC_TYPE_EXTENDED_LS;
6416*7836SJohn.Forte@Sun.COM 	fr_hdr->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
6417*7836SJohn.Forte@Sun.COM 	fr_hdr->df_ctl = 0;
6418*7836SJohn.Forte@Sun.COM 	fr_hdr->s_id = fport->fcipp_sid.port_id;
6419*7836SJohn.Forte@Sun.COM 	fr_hdr->d_id = frp->fcipr_d_id.port_id;
6420*7836SJohn.Forte@Sun.COM 	fr_hdr->seq_cnt = 0;
6421*7836SJohn.Forte@Sun.COM 	fr_hdr->ox_id = 0xffff;
6422*7836SJohn.Forte@Sun.COM 	fr_hdr->rx_id = 0xffff;
6423*7836SJohn.Forte@Sun.COM 	fr_hdr->ro = 0;
6424*7836SJohn.Forte@Sun.COM 
6425*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_rsplen = sizeof (la_els_logi_t);
6426*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_comp = fcip_ipkt_callback;
6427*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6428*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_timeout = 10;	/* 10 seconds */
6429*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_ttl = fptr->fcip_timeout_ticks + fc_pkt->pkt_timeout;
6430*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_private = (opaque_t)fcip_pkt;
6431*7836SJohn.Forte@Sun.COM 
6432*7836SJohn.Forte@Sun.COM 	/*
6433*7836SJohn.Forte@Sun.COM 	 * Everybody does class 3, so let's just set it.  If the transport
6434*7836SJohn.Forte@Sun.COM 	 * knows better, it will deal with the class appropriately.
6435*7836SJohn.Forte@Sun.COM 	 */
6436*7836SJohn.Forte@Sun.COM 
6437*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_flags = FC_TRAN_INTR | FC_TRAN_CLASS3;
6438*7836SJohn.Forte@Sun.COM 
6439*7836SJohn.Forte@Sun.COM 	/*
6440*7836SJohn.Forte@Sun.COM 	 * we need only fill in the ls_code and the cmd frame header
6441*7836SJohn.Forte@Sun.COM 	 */
6442*7836SJohn.Forte@Sun.COM 	bzero((void *)&logi, sizeof (la_els_logi_t));
6443*7836SJohn.Forte@Sun.COM 	logi.ls_code.ls_code = LA_ELS_PLOGI;
6444*7836SJohn.Forte@Sun.COM 	logi.ls_code.mbz = 0;
6445*7836SJohn.Forte@Sun.COM 
6446*7836SJohn.Forte@Sun.COM 	FCIP_CP_OUT((uint8_t *)&logi, fc_pkt->pkt_cmd, fc_pkt->pkt_cmd_acc,
6447*7836SJohn.Forte@Sun.COM 	    sizeof (la_els_logi_t));
6448*7836SJohn.Forte@Sun.COM 
6449*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_login(fport->fcipp_handle, &fc_pkt, 1);
6450*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
6451*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
6452*7836SJohn.Forte@Sun.COM 		    "!fc_ulp_login failed for d_id: 0x%x, rval: 0x%x",
6453*7836SJohn.Forte@Sun.COM 		    frp->fcipr_d_id.port_id, rval);
6454*7836SJohn.Forte@Sun.COM 		fcip_ipkt_free(fcip_pkt);
6455*7836SJohn.Forte@Sun.COM 	}
6456*7836SJohn.Forte@Sun.COM 	return (rval);
6457*7836SJohn.Forte@Sun.COM }
6458*7836SJohn.Forte@Sun.COM 
6459*7836SJohn.Forte@Sun.COM /*
6460*7836SJohn.Forte@Sun.COM  * The packet callback routine - called from the transport/FCA after
6461*7836SJohn.Forte@Sun.COM  * it is done DMA'ing/sending out the packet contents on the wire so
6462*7836SJohn.Forte@Sun.COM  * that the alloc'ed packet can be freed
6463*7836SJohn.Forte@Sun.COM  */
6464*7836SJohn.Forte@Sun.COM static void
fcip_ipkt_callback(fc_packet_t * fc_pkt)6465*7836SJohn.Forte@Sun.COM fcip_ipkt_callback(fc_packet_t *fc_pkt)
6466*7836SJohn.Forte@Sun.COM {
6467*7836SJohn.Forte@Sun.COM 	ls_code_t			logi_req;
6468*7836SJohn.Forte@Sun.COM 	ls_code_t			logi_resp;
6469*7836SJohn.Forte@Sun.COM 	fcip_pkt_t			*fcip_pkt;
6470*7836SJohn.Forte@Sun.COM 	fc_frame_hdr_t			*fr_hdr;
6471*7836SJohn.Forte@Sun.COM 	struct fcip 			*fptr;
6472*7836SJohn.Forte@Sun.COM 	fcip_port_info_t		*fport;
6473*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table	*frp;
6474*7836SJohn.Forte@Sun.COM 
6475*7836SJohn.Forte@Sun.COM 	fr_hdr = &fc_pkt->pkt_cmd_fhdr;
6476*7836SJohn.Forte@Sun.COM 
6477*7836SJohn.Forte@Sun.COM 	FCIP_CP_IN(fc_pkt->pkt_resp, (uint8_t *)&logi_resp,
6478*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_resp_acc, sizeof (logi_resp));
6479*7836SJohn.Forte@Sun.COM 
6480*7836SJohn.Forte@Sun.COM 	FCIP_CP_IN(fc_pkt->pkt_cmd, (uint8_t *)&logi_req, fc_pkt->pkt_cmd_acc,
6481*7836SJohn.Forte@Sun.COM 	    sizeof (logi_req));
6482*7836SJohn.Forte@Sun.COM 
6483*7836SJohn.Forte@Sun.COM 	fcip_pkt = (fcip_pkt_t *)fc_pkt->pkt_ulp_private;
6484*7836SJohn.Forte@Sun.COM 	frp = fcip_pkt->fcip_pkt_frp;
6485*7836SJohn.Forte@Sun.COM 	fptr = fcip_pkt->fcip_pkt_fptr;
6486*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
6487*7836SJohn.Forte@Sun.COM 
6488*7836SJohn.Forte@Sun.COM 	ASSERT(logi_req.ls_code == LA_ELS_PLOGI);
6489*7836SJohn.Forte@Sun.COM 
6490*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_state != FC_PKT_SUCCESS ||
6491*7836SJohn.Forte@Sun.COM 	    logi_resp.ls_code != LA_ELS_ACC) {
6492*7836SJohn.Forte@Sun.COM 		/* EMPTY */
6493*7836SJohn.Forte@Sun.COM 
6494*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_WARN,
6495*7836SJohn.Forte@Sun.COM 		    "opcode : 0x%x to d_id: 0x%x failed",
6496*7836SJohn.Forte@Sun.COM 		    logi_req.ls_code, fr_hdr->d_id));
6497*7836SJohn.Forte@Sun.COM 
6498*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
6499*7836SJohn.Forte@Sun.COM 		frp->fcipr_state = PORT_DEVICE_INVALID;
6500*7836SJohn.Forte@Sun.COM 		frp->fcipr_invalid_timeout = fptr->fcip_timeout_ticks +
6501*7836SJohn.Forte@Sun.COM 		    (FCIP_RTE_TIMEOUT / 2);
6502*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
6503*7836SJohn.Forte@Sun.COM 	} else {
6504*7836SJohn.Forte@Sun.COM 		fc_portid_t	d_id;
6505*7836SJohn.Forte@Sun.COM 
6506*7836SJohn.Forte@Sun.COM 		d_id.port_id = fr_hdr->d_id;
6507*7836SJohn.Forte@Sun.COM 		d_id.priv_lilp_posit = 0;
6508*7836SJohn.Forte@Sun.COM 
6509*7836SJohn.Forte@Sun.COM 		/*
6510*7836SJohn.Forte@Sun.COM 		 * Update PLOGI results; FCA Handle, and Port device handles
6511*7836SJohn.Forte@Sun.COM 		 */
6512*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
6513*7836SJohn.Forte@Sun.COM 		frp->fcipr_pd = fc_pkt->pkt_pd;
6514*7836SJohn.Forte@Sun.COM 		frp->fcipr_fca_dev =
6515*7836SJohn.Forte@Sun.COM 		    fc_ulp_get_fca_device(fport->fcipp_handle, d_id);
6516*7836SJohn.Forte@Sun.COM 		frp->fcipr_state = PORT_DEVICE_LOGGED_IN;
6517*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
6518*7836SJohn.Forte@Sun.COM 	}
6519*7836SJohn.Forte@Sun.COM 
6520*7836SJohn.Forte@Sun.COM 	fcip_ipkt_free(fcip_pkt);
6521*7836SJohn.Forte@Sun.COM }
6522*7836SJohn.Forte@Sun.COM 
6523*7836SJohn.Forte@Sun.COM 
6524*7836SJohn.Forte@Sun.COM /*
6525*7836SJohn.Forte@Sun.COM  * pkt_alloc routine for outbound IP datagrams. The cache constructor
6526*7836SJohn.Forte@Sun.COM  * Only initializes the pkt_cmd_dma (which is where the outbound datagram
6527*7836SJohn.Forte@Sun.COM  * is stuffed) since we don't expect response
6528*7836SJohn.Forte@Sun.COM  */
6529*7836SJohn.Forte@Sun.COM static fcip_pkt_t *
fcip_pkt_alloc(struct fcip * fptr,mblk_t * bp,int flags,int datalen)6530*7836SJohn.Forte@Sun.COM fcip_pkt_alloc(struct fcip *fptr, mblk_t *bp, int flags, int datalen)
6531*7836SJohn.Forte@Sun.COM {
6532*7836SJohn.Forte@Sun.COM 	fcip_pkt_t 	*fcip_pkt;
6533*7836SJohn.Forte@Sun.COM 	fc_packet_t	*fc_pkt;
6534*7836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	pkt_cookie;
6535*7836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	*cp;
6536*7836SJohn.Forte@Sun.COM 	uint32_t		cnt;
6537*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6538*7836SJohn.Forte@Sun.COM 
6539*7836SJohn.Forte@Sun.COM 	fcip_pkt = kmem_cache_alloc(fptr->fcip_xmit_cache, flags);
6540*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
6541*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM, (CE_WARN,
6542*7836SJohn.Forte@Sun.COM 		    "fcip_pkt_alloc: kmem_cache_alloc failed"));
6543*7836SJohn.Forte@Sun.COM 		return (NULL);
6544*7836SJohn.Forte@Sun.COM 	}
6545*7836SJohn.Forte@Sun.COM 
6546*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6547*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_fcpktp = fc_pkt;
6548*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_flags = 0;
6549*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dma_flags = 0;
6550*7836SJohn.Forte@Sun.COM 
6551*7836SJohn.Forte@Sun.COM 	/*
6552*7836SJohn.Forte@Sun.COM 	 * the cache constructor has allocated the dma handle
6553*7836SJohn.Forte@Sun.COM 	 */
6554*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmd = (caddr_t)bp->b_rptr;
6555*7836SJohn.Forte@Sun.COM 	if (ddi_dma_addr_bind_handle(fc_pkt->pkt_cmd_dma, NULL,
6556*7836SJohn.Forte@Sun.COM 	    (caddr_t)bp->b_rptr, datalen, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
6557*7836SJohn.Forte@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &pkt_cookie,
6558*7836SJohn.Forte@Sun.COM 	    &fc_pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED) {
6559*7836SJohn.Forte@Sun.COM 			goto fail;
6560*7836SJohn.Forte@Sun.COM 	}
6561*7836SJohn.Forte@Sun.COM 
6562*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dma_flags |= FCIP_CMD_DMA_BOUND;
6563*7836SJohn.Forte@Sun.COM 
6564*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_cmd_cookie_cnt >
6565*7836SJohn.Forte@Sun.COM 	    fport->fcipp_cmd_dma_attr.dma_attr_sgllen) {
6566*7836SJohn.Forte@Sun.COM 		goto fail;
6567*7836SJohn.Forte@Sun.COM 	}
6568*7836SJohn.Forte@Sun.COM 
6569*7836SJohn.Forte@Sun.COM 	ASSERT(fc_pkt->pkt_cmd_cookie_cnt != 0);
6570*7836SJohn.Forte@Sun.COM 
6571*7836SJohn.Forte@Sun.COM 	cp = fc_pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
6572*7836SJohn.Forte@Sun.COM 	    fc_pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
6573*7836SJohn.Forte@Sun.COM 	    KM_NOSLEEP);
6574*7836SJohn.Forte@Sun.COM 
6575*7836SJohn.Forte@Sun.COM 	if (cp == NULL) {
6576*7836SJohn.Forte@Sun.COM 		goto fail;
6577*7836SJohn.Forte@Sun.COM 	}
6578*7836SJohn.Forte@Sun.COM 
6579*7836SJohn.Forte@Sun.COM 	*cp = pkt_cookie;
6580*7836SJohn.Forte@Sun.COM 	cp++;
6581*7836SJohn.Forte@Sun.COM 	for (cnt = 1; cnt < fc_pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
6582*7836SJohn.Forte@Sun.COM 		ddi_dma_nextcookie(fc_pkt->pkt_cmd_dma, &pkt_cookie);
6583*7836SJohn.Forte@Sun.COM 		*cp = pkt_cookie;
6584*7836SJohn.Forte@Sun.COM 	}
6585*7836SJohn.Forte@Sun.COM 
6586*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmdlen = datalen;
6587*7836SJohn.Forte@Sun.COM 
6588*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_mp = NULL;
6589*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_wq = NULL;
6590*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_dest = NULL;
6591*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_next = NULL;
6592*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_prev = NULL;
6593*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_state = 0;
6594*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_reason = 0;
6595*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags = 0;
6596*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_frp = NULL;
6597*7836SJohn.Forte@Sun.COM 
6598*7836SJohn.Forte@Sun.COM 	return (fcip_pkt);
6599*7836SJohn.Forte@Sun.COM fail:
6600*7836SJohn.Forte@Sun.COM 	if (fcip_pkt) {
6601*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, 0);
6602*7836SJohn.Forte@Sun.COM 	}
6603*7836SJohn.Forte@Sun.COM 	return ((fcip_pkt_t *)0);
6604*7836SJohn.Forte@Sun.COM }
6605*7836SJohn.Forte@Sun.COM 
6606*7836SJohn.Forte@Sun.COM /*
6607*7836SJohn.Forte@Sun.COM  * Free a packet and all its associated resources
6608*7836SJohn.Forte@Sun.COM  */
6609*7836SJohn.Forte@Sun.COM static void
fcip_pkt_free(struct fcip_pkt * fcip_pkt,int free_mblk)6610*7836SJohn.Forte@Sun.COM fcip_pkt_free(struct fcip_pkt *fcip_pkt, int free_mblk)
6611*7836SJohn.Forte@Sun.COM {
6612*7836SJohn.Forte@Sun.COM 	fc_packet_t	*fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6613*7836SJohn.Forte@Sun.COM 	struct fcip *fptr = fcip_pkt->fcip_pkt_fptr;
6614*7836SJohn.Forte@Sun.COM 
6615*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_cmd_cookie != NULL) {
6616*7836SJohn.Forte@Sun.COM 		kmem_free(fc_pkt->pkt_cmd_cookie, fc_pkt->pkt_cmd_cookie_cnt *
6617*7836SJohn.Forte@Sun.COM 		    sizeof (ddi_dma_cookie_t));
6618*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_cmd_cookie = NULL;
6619*7836SJohn.Forte@Sun.COM 	}
6620*7836SJohn.Forte@Sun.COM 
6621*7836SJohn.Forte@Sun.COM 	fcip_free_pkt_dma(fcip_pkt);
6622*7836SJohn.Forte@Sun.COM 	if (free_mblk && fcip_pkt->fcip_pkt_mp) {
6623*7836SJohn.Forte@Sun.COM 		freemsg(fcip_pkt->fcip_pkt_mp);
6624*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_mp = NULL;
6625*7836SJohn.Forte@Sun.COM 	}
6626*7836SJohn.Forte@Sun.COM 
6627*7836SJohn.Forte@Sun.COM 	(void) fc_ulp_uninit_packet(fptr->fcip_port_info->fcipp_handle, fc_pkt);
6628*7836SJohn.Forte@Sun.COM 
6629*7836SJohn.Forte@Sun.COM 	kmem_cache_free(fptr->fcip_xmit_cache, (void *)fcip_pkt);
6630*7836SJohn.Forte@Sun.COM }
6631*7836SJohn.Forte@Sun.COM 
6632*7836SJohn.Forte@Sun.COM /*
6633*7836SJohn.Forte@Sun.COM  * Allocate a Packet for internal driver use. This is for requests
6634*7836SJohn.Forte@Sun.COM  * that originate from within the driver
6635*7836SJohn.Forte@Sun.COM  */
6636*7836SJohn.Forte@Sun.COM static fcip_pkt_t *
fcip_ipkt_alloc(struct fcip * fptr,int cmdlen,int resplen,opaque_t pd,int flags)6637*7836SJohn.Forte@Sun.COM fcip_ipkt_alloc(struct fcip *fptr, int cmdlen, int resplen,
6638*7836SJohn.Forte@Sun.COM     opaque_t pd, int flags)
6639*7836SJohn.Forte@Sun.COM {
6640*7836SJohn.Forte@Sun.COM 	fcip_pkt_t 		*fcip_pkt;
6641*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6642*7836SJohn.Forte@Sun.COM 	int			(*cb)(caddr_t);
6643*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6644*7836SJohn.Forte@Sun.COM 	size_t			real_len;
6645*7836SJohn.Forte@Sun.COM 	uint_t			held_here = 0;
6646*7836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	pkt_cookie;
6647*7836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	*cp;
6648*7836SJohn.Forte@Sun.COM 	uint32_t		cnt;
6649*7836SJohn.Forte@Sun.COM 
6650*7836SJohn.Forte@Sun.COM 	cb = (flags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
6651*7836SJohn.Forte@Sun.COM 
6652*7836SJohn.Forte@Sun.COM 	fcip_pkt = kmem_zalloc((sizeof (fcip_pkt_t) +
6653*7836SJohn.Forte@Sun.COM 	    fport->fcipp_fca_pkt_size), flags);
6654*7836SJohn.Forte@Sun.COM 
6655*7836SJohn.Forte@Sun.COM 	if (fcip_pkt == NULL) {
6656*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
6657*7836SJohn.Forte@Sun.COM 		    (CE_WARN, "pkt alloc of ineternal pkt failed"));
6658*7836SJohn.Forte@Sun.COM 		goto fail;
6659*7836SJohn.Forte@Sun.COM 	}
6660*7836SJohn.Forte@Sun.COM 
6661*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags = FCIP_PKT_INTERNAL;
6662*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_fptr = fptr;
6663*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6664*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_fcpktp = fc_pkt;
6665*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_flags = 0;
6666*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_cmdlen = 0;
6667*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_rsplen = 0;
6668*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_datalen = 0;
6669*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_fca_private = (opaque_t)((caddr_t)fcip_pkt +
6670*7836SJohn.Forte@Sun.COM 	    sizeof (fcip_pkt_t));
6671*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_ulp_private = (opaque_t)fcip_pkt;
6672*7836SJohn.Forte@Sun.COM 
6673*7836SJohn.Forte@Sun.COM 	if (cmdlen) {
6674*7836SJohn.Forte@Sun.COM 		if (ddi_dma_alloc_handle(fptr->fcip_dip,
6675*7836SJohn.Forte@Sun.COM 		    &fport->fcipp_cmd_dma_attr, cb, NULL,
6676*7836SJohn.Forte@Sun.COM 		    &fc_pkt->pkt_cmd_dma) != DDI_SUCCESS) {
6677*7836SJohn.Forte@Sun.COM 			goto fail;
6678*7836SJohn.Forte@Sun.COM 		}
6679*7836SJohn.Forte@Sun.COM 
6680*7836SJohn.Forte@Sun.COM 		if (ddi_dma_mem_alloc(fc_pkt->pkt_cmd_dma, cmdlen,
6681*7836SJohn.Forte@Sun.COM 		    &fport->fcipp_fca_acc_attr, DDI_DMA_CONSISTENT,
6682*7836SJohn.Forte@Sun.COM 		    cb, NULL, (caddr_t *)&fc_pkt->pkt_cmd,
6683*7836SJohn.Forte@Sun.COM 		    &real_len, &fc_pkt->pkt_cmd_acc) != DDI_SUCCESS) {
6684*7836SJohn.Forte@Sun.COM 			goto fail;
6685*7836SJohn.Forte@Sun.COM 		}
6686*7836SJohn.Forte@Sun.COM 
6687*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_dma_flags |= FCIP_CMD_DMA_MEM;
6688*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_cmdlen = cmdlen;
6689*7836SJohn.Forte@Sun.COM 
6690*7836SJohn.Forte@Sun.COM 		if (real_len < cmdlen) {
6691*7836SJohn.Forte@Sun.COM 			goto fail;
6692*7836SJohn.Forte@Sun.COM 		}
6693*7836SJohn.Forte@Sun.COM 
6694*7836SJohn.Forte@Sun.COM 		if (ddi_dma_addr_bind_handle(fc_pkt->pkt_cmd_dma, NULL,
6695*7836SJohn.Forte@Sun.COM 		    (caddr_t)fc_pkt->pkt_cmd, real_len,
6696*7836SJohn.Forte@Sun.COM 		    DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
6697*7836SJohn.Forte@Sun.COM 		    &pkt_cookie, &fc_pkt->pkt_cmd_cookie_cnt) !=
6698*7836SJohn.Forte@Sun.COM 		    DDI_DMA_MAPPED) {
6699*7836SJohn.Forte@Sun.COM 			goto fail;
6700*7836SJohn.Forte@Sun.COM 		}
6701*7836SJohn.Forte@Sun.COM 
6702*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_dma_flags |= FCIP_CMD_DMA_BOUND;
6703*7836SJohn.Forte@Sun.COM 
6704*7836SJohn.Forte@Sun.COM 		if (fc_pkt->pkt_cmd_cookie_cnt >
6705*7836SJohn.Forte@Sun.COM 		    fport->fcipp_cmd_dma_attr.dma_attr_sgllen) {
6706*7836SJohn.Forte@Sun.COM 			goto fail;
6707*7836SJohn.Forte@Sun.COM 		}
6708*7836SJohn.Forte@Sun.COM 
6709*7836SJohn.Forte@Sun.COM 		ASSERT(fc_pkt->pkt_cmd_cookie_cnt != 0);
6710*7836SJohn.Forte@Sun.COM 
6711*7836SJohn.Forte@Sun.COM 		cp = fc_pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
6712*7836SJohn.Forte@Sun.COM 		    fc_pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
6713*7836SJohn.Forte@Sun.COM 		    KM_NOSLEEP);
6714*7836SJohn.Forte@Sun.COM 
6715*7836SJohn.Forte@Sun.COM 		if (cp == NULL) {
6716*7836SJohn.Forte@Sun.COM 			goto fail;
6717*7836SJohn.Forte@Sun.COM 		}
6718*7836SJohn.Forte@Sun.COM 
6719*7836SJohn.Forte@Sun.COM 		*cp = pkt_cookie;
6720*7836SJohn.Forte@Sun.COM 		cp++;
6721*7836SJohn.Forte@Sun.COM 		for (cnt = 1; cnt < fc_pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
6722*7836SJohn.Forte@Sun.COM 			ddi_dma_nextcookie(fc_pkt->pkt_cmd_dma, &pkt_cookie);
6723*7836SJohn.Forte@Sun.COM 			*cp = pkt_cookie;
6724*7836SJohn.Forte@Sun.COM 		}
6725*7836SJohn.Forte@Sun.COM 	}
6726*7836SJohn.Forte@Sun.COM 
6727*7836SJohn.Forte@Sun.COM 	if (resplen) {
6728*7836SJohn.Forte@Sun.COM 		if (ddi_dma_alloc_handle(fptr->fcip_dip,
6729*7836SJohn.Forte@Sun.COM 		    &fport->fcipp_resp_dma_attr, cb, NULL,
6730*7836SJohn.Forte@Sun.COM 		    &fc_pkt->pkt_resp_dma) != DDI_SUCCESS) {
6731*7836SJohn.Forte@Sun.COM 			goto fail;
6732*7836SJohn.Forte@Sun.COM 		}
6733*7836SJohn.Forte@Sun.COM 
6734*7836SJohn.Forte@Sun.COM 		if (ddi_dma_mem_alloc(fc_pkt->pkt_resp_dma, resplen,
6735*7836SJohn.Forte@Sun.COM 		    &fport->fcipp_fca_acc_attr, DDI_DMA_CONSISTENT,
6736*7836SJohn.Forte@Sun.COM 		    cb, NULL, (caddr_t *)&fc_pkt->pkt_resp,
6737*7836SJohn.Forte@Sun.COM 		    &real_len, &fc_pkt->pkt_resp_acc) != DDI_SUCCESS) {
6738*7836SJohn.Forte@Sun.COM 			goto fail;
6739*7836SJohn.Forte@Sun.COM 		}
6740*7836SJohn.Forte@Sun.COM 
6741*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_dma_flags |= FCIP_RESP_DMA_MEM;
6742*7836SJohn.Forte@Sun.COM 
6743*7836SJohn.Forte@Sun.COM 		if (real_len < resplen) {
6744*7836SJohn.Forte@Sun.COM 			goto fail;
6745*7836SJohn.Forte@Sun.COM 		}
6746*7836SJohn.Forte@Sun.COM 
6747*7836SJohn.Forte@Sun.COM 		if (ddi_dma_addr_bind_handle(fc_pkt->pkt_resp_dma, NULL,
6748*7836SJohn.Forte@Sun.COM 		    (caddr_t)fc_pkt->pkt_resp, real_len,
6749*7836SJohn.Forte@Sun.COM 		    DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
6750*7836SJohn.Forte@Sun.COM 		    &pkt_cookie, &fc_pkt->pkt_resp_cookie_cnt) !=
6751*7836SJohn.Forte@Sun.COM 		    DDI_DMA_MAPPED) {
6752*7836SJohn.Forte@Sun.COM 			goto fail;
6753*7836SJohn.Forte@Sun.COM 		}
6754*7836SJohn.Forte@Sun.COM 
6755*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_dma_flags |= FCIP_RESP_DMA_BOUND;
6756*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_rsplen = resplen;
6757*7836SJohn.Forte@Sun.COM 
6758*7836SJohn.Forte@Sun.COM 		if (fc_pkt->pkt_resp_cookie_cnt >
6759*7836SJohn.Forte@Sun.COM 		    fport->fcipp_resp_dma_attr.dma_attr_sgllen) {
6760*7836SJohn.Forte@Sun.COM 			goto fail;
6761*7836SJohn.Forte@Sun.COM 		}
6762*7836SJohn.Forte@Sun.COM 
6763*7836SJohn.Forte@Sun.COM 		ASSERT(fc_pkt->pkt_resp_cookie_cnt != 0);
6764*7836SJohn.Forte@Sun.COM 
6765*7836SJohn.Forte@Sun.COM 		cp = fc_pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
6766*7836SJohn.Forte@Sun.COM 		    fc_pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
6767*7836SJohn.Forte@Sun.COM 		    KM_NOSLEEP);
6768*7836SJohn.Forte@Sun.COM 
6769*7836SJohn.Forte@Sun.COM 		if (cp == NULL) {
6770*7836SJohn.Forte@Sun.COM 			goto fail;
6771*7836SJohn.Forte@Sun.COM 		}
6772*7836SJohn.Forte@Sun.COM 
6773*7836SJohn.Forte@Sun.COM 		*cp = pkt_cookie;
6774*7836SJohn.Forte@Sun.COM 		cp++;
6775*7836SJohn.Forte@Sun.COM 		for (cnt = 1; cnt < fc_pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
6776*7836SJohn.Forte@Sun.COM 			ddi_dma_nextcookie(fc_pkt->pkt_resp_dma, &pkt_cookie);
6777*7836SJohn.Forte@Sun.COM 			*cp = pkt_cookie;
6778*7836SJohn.Forte@Sun.COM 		}
6779*7836SJohn.Forte@Sun.COM 	}
6780*7836SJohn.Forte@Sun.COM 
6781*7836SJohn.Forte@Sun.COM 	/*
6782*7836SJohn.Forte@Sun.COM 	 * Initialize pkt_pd prior to calling fc_ulp_init_packet
6783*7836SJohn.Forte@Sun.COM 	 */
6784*7836SJohn.Forte@Sun.COM 
6785*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_pd = pd;
6786*7836SJohn.Forte@Sun.COM 
6787*7836SJohn.Forte@Sun.COM 	/*
6788*7836SJohn.Forte@Sun.COM 	 * Ask the FCA to bless the internal packet
6789*7836SJohn.Forte@Sun.COM 	 */
6790*7836SJohn.Forte@Sun.COM 	if (fc_ulp_init_packet((opaque_t)fport->fcipp_handle,
6791*7836SJohn.Forte@Sun.COM 	    fc_pkt, flags) != FC_SUCCESS) {
6792*7836SJohn.Forte@Sun.COM 		goto fail;
6793*7836SJohn.Forte@Sun.COM 	}
6794*7836SJohn.Forte@Sun.COM 
6795*7836SJohn.Forte@Sun.COM 	/*
6796*7836SJohn.Forte@Sun.COM 	 * Keep track of # of ipkts alloc-ed
6797*7836SJohn.Forte@Sun.COM 	 * This function can get called with mutex either held or not. So, we'll
6798*7836SJohn.Forte@Sun.COM 	 * grab mutex if it is not already held by this thread.
6799*7836SJohn.Forte@Sun.COM 	 * This has to be cleaned up someday.
6800*7836SJohn.Forte@Sun.COM 	 */
6801*7836SJohn.Forte@Sun.COM 	if (!MUTEX_HELD(&fptr->fcip_mutex)) {
6802*7836SJohn.Forte@Sun.COM 		held_here = 1;
6803*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_mutex);
6804*7836SJohn.Forte@Sun.COM 	}
6805*7836SJohn.Forte@Sun.COM 
6806*7836SJohn.Forte@Sun.COM 	fptr->fcip_num_ipkts_pending++;
6807*7836SJohn.Forte@Sun.COM 
6808*7836SJohn.Forte@Sun.COM 	if (held_here)
6809*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
6810*7836SJohn.Forte@Sun.COM 
6811*7836SJohn.Forte@Sun.COM 	return (fcip_pkt);
6812*7836SJohn.Forte@Sun.COM fail:
6813*7836SJohn.Forte@Sun.COM 	if (fcip_pkt) {
6814*7836SJohn.Forte@Sun.COM 		fcip_ipkt_free(fcip_pkt);
6815*7836SJohn.Forte@Sun.COM 	}
6816*7836SJohn.Forte@Sun.COM 
6817*7836SJohn.Forte@Sun.COM 	return (NULL);
6818*7836SJohn.Forte@Sun.COM }
6819*7836SJohn.Forte@Sun.COM 
6820*7836SJohn.Forte@Sun.COM /*
6821*7836SJohn.Forte@Sun.COM  * free up an internal IP packet (like a FARP pkt etc)
6822*7836SJohn.Forte@Sun.COM  */
6823*7836SJohn.Forte@Sun.COM static void
fcip_ipkt_free(fcip_pkt_t * fcip_pkt)6824*7836SJohn.Forte@Sun.COM fcip_ipkt_free(fcip_pkt_t *fcip_pkt)
6825*7836SJohn.Forte@Sun.COM {
6826*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6827*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr = fcip_pkt->fcip_pkt_fptr;
6828*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6829*7836SJohn.Forte@Sun.COM 
6830*7836SJohn.Forte@Sun.COM 	ASSERT(fptr != NULL);
6831*7836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&fptr->fcip_mutex));
6832*7836SJohn.Forte@Sun.COM 
6833*7836SJohn.Forte@Sun.COM 	/* One less ipkt to wait for */
6834*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
6835*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_num_ipkts_pending)	/* Safety check */
6836*7836SJohn.Forte@Sun.COM 		fptr->fcip_num_ipkts_pending--;
6837*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
6838*7836SJohn.Forte@Sun.COM 
6839*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6840*7836SJohn.Forte@Sun.COM 
6841*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_cmd_cookie != NULL) {
6842*7836SJohn.Forte@Sun.COM 		kmem_free(fc_pkt->pkt_cmd_cookie, fc_pkt->pkt_cmd_cookie_cnt *
6843*7836SJohn.Forte@Sun.COM 		    sizeof (ddi_dma_cookie_t));
6844*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_cmd_cookie = NULL;
6845*7836SJohn.Forte@Sun.COM 	}
6846*7836SJohn.Forte@Sun.COM 
6847*7836SJohn.Forte@Sun.COM 	if (fc_pkt->pkt_resp_cookie != NULL) {
6848*7836SJohn.Forte@Sun.COM 		kmem_free(fc_pkt->pkt_resp_cookie, fc_pkt->pkt_resp_cookie_cnt *
6849*7836SJohn.Forte@Sun.COM 		    sizeof (ddi_dma_cookie_t));
6850*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_resp_cookie = NULL;
6851*7836SJohn.Forte@Sun.COM 	}
6852*7836SJohn.Forte@Sun.COM 
6853*7836SJohn.Forte@Sun.COM 	if (fc_ulp_uninit_packet(fport->fcipp_handle, fc_pkt) != FC_SUCCESS) {
6854*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_ELS, (CE_WARN,
6855*7836SJohn.Forte@Sun.COM 		    "fc_ulp_uninit_pkt failed for internal fc pkt 0x%p",
6856*7836SJohn.Forte@Sun.COM 		    (void *)fc_pkt));
6857*7836SJohn.Forte@Sun.COM 	}
6858*7836SJohn.Forte@Sun.COM 	fcip_free_pkt_dma(fcip_pkt);
6859*7836SJohn.Forte@Sun.COM 	kmem_free(fcip_pkt, (sizeof (fcip_pkt_t) + fport->fcipp_fca_pkt_size));
6860*7836SJohn.Forte@Sun.COM }
6861*7836SJohn.Forte@Sun.COM 
6862*7836SJohn.Forte@Sun.COM /*
6863*7836SJohn.Forte@Sun.COM  * initialize a unicast request. This is a misnomer because even the
6864*7836SJohn.Forte@Sun.COM  * broadcast requests are initialized with this routine
6865*7836SJohn.Forte@Sun.COM  */
6866*7836SJohn.Forte@Sun.COM static void
fcip_init_unicast_pkt(fcip_pkt_t * fcip_pkt,fc_portid_t sid,fc_portid_t did,void (* comp)())6867*7836SJohn.Forte@Sun.COM fcip_init_unicast_pkt(fcip_pkt_t *fcip_pkt, fc_portid_t sid, fc_portid_t did,
6868*7836SJohn.Forte@Sun.COM     void (*comp) ())
6869*7836SJohn.Forte@Sun.COM {
6870*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6871*7836SJohn.Forte@Sun.COM 	fc_frame_hdr_t		*fr_hdr;
6872*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr = fcip_pkt->fcip_pkt_fptr;
6873*7836SJohn.Forte@Sun.COM 
6874*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6875*7836SJohn.Forte@Sun.COM 	fr_hdr = &fc_pkt->pkt_cmd_fhdr;
6876*7836SJohn.Forte@Sun.COM 
6877*7836SJohn.Forte@Sun.COM 	fr_hdr->r_ctl = R_CTL_DEVICE_DATA | R_CTL_UNSOL_DATA;
6878*7836SJohn.Forte@Sun.COM 	fr_hdr->s_id = sid.port_id;
6879*7836SJohn.Forte@Sun.COM 	fr_hdr->d_id = did.port_id;
6880*7836SJohn.Forte@Sun.COM 	fr_hdr->type = FC_TYPE_IS8802_SNAP;
6881*7836SJohn.Forte@Sun.COM 	fr_hdr->f_ctl = F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ;
6882*7836SJohn.Forte@Sun.COM 	fr_hdr->df_ctl = DF_CTL_NET_HDR;
6883*7836SJohn.Forte@Sun.COM 	fr_hdr->seq_cnt = 0;
6884*7836SJohn.Forte@Sun.COM 	fr_hdr->ox_id = 0xffff;
6885*7836SJohn.Forte@Sun.COM 	fr_hdr->rx_id = 0xffff;
6886*7836SJohn.Forte@Sun.COM 	fr_hdr->ro = 0;
6887*7836SJohn.Forte@Sun.COM 	/*
6888*7836SJohn.Forte@Sun.COM 	 * reset all the length fields
6889*7836SJohn.Forte@Sun.COM 	 */
6890*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_rsplen = 0;
6891*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_datalen = 0;
6892*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_comp = comp;
6893*7836SJohn.Forte@Sun.COM 	if (comp) {
6894*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_tran_flags |= FC_TRAN_INTR;
6895*7836SJohn.Forte@Sun.COM 	} else {
6896*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6897*7836SJohn.Forte@Sun.COM 	}
6898*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_type = FC_PKT_OUTBOUND | FC_PKT_IP_WRITE;
6899*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_timeout = fcip_pkt_ttl_ticks;
6900*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_ttl = fptr->fcip_timeout_ticks + fc_pkt->pkt_timeout;
6901*7836SJohn.Forte@Sun.COM }
6902*7836SJohn.Forte@Sun.COM 
6903*7836SJohn.Forte@Sun.COM 
6904*7836SJohn.Forte@Sun.COM /*
6905*7836SJohn.Forte@Sun.COM  * Initialize a fcip_packet for broadcast data transfers
6906*7836SJohn.Forte@Sun.COM  */
6907*7836SJohn.Forte@Sun.COM static void
fcip_init_broadcast_pkt(fcip_pkt_t * fcip_pkt,void (* comp)(),int is_els)6908*7836SJohn.Forte@Sun.COM fcip_init_broadcast_pkt(fcip_pkt_t *fcip_pkt, void (*comp) (), int is_els)
6909*7836SJohn.Forte@Sun.COM {
6910*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
6911*7836SJohn.Forte@Sun.COM 	fc_frame_hdr_t		*fr_hdr;
6912*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr = fcip_pkt->fcip_pkt_fptr;
6913*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
6914*7836SJohn.Forte@Sun.COM 	uint32_t		sid;
6915*7836SJohn.Forte@Sun.COM 	uint32_t		did;
6916*7836SJohn.Forte@Sun.COM 
6917*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_1((fcip_init_broadcast_pkt, "fcip io", /* CSTYLED */,
6918*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter"));
6919*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6920*7836SJohn.Forte@Sun.COM 	fr_hdr = &fc_pkt->pkt_cmd_fhdr;
6921*7836SJohn.Forte@Sun.COM 	sid = fport->fcipp_sid.port_id;
6922*7836SJohn.Forte@Sun.COM 
6923*7836SJohn.Forte@Sun.COM 	if (is_els) {
6924*7836SJohn.Forte@Sun.COM 		fr_hdr->r_ctl = R_CTL_ELS_REQ;
6925*7836SJohn.Forte@Sun.COM 	} else {
6926*7836SJohn.Forte@Sun.COM 		fr_hdr->r_ctl = R_CTL_DEVICE_DATA | R_CTL_UNSOL_DATA;
6927*7836SJohn.Forte@Sun.COM 	}
6928*7836SJohn.Forte@Sun.COM 	fr_hdr->s_id = sid;
6929*7836SJohn.Forte@Sun.COM 	/*
6930*7836SJohn.Forte@Sun.COM 	 * The destination broadcast address depends on the topology
6931*7836SJohn.Forte@Sun.COM 	 * of the underlying port
6932*7836SJohn.Forte@Sun.COM 	 */
6933*7836SJohn.Forte@Sun.COM 	did = fptr->fcip_broadcast_did;
6934*7836SJohn.Forte@Sun.COM 	/*
6935*7836SJohn.Forte@Sun.COM 	 * mark pkt a broadcast pkt
6936*7836SJohn.Forte@Sun.COM 	 */
6937*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_type = FC_PKT_BROADCAST;
6938*7836SJohn.Forte@Sun.COM 
6939*7836SJohn.Forte@Sun.COM 	fr_hdr->d_id = did;
6940*7836SJohn.Forte@Sun.COM 	fr_hdr->type = FC_TYPE_IS8802_SNAP;
6941*7836SJohn.Forte@Sun.COM 	fr_hdr->f_ctl = F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
6942*7836SJohn.Forte@Sun.COM 	fr_hdr->f_ctl &= ~(F_CTL_SEQ_INITIATIVE);
6943*7836SJohn.Forte@Sun.COM 	fr_hdr->df_ctl = DF_CTL_NET_HDR;
6944*7836SJohn.Forte@Sun.COM 	fr_hdr->seq_cnt = 0;
6945*7836SJohn.Forte@Sun.COM 	fr_hdr->ox_id = 0xffff;
6946*7836SJohn.Forte@Sun.COM 	fr_hdr->rx_id = 0xffff;
6947*7836SJohn.Forte@Sun.COM 	fr_hdr->ro = 0;
6948*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_comp = comp;
6949*7836SJohn.Forte@Sun.COM 
6950*7836SJohn.Forte@Sun.COM 	if (comp) {
6951*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_tran_flags |= FC_TRAN_INTR;
6952*7836SJohn.Forte@Sun.COM 	} else {
6953*7836SJohn.Forte@Sun.COM 		fc_pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6954*7836SJohn.Forte@Sun.COM 	}
6955*7836SJohn.Forte@Sun.COM 
6956*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_tran_type = FC_PKT_BROADCAST;
6957*7836SJohn.Forte@Sun.COM 	fc_pkt->pkt_timeout = fcip_pkt_ttl_ticks;
6958*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_ttl = fptr->fcip_timeout_ticks + fc_pkt->pkt_timeout;
6959*7836SJohn.Forte@Sun.COM }
6960*7836SJohn.Forte@Sun.COM 
6961*7836SJohn.Forte@Sun.COM 
6962*7836SJohn.Forte@Sun.COM 
6963*7836SJohn.Forte@Sun.COM /*
6964*7836SJohn.Forte@Sun.COM  * Free up all DMA resources associated with an allocated packet
6965*7836SJohn.Forte@Sun.COM  */
6966*7836SJohn.Forte@Sun.COM static void
fcip_free_pkt_dma(fcip_pkt_t * fcip_pkt)6967*7836SJohn.Forte@Sun.COM fcip_free_pkt_dma(fcip_pkt_t *fcip_pkt)
6968*7836SJohn.Forte@Sun.COM {
6969*7836SJohn.Forte@Sun.COM 	fc_packet_t	*fc_pkt;
6970*7836SJohn.Forte@Sun.COM 
6971*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
6972*7836SJohn.Forte@Sun.COM 
6973*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
6974*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "in freepktdma : flags 0x%x",
6975*7836SJohn.Forte@Sun.COM 	    fcip_pkt->fcip_pkt_dma_flags));
6976*7836SJohn.Forte@Sun.COM 
6977*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_dma_flags & FCIP_CMD_DMA_BOUND) {
6978*7836SJohn.Forte@Sun.COM 		(void) ddi_dma_unbind_handle(fc_pkt->pkt_cmd_dma);
6979*7836SJohn.Forte@Sun.COM 	}
6980*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_dma_flags & FCIP_CMD_DMA_MEM) {
6981*7836SJohn.Forte@Sun.COM 		ddi_dma_mem_free(&fc_pkt->pkt_cmd_acc);
6982*7836SJohn.Forte@Sun.COM 	}
6983*7836SJohn.Forte@Sun.COM 
6984*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_dma_flags & FCIP_RESP_DMA_BOUND) {
6985*7836SJohn.Forte@Sun.COM 		(void) ddi_dma_unbind_handle(fc_pkt->pkt_resp_dma);
6986*7836SJohn.Forte@Sun.COM 	}
6987*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_dma_flags & FCIP_RESP_DMA_MEM) {
6988*7836SJohn.Forte@Sun.COM 		ddi_dma_mem_free(&fc_pkt->pkt_resp_acc);
6989*7836SJohn.Forte@Sun.COM 	}
6990*7836SJohn.Forte@Sun.COM 	/*
6991*7836SJohn.Forte@Sun.COM 	 * for internal commands, we need to free up the dma handles too.
6992*7836SJohn.Forte@Sun.COM 	 * This is done in the cache destructor for non internal cmds
6993*7836SJohn.Forte@Sun.COM 	 */
6994*7836SJohn.Forte@Sun.COM 	if (fcip_pkt->fcip_pkt_flags & FCIP_PKT_INTERNAL) {
6995*7836SJohn.Forte@Sun.COM 		if (fc_pkt->pkt_cmd_dma) {
6996*7836SJohn.Forte@Sun.COM 			ddi_dma_free_handle(&fc_pkt->pkt_cmd_dma);
6997*7836SJohn.Forte@Sun.COM 		}
6998*7836SJohn.Forte@Sun.COM 		if (fc_pkt->pkt_resp_dma) {
6999*7836SJohn.Forte@Sun.COM 			ddi_dma_free_handle(&fc_pkt->pkt_resp_dma);
7000*7836SJohn.Forte@Sun.COM 		}
7001*7836SJohn.Forte@Sun.COM 	}
7002*7836SJohn.Forte@Sun.COM }
7003*7836SJohn.Forte@Sun.COM 
7004*7836SJohn.Forte@Sun.COM 
7005*7836SJohn.Forte@Sun.COM /*
7006*7836SJohn.Forte@Sun.COM  * helper routine to generate a string, given an ether addr
7007*7836SJohn.Forte@Sun.COM  */
7008*7836SJohn.Forte@Sun.COM static void
fcip_ether_to_str(struct ether_addr * e,caddr_t s)7009*7836SJohn.Forte@Sun.COM fcip_ether_to_str(struct ether_addr *e, caddr_t s)
7010*7836SJohn.Forte@Sun.COM {
7011*7836SJohn.Forte@Sun.COM 	int i;
7012*7836SJohn.Forte@Sun.COM 
7013*7836SJohn.Forte@Sun.COM 	for (i = 0; i < sizeof (struct ether_addr); i++, s += 2) {
7014*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_MISC,
7015*7836SJohn.Forte@Sun.COM 		    (CE_CONT, "0x%02X:", e->ether_addr_octet[i]));
7016*7836SJohn.Forte@Sun.COM 		(void) sprintf(s, "%02X", e->ether_addr_octet[i]);
7017*7836SJohn.Forte@Sun.COM 	}
7018*7836SJohn.Forte@Sun.COM 
7019*7836SJohn.Forte@Sun.COM 	*s = '\0';
7020*7836SJohn.Forte@Sun.COM }
7021*7836SJohn.Forte@Sun.COM 
7022*7836SJohn.Forte@Sun.COM /*
7023*7836SJohn.Forte@Sun.COM  * When a broadcast request comes from the upper streams modules, it
7024*7836SJohn.Forte@Sun.COM  * is ugly to look into every datagram to figure out if it is a broadcast
7025*7836SJohn.Forte@Sun.COM  * datagram or a unicast packet. Instead just add the broadcast entries
7026*7836SJohn.Forte@Sun.COM  * into our routing and dest tables and the standard hash table look ups
7027*7836SJohn.Forte@Sun.COM  * will find the entries. It is a lot cleaner this way. Also Solaris ifconfig
7028*7836SJohn.Forte@Sun.COM  * seems to be very ethernet specific and it requires broadcasts to the
7029*7836SJohn.Forte@Sun.COM  * ether broadcast addr of 0xffffffffff to succeed even though we specified
7030*7836SJohn.Forte@Sun.COM  * in the dl_info request that our broadcast MAC addr is 0x0000000000
7031*7836SJohn.Forte@Sun.COM  * (can't figure out why RFC2625 did this though). So add broadcast entries
7032*7836SJohn.Forte@Sun.COM  * for both MAC address
7033*7836SJohn.Forte@Sun.COM  */
7034*7836SJohn.Forte@Sun.COM static int
fcip_dest_add_broadcast_entry(struct fcip * fptr,int new_flag)7035*7836SJohn.Forte@Sun.COM fcip_dest_add_broadcast_entry(struct fcip *fptr, int new_flag)
7036*7836SJohn.Forte@Sun.COM {
7037*7836SJohn.Forte@Sun.COM 	fc_portmap_t 		map;
7038*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table *frp;
7039*7836SJohn.Forte@Sun.COM 	uint32_t		did;
7040*7836SJohn.Forte@Sun.COM 	la_wwn_t		broadcast_wwn;
7041*7836SJohn.Forte@Sun.COM 
7042*7836SJohn.Forte@Sun.COM 	/*
7043*7836SJohn.Forte@Sun.COM 	 * get port_id of destination for broadcast - this is topology
7044*7836SJohn.Forte@Sun.COM 	 * dependent
7045*7836SJohn.Forte@Sun.COM 	 */
7046*7836SJohn.Forte@Sun.COM 	did = fptr->fcip_broadcast_did;
7047*7836SJohn.Forte@Sun.COM 
7048*7836SJohn.Forte@Sun.COM 	ether_to_wwn(&fcip_arpbroadcast_addr, &broadcast_wwn);
7049*7836SJohn.Forte@Sun.COM 	bcopy((void *)&broadcast_wwn, (void *)&map.map_pwwn, sizeof (la_wwn_t));
7050*7836SJohn.Forte@Sun.COM 	bcopy((void *)&broadcast_wwn, (void *)&map.map_nwwn, sizeof (la_wwn_t));
7051*7836SJohn.Forte@Sun.COM 
7052*7836SJohn.Forte@Sun.COM 	map.map_did.port_id = did;
7053*7836SJohn.Forte@Sun.COM 	map.map_hard_addr.hard_addr = did;
7054*7836SJohn.Forte@Sun.COM 	map.map_state = PORT_DEVICE_VALID;
7055*7836SJohn.Forte@Sun.COM 	if (new_flag) {
7056*7836SJohn.Forte@Sun.COM 		map.map_type = PORT_DEVICE_NEW;
7057*7836SJohn.Forte@Sun.COM 	} else {
7058*7836SJohn.Forte@Sun.COM 		map.map_type = PORT_DEVICE_CHANGED;
7059*7836SJohn.Forte@Sun.COM 	}
7060*7836SJohn.Forte@Sun.COM 	map.map_flags = 0;
7061*7836SJohn.Forte@Sun.COM 	map.map_pd = NULL;
7062*7836SJohn.Forte@Sun.COM 	bzero(&map.map_fc4_types, sizeof (map.map_fc4_types));
7063*7836SJohn.Forte@Sun.COM 	fcip_rt_update(fptr, &map, 1);
7064*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
7065*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, &broadcast_wwn, FCIP_COMPARE_NWWN);
7066*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
7067*7836SJohn.Forte@Sun.COM 	if (frp == NULL) {
7068*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
7069*7836SJohn.Forte@Sun.COM 	}
7070*7836SJohn.Forte@Sun.COM 	(void) fcip_add_dest(fptr, frp);
7071*7836SJohn.Forte@Sun.COM 	/*
7072*7836SJohn.Forte@Sun.COM 	 * The Upper IP layers expect the traditional broadcast MAC addr
7073*7836SJohn.Forte@Sun.COM 	 * of 0xff ff ff ff ff ff to work too if we want to plumb the fcip
7074*7836SJohn.Forte@Sun.COM 	 * stream through the /etc/hostname.fcipXX file. Instead of checking
7075*7836SJohn.Forte@Sun.COM 	 * each phys addr for a match with fcip's ARP header broadcast
7076*7836SJohn.Forte@Sun.COM 	 * addr (0x00 00 00 00 00 00), its simply easier to add another
7077*7836SJohn.Forte@Sun.COM 	 * broadcast entry for 0xff ff ff ff ff ff.
7078*7836SJohn.Forte@Sun.COM 	 */
7079*7836SJohn.Forte@Sun.COM 	ether_to_wwn(&fcipnhbroadcastaddr, &broadcast_wwn);
7080*7836SJohn.Forte@Sun.COM 	bcopy((void *)&broadcast_wwn, (void *)&map.map_pwwn, sizeof (la_wwn_t));
7081*7836SJohn.Forte@Sun.COM 	bcopy((void *)&broadcast_wwn, (void *)&map.map_nwwn, sizeof (la_wwn_t));
7082*7836SJohn.Forte@Sun.COM 	fcip_rt_update(fptr, &map, 1);
7083*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
7084*7836SJohn.Forte@Sun.COM 	frp = fcip_lookup_rtable(fptr, &broadcast_wwn, FCIP_COMPARE_NWWN);
7085*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
7086*7836SJohn.Forte@Sun.COM 	if (frp == NULL) {
7087*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
7088*7836SJohn.Forte@Sun.COM 	}
7089*7836SJohn.Forte@Sun.COM 	(void) fcip_add_dest(fptr, frp);
7090*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
7091*7836SJohn.Forte@Sun.COM }
7092*7836SJohn.Forte@Sun.COM 
7093*7836SJohn.Forte@Sun.COM /*
7094*7836SJohn.Forte@Sun.COM  * We need to obtain the D_ID of the broadcast port for transmitting all
7095*7836SJohn.Forte@Sun.COM  * our broadcast (and multicast) requests. The broadcast D_ID as we know
7096*7836SJohn.Forte@Sun.COM  * is dependent on the link topology
7097*7836SJohn.Forte@Sun.COM  */
7098*7836SJohn.Forte@Sun.COM static uint32_t
fcip_get_broadcast_did(struct fcip * fptr)7099*7836SJohn.Forte@Sun.COM fcip_get_broadcast_did(struct fcip *fptr)
7100*7836SJohn.Forte@Sun.COM {
7101*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = fptr->fcip_port_info;
7102*7836SJohn.Forte@Sun.COM 	uint32_t		did = 0;
7103*7836SJohn.Forte@Sun.COM 	uint32_t		sid;
7104*7836SJohn.Forte@Sun.COM 
7105*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_get_broadcast_did, "fcip io", /* CSTYLED */,
7106*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "enter",
7107*7836SJohn.Forte@Sun.COM 		tnf_opaque, fptr, fptr));
7108*7836SJohn.Forte@Sun.COM 
7109*7836SJohn.Forte@Sun.COM 	sid = fport->fcipp_sid.port_id;
7110*7836SJohn.Forte@Sun.COM 
7111*7836SJohn.Forte@Sun.COM 	switch (fport->fcipp_topology) {
7112*7836SJohn.Forte@Sun.COM 
7113*7836SJohn.Forte@Sun.COM 	case FC_TOP_PT_PT: {
7114*7836SJohn.Forte@Sun.COM 		fc_portmap_t	*port_map = NULL;
7115*7836SJohn.Forte@Sun.COM 		uint32_t	listlen = 0;
7116*7836SJohn.Forte@Sun.COM 
7117*7836SJohn.Forte@Sun.COM 		if (fc_ulp_getportmap(fport->fcipp_handle, &port_map,
7118*7836SJohn.Forte@Sun.COM 		    &listlen, FC_ULP_PLOGI_DONTCARE) == FC_SUCCESS) {
7119*7836SJohn.Forte@Sun.COM 			FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_NOTE,
7120*7836SJohn.Forte@Sun.COM 			    "fcip_gpmap: listlen :  0x%x", listlen));
7121*7836SJohn.Forte@Sun.COM 			if (listlen == 1) {
7122*7836SJohn.Forte@Sun.COM 				did = port_map->map_did.port_id;
7123*7836SJohn.Forte@Sun.COM 			}
7124*7836SJohn.Forte@Sun.COM 		}
7125*7836SJohn.Forte@Sun.COM 		if (port_map) {
7126*7836SJohn.Forte@Sun.COM 			kmem_free(port_map, listlen * sizeof (fc_portmap_t));
7127*7836SJohn.Forte@Sun.COM 		}
7128*7836SJohn.Forte@Sun.COM 		if (listlen != 1) {
7129*7836SJohn.Forte@Sun.COM 			/* Dummy return value */
7130*7836SJohn.Forte@Sun.COM 			return (0x00FFFFFF);
7131*7836SJohn.Forte@Sun.COM 		}
7132*7836SJohn.Forte@Sun.COM 		break;
7133*7836SJohn.Forte@Sun.COM 	}
7134*7836SJohn.Forte@Sun.COM 
7135*7836SJohn.Forte@Sun.COM 	case FC_TOP_NO_NS:
7136*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
7137*7836SJohn.Forte@Sun.COM 	case FC_TOP_FABRIC:
7138*7836SJohn.Forte@Sun.COM 		/*
7139*7836SJohn.Forte@Sun.COM 		 * The broadcast address is the same whether or not
7140*7836SJohn.Forte@Sun.COM 		 * the switch/fabric contains a Name service.
7141*7836SJohn.Forte@Sun.COM 		 */
7142*7836SJohn.Forte@Sun.COM 		did = 0x00FFFFFF;
7143*7836SJohn.Forte@Sun.COM 		break;
7144*7836SJohn.Forte@Sun.COM 
7145*7836SJohn.Forte@Sun.COM 	case FC_TOP_PUBLIC_LOOP:
7146*7836SJohn.Forte@Sun.COM 		/*
7147*7836SJohn.Forte@Sun.COM 		 * The open replicate primitive must not be used. The
7148*7836SJohn.Forte@Sun.COM 		 * broadcast sequence is simply sent to ALPA 0x00. The
7149*7836SJohn.Forte@Sun.COM 		 * fabric controller then propagates the broadcast to all
7150*7836SJohn.Forte@Sun.COM 		 * other ports. The fabric propagates the broadcast by
7151*7836SJohn.Forte@Sun.COM 		 * using the OPNfr primitive.
7152*7836SJohn.Forte@Sun.COM 		 */
7153*7836SJohn.Forte@Sun.COM 		did = 0x00;
7154*7836SJohn.Forte@Sun.COM 		break;
7155*7836SJohn.Forte@Sun.COM 
7156*7836SJohn.Forte@Sun.COM 	case FC_TOP_PRIVATE_LOOP:
7157*7836SJohn.Forte@Sun.COM 		/*
7158*7836SJohn.Forte@Sun.COM 		 * The source port for broadcast in private loop mode
7159*7836SJohn.Forte@Sun.COM 		 * must send an OPN(fr) signal forcing all ports in the
7160*7836SJohn.Forte@Sun.COM 		 * loop to replicate the frames that they receive.
7161*7836SJohn.Forte@Sun.COM 		 */
7162*7836SJohn.Forte@Sun.COM 		did = 0x00FFFFFF;
7163*7836SJohn.Forte@Sun.COM 		break;
7164*7836SJohn.Forte@Sun.COM 
7165*7836SJohn.Forte@Sun.COM 	case FC_TOP_UNKNOWN:
7166*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
7167*7836SJohn.Forte@Sun.COM 	default:
7168*7836SJohn.Forte@Sun.COM 		did = sid;
7169*7836SJohn.Forte@Sun.COM 		FCIP_DEBUG(FCIP_DEBUG_INIT, (CE_WARN,
7170*7836SJohn.Forte@Sun.COM 		    "fcip(0x%x):unknown topology in init_broadcast_pkt",
7171*7836SJohn.Forte@Sun.COM 		    fptr->fcip_instance));
7172*7836SJohn.Forte@Sun.COM 		break;
7173*7836SJohn.Forte@Sun.COM 	}
7174*7836SJohn.Forte@Sun.COM 	FCIP_TNF_PROBE_2((fcip_get_broadcast_did, "fcip io", /* CSTYLED */,
7175*7836SJohn.Forte@Sun.COM 		tnf_string, msg, "return",
7176*7836SJohn.Forte@Sun.COM 		tnf_opaque, did, did));
7177*7836SJohn.Forte@Sun.COM 
7178*7836SJohn.Forte@Sun.COM 	return (did);
7179*7836SJohn.Forte@Sun.COM }
7180*7836SJohn.Forte@Sun.COM 
7181*7836SJohn.Forte@Sun.COM 
7182*7836SJohn.Forte@Sun.COM /*
7183*7836SJohn.Forte@Sun.COM  * fcip timeout performs 2 operations:
7184*7836SJohn.Forte@Sun.COM  * 1. timeout any packets sent to the FCA for which a callback hasn't
7185*7836SJohn.Forte@Sun.COM  *    happened. If you are wondering why we need a callback since all
7186*7836SJohn.Forte@Sun.COM  *    traffic in FCIP is unidirectional, hence all exchanges are unidirectional
7187*7836SJohn.Forte@Sun.COM  *    but wait, we can only free up the resources after we know the FCA has
7188*7836SJohn.Forte@Sun.COM  *    DMA'ed out the data. pretty obvious eh :)
7189*7836SJohn.Forte@Sun.COM  *
7190*7836SJohn.Forte@Sun.COM  * 2. Retire and routing table entries we marked up for retiring. This is
7191*7836SJohn.Forte@Sun.COM  *    to give the link a chance to recover instead of marking a port down
7192*7836SJohn.Forte@Sun.COM  *    when we have lost all communication with it after a link transition
7193*7836SJohn.Forte@Sun.COM  */
7194*7836SJohn.Forte@Sun.COM static void
fcip_timeout(void * arg)7195*7836SJohn.Forte@Sun.COM fcip_timeout(void *arg)
7196*7836SJohn.Forte@Sun.COM {
7197*7836SJohn.Forte@Sun.COM 	struct fcip 			*fptr = (struct fcip *)arg;
7198*7836SJohn.Forte@Sun.COM 	int				i;
7199*7836SJohn.Forte@Sun.COM 	fcip_pkt_t			*fcip_pkt;
7200*7836SJohn.Forte@Sun.COM 	struct fcip_dest		*fdestp;
7201*7836SJohn.Forte@Sun.COM 	int 				index;
7202*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table 	*frtp;
7203*7836SJohn.Forte@Sun.COM 	int				dispatch_rte_removal = 0;
7204*7836SJohn.Forte@Sun.COM 
7205*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
7206*7836SJohn.Forte@Sun.COM 
7207*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags |= FCIP_IN_TIMEOUT;
7208*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_ticks += fcip_tick_incr;
7209*7836SJohn.Forte@Sun.COM 
7210*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_flags & (FCIP_DETACHED | FCIP_DETACHING | \
7211*7836SJohn.Forte@Sun.COM 	    FCIP_SUSPENDED | FCIP_POWER_DOWN)) {
7212*7836SJohn.Forte@Sun.COM 		fptr->fcip_flags &= ~(FCIP_IN_TIMEOUT);
7213*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_mutex);
7214*7836SJohn.Forte@Sun.COM 		return;
7215*7836SJohn.Forte@Sun.COM 	}
7216*7836SJohn.Forte@Sun.COM 
7217*7836SJohn.Forte@Sun.COM 	if (fptr->fcip_port_state == FCIP_PORT_OFFLINE) {
7218*7836SJohn.Forte@Sun.COM 		if (fptr->fcip_timeout_ticks > fptr->fcip_mark_offline) {
7219*7836SJohn.Forte@Sun.COM 			fptr->fcip_flags |= FCIP_LINK_DOWN;
7220*7836SJohn.Forte@Sun.COM 		}
7221*7836SJohn.Forte@Sun.COM 	}
7222*7836SJohn.Forte@Sun.COM 	if (!fptr->fcip_flags & FCIP_RTE_REMOVING) {
7223*7836SJohn.Forte@Sun.COM 		dispatch_rte_removal = 1;
7224*7836SJohn.Forte@Sun.COM 	}
7225*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
7226*7836SJohn.Forte@Sun.COM 
7227*7836SJohn.Forte@Sun.COM 	/*
7228*7836SJohn.Forte@Sun.COM 	 * Check if we have any Invalid routing table entries in our
7229*7836SJohn.Forte@Sun.COM 	 * hashtable we have marked off for deferred removal. If any,
7230*7836SJohn.Forte@Sun.COM 	 * we can spawn a taskq thread to do the cleanup for us. We
7231*7836SJohn.Forte@Sun.COM 	 * need to avoid cleanup in the timeout thread since we may
7232*7836SJohn.Forte@Sun.COM 	 * have to wait for outstanding commands to complete before
7233*7836SJohn.Forte@Sun.COM 	 * we retire a routing table entry. Also dispatch the taskq
7234*7836SJohn.Forte@Sun.COM 	 * thread only if we are already do not have a taskq thread
7235*7836SJohn.Forte@Sun.COM 	 * dispatched.
7236*7836SJohn.Forte@Sun.COM 	 */
7237*7836SJohn.Forte@Sun.COM 	if (dispatch_rte_removal) {
7238*7836SJohn.Forte@Sun.COM 		mutex_enter(&fptr->fcip_rt_mutex);
7239*7836SJohn.Forte@Sun.COM 		for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
7240*7836SJohn.Forte@Sun.COM 			frtp = fptr->fcip_rtable[index];
7241*7836SJohn.Forte@Sun.COM 			while (frtp) {
7242*7836SJohn.Forte@Sun.COM 				if ((frtp->fcipr_state == FCIP_RT_INVALID) &&
7243*7836SJohn.Forte@Sun.COM 				    (fptr->fcip_timeout_ticks >
7244*7836SJohn.Forte@Sun.COM 				    frtp->fcipr_invalid_timeout)) {
7245*7836SJohn.Forte@Sun.COM 					/*
7246*7836SJohn.Forte@Sun.COM 					 * If we cannot schedule a task thread
7247*7836SJohn.Forte@Sun.COM 					 * let us attempt again on the next
7248*7836SJohn.Forte@Sun.COM 					 * tick rather than call
7249*7836SJohn.Forte@Sun.COM 					 * fcip_rte_remove_deferred() from here
7250*7836SJohn.Forte@Sun.COM 					 * directly since the routine can sleep.
7251*7836SJohn.Forte@Sun.COM 					 */
7252*7836SJohn.Forte@Sun.COM 					frtp->fcipr_state = FCIP_RT_RETIRED;
7253*7836SJohn.Forte@Sun.COM 
7254*7836SJohn.Forte@Sun.COM 					mutex_enter(&fptr->fcip_mutex);
7255*7836SJohn.Forte@Sun.COM 					fptr->fcip_flags |= FCIP_RTE_REMOVING;
7256*7836SJohn.Forte@Sun.COM 					mutex_exit(&fptr->fcip_mutex);
7257*7836SJohn.Forte@Sun.COM 
7258*7836SJohn.Forte@Sun.COM 					if (taskq_dispatch(fptr->fcip_tq,
7259*7836SJohn.Forte@Sun.COM 					    fcip_rte_remove_deferred, fptr,
7260*7836SJohn.Forte@Sun.COM 					    KM_NOSLEEP) == 0) {
7261*7836SJohn.Forte@Sun.COM 						/*
7262*7836SJohn.Forte@Sun.COM 						 * failed - so mark the entry
7263*7836SJohn.Forte@Sun.COM 						 * as invalid again.
7264*7836SJohn.Forte@Sun.COM 						 */
7265*7836SJohn.Forte@Sun.COM 						frtp->fcipr_state =
7266*7836SJohn.Forte@Sun.COM 						    FCIP_RT_INVALID;
7267*7836SJohn.Forte@Sun.COM 
7268*7836SJohn.Forte@Sun.COM 						mutex_enter(&fptr->fcip_mutex);
7269*7836SJohn.Forte@Sun.COM 						fptr->fcip_flags &=
7270*7836SJohn.Forte@Sun.COM 						    ~FCIP_RTE_REMOVING;
7271*7836SJohn.Forte@Sun.COM 						mutex_exit(&fptr->fcip_mutex);
7272*7836SJohn.Forte@Sun.COM 					}
7273*7836SJohn.Forte@Sun.COM 				}
7274*7836SJohn.Forte@Sun.COM 				frtp = frtp->fcipr_next;
7275*7836SJohn.Forte@Sun.COM 			}
7276*7836SJohn.Forte@Sun.COM 		}
7277*7836SJohn.Forte@Sun.COM 		mutex_exit(&fptr->fcip_rt_mutex);
7278*7836SJohn.Forte@Sun.COM 	}
7279*7836SJohn.Forte@Sun.COM 
7280*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_dest_mutex);
7281*7836SJohn.Forte@Sun.COM 
7282*7836SJohn.Forte@Sun.COM 	/*
7283*7836SJohn.Forte@Sun.COM 	 * Now timeout any packets stuck with the transport/FCA for too long
7284*7836SJohn.Forte@Sun.COM 	 */
7285*7836SJohn.Forte@Sun.COM 	for (i = 0; i < FCIP_DEST_HASH_ELEMS; i++) {
7286*7836SJohn.Forte@Sun.COM 		fdestp = fptr->fcip_dest[i];
7287*7836SJohn.Forte@Sun.COM 		while (fdestp != NULL) {
7288*7836SJohn.Forte@Sun.COM 			mutex_enter(&fdestp->fcipd_mutex);
7289*7836SJohn.Forte@Sun.COM 			for (fcip_pkt = fdestp->fcipd_head; fcip_pkt != NULL;
7290*7836SJohn.Forte@Sun.COM 			    fcip_pkt = fcip_pkt->fcip_pkt_next) {
7291*7836SJohn.Forte@Sun.COM 				if (fcip_pkt->fcip_pkt_flags &
7292*7836SJohn.Forte@Sun.COM 				    (FCIP_PKT_RETURNED | FCIP_PKT_IN_TIMEOUT |
7293*7836SJohn.Forte@Sun.COM 				    FCIP_PKT_IN_ABORT)) {
7294*7836SJohn.Forte@Sun.COM 					continue;
7295*7836SJohn.Forte@Sun.COM 				}
7296*7836SJohn.Forte@Sun.COM 				if (fptr->fcip_timeout_ticks >
7297*7836SJohn.Forte@Sun.COM 				    fcip_pkt->fcip_pkt_ttl) {
7298*7836SJohn.Forte@Sun.COM 					fcip_pkt->fcip_pkt_flags |=
7299*7836SJohn.Forte@Sun.COM 					    FCIP_PKT_IN_TIMEOUT;
7300*7836SJohn.Forte@Sun.COM 
7301*7836SJohn.Forte@Sun.COM 					mutex_exit(&fdestp->fcipd_mutex);
7302*7836SJohn.Forte@Sun.COM 					if (taskq_dispatch(fptr->fcip_tq,
7303*7836SJohn.Forte@Sun.COM 					    fcip_pkt_timeout, fcip_pkt,
7304*7836SJohn.Forte@Sun.COM 					    KM_NOSLEEP) == 0) {
7305*7836SJohn.Forte@Sun.COM 						/*
7306*7836SJohn.Forte@Sun.COM 						 * timeout immediately
7307*7836SJohn.Forte@Sun.COM 						 */
7308*7836SJohn.Forte@Sun.COM 						fcip_pkt_timeout(fcip_pkt);
7309*7836SJohn.Forte@Sun.COM 					}
7310*7836SJohn.Forte@Sun.COM 					mutex_enter(&fdestp->fcipd_mutex);
7311*7836SJohn.Forte@Sun.COM 					/*
7312*7836SJohn.Forte@Sun.COM 					 * The linked list is altered because
7313*7836SJohn.Forte@Sun.COM 					 * of one of the following reasons:
7314*7836SJohn.Forte@Sun.COM 					 *	a. Timeout code dequeued a pkt
7315*7836SJohn.Forte@Sun.COM 					 *	b. Pkt completion happened
7316*7836SJohn.Forte@Sun.COM 					 *
7317*7836SJohn.Forte@Sun.COM 					 * So restart the spin starting at
7318*7836SJohn.Forte@Sun.COM 					 * the head again; This is a bit
7319*7836SJohn.Forte@Sun.COM 					 * excessive, but okay since
7320*7836SJohn.Forte@Sun.COM 					 * fcip_timeout_ticks isn't incremented
7321*7836SJohn.Forte@Sun.COM 					 * for this spin, we will skip the
7322*7836SJohn.Forte@Sun.COM 					 * not-to-be-timedout packets quickly
7323*7836SJohn.Forte@Sun.COM 					 */
7324*7836SJohn.Forte@Sun.COM 					fcip_pkt = fdestp->fcipd_head;
7325*7836SJohn.Forte@Sun.COM 					if (fcip_pkt == NULL) {
7326*7836SJohn.Forte@Sun.COM 						break;
7327*7836SJohn.Forte@Sun.COM 					}
7328*7836SJohn.Forte@Sun.COM 				}
7329*7836SJohn.Forte@Sun.COM 			}
7330*7836SJohn.Forte@Sun.COM 			mutex_exit(&fdestp->fcipd_mutex);
7331*7836SJohn.Forte@Sun.COM 			fdestp = fdestp->fcipd_next;
7332*7836SJohn.Forte@Sun.COM 		}
7333*7836SJohn.Forte@Sun.COM 	}
7334*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_dest_mutex);
7335*7836SJohn.Forte@Sun.COM 
7336*7836SJohn.Forte@Sun.COM 	/*
7337*7836SJohn.Forte@Sun.COM 	 * reschedule the timeout thread
7338*7836SJohn.Forte@Sun.COM 	 */
7339*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
7340*7836SJohn.Forte@Sun.COM 
7341*7836SJohn.Forte@Sun.COM 	fptr->fcip_timeout_id = timeout(fcip_timeout, fptr,
7342*7836SJohn.Forte@Sun.COM 	    drv_usectohz(1000000));
7343*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~(FCIP_IN_TIMEOUT);
7344*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
7345*7836SJohn.Forte@Sun.COM }
7346*7836SJohn.Forte@Sun.COM 
7347*7836SJohn.Forte@Sun.COM 
7348*7836SJohn.Forte@Sun.COM /*
7349*7836SJohn.Forte@Sun.COM  * This routine is either called from taskq or directly from fcip_timeout
7350*7836SJohn.Forte@Sun.COM  * does the actual job of aborting the packet
7351*7836SJohn.Forte@Sun.COM  */
7352*7836SJohn.Forte@Sun.COM static void
fcip_pkt_timeout(void * arg)7353*7836SJohn.Forte@Sun.COM fcip_pkt_timeout(void *arg)
7354*7836SJohn.Forte@Sun.COM {
7355*7836SJohn.Forte@Sun.COM 	fcip_pkt_t		*fcip_pkt = (fcip_pkt_t *)arg;
7356*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp;
7357*7836SJohn.Forte@Sun.COM 	struct fcip		*fptr;
7358*7836SJohn.Forte@Sun.COM 	fc_packet_t		*fc_pkt;
7359*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
7360*7836SJohn.Forte@Sun.COM 	int			rval;
7361*7836SJohn.Forte@Sun.COM 
7362*7836SJohn.Forte@Sun.COM 	fdestp = fcip_pkt->fcip_pkt_dest;
7363*7836SJohn.Forte@Sun.COM 	fptr = fcip_pkt->fcip_pkt_fptr;
7364*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
7365*7836SJohn.Forte@Sun.COM 	fc_pkt = FCIP_PKT_TO_FC_PKT(fcip_pkt);
7366*7836SJohn.Forte@Sun.COM 
7367*7836SJohn.Forte@Sun.COM 	/*
7368*7836SJohn.Forte@Sun.COM 	 * try to abort the pkt
7369*7836SJohn.Forte@Sun.COM 	 */
7370*7836SJohn.Forte@Sun.COM 	fcip_pkt->fcip_pkt_flags |= FCIP_PKT_IN_ABORT;
7371*7836SJohn.Forte@Sun.COM 	rval = fc_ulp_abort(fport->fcipp_handle, fc_pkt, KM_NOSLEEP);
7372*7836SJohn.Forte@Sun.COM 
7373*7836SJohn.Forte@Sun.COM 	FCIP_DEBUG(FCIP_DEBUG_DOWNSTREAM,
7374*7836SJohn.Forte@Sun.COM 	    (CE_NOTE, "fc_ulp_abort returns: 0x%x", rval));
7375*7836SJohn.Forte@Sun.COM 
7376*7836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
7377*7836SJohn.Forte@Sun.COM 		ASSERT(fdestp != NULL);
7378*7836SJohn.Forte@Sun.COM 
7379*7836SJohn.Forte@Sun.COM 		/*
7380*7836SJohn.Forte@Sun.COM 		 * dequeue the pkt from the dest structure pkt list
7381*7836SJohn.Forte@Sun.COM 		 */
7382*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_ABORT;
7383*7836SJohn.Forte@Sun.COM 		mutex_enter(&fdestp->fcipd_mutex);
7384*7836SJohn.Forte@Sun.COM 		rval = fcip_fdestp_dequeue_pkt(fdestp, fcip_pkt);
7385*7836SJohn.Forte@Sun.COM 		ASSERT(rval == 1);
7386*7836SJohn.Forte@Sun.COM 		mutex_exit(&fdestp->fcipd_mutex);
7387*7836SJohn.Forte@Sun.COM 
7388*7836SJohn.Forte@Sun.COM 		/*
7389*7836SJohn.Forte@Sun.COM 		 * Now cleanup the pkt and free the mblk
7390*7836SJohn.Forte@Sun.COM 		 */
7391*7836SJohn.Forte@Sun.COM 		fcip_pkt_free(fcip_pkt, 1);
7392*7836SJohn.Forte@Sun.COM 	} else {
7393*7836SJohn.Forte@Sun.COM 		/*
7394*7836SJohn.Forte@Sun.COM 		 * abort failed - just mark the pkt as done and
7395*7836SJohn.Forte@Sun.COM 		 * wait for it to complete in fcip_pkt_callback since
7396*7836SJohn.Forte@Sun.COM 		 * the pkt has already been xmitted by the FCA
7397*7836SJohn.Forte@Sun.COM 		 */
7398*7836SJohn.Forte@Sun.COM 		fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_TIMEOUT;
7399*7836SJohn.Forte@Sun.COM 		if (fcip_pkt->fcip_pkt_flags & FCIP_PKT_RETURNED) {
7400*7836SJohn.Forte@Sun.COM 			fcip_pkt->fcip_pkt_flags &= ~FCIP_PKT_IN_ABORT;
7401*7836SJohn.Forte@Sun.COM 			mutex_enter(&fdestp->fcipd_mutex);
7402*7836SJohn.Forte@Sun.COM 			rval = fcip_fdestp_dequeue_pkt(fdestp, fcip_pkt);
7403*7836SJohn.Forte@Sun.COM 			ASSERT(rval == 1);
7404*7836SJohn.Forte@Sun.COM 			mutex_exit(&fdestp->fcipd_mutex);
7405*7836SJohn.Forte@Sun.COM 
7406*7836SJohn.Forte@Sun.COM 			fcip_pkt_free(fcip_pkt, 1);
7407*7836SJohn.Forte@Sun.COM 		}
7408*7836SJohn.Forte@Sun.COM 		return;
7409*7836SJohn.Forte@Sun.COM 	}
7410*7836SJohn.Forte@Sun.COM }
7411*7836SJohn.Forte@Sun.COM 
7412*7836SJohn.Forte@Sun.COM 
7413*7836SJohn.Forte@Sun.COM /*
7414*7836SJohn.Forte@Sun.COM  * Remove  a routing table entry marked for deferred removal. This routine
7415*7836SJohn.Forte@Sun.COM  * unlike fcip_pkt_timeout, is always called from a taskq context
7416*7836SJohn.Forte@Sun.COM  */
7417*7836SJohn.Forte@Sun.COM static void
fcip_rte_remove_deferred(void * arg)7418*7836SJohn.Forte@Sun.COM fcip_rte_remove_deferred(void *arg)
7419*7836SJohn.Forte@Sun.COM {
7420*7836SJohn.Forte@Sun.COM 	struct fcip 			*fptr = (struct fcip *)arg;
7421*7836SJohn.Forte@Sun.COM 	int				hash_bucket;
7422*7836SJohn.Forte@Sun.COM 	struct fcip_dest 		*fdestp;
7423*7836SJohn.Forte@Sun.COM 	la_wwn_t			*pwwn;
7424*7836SJohn.Forte@Sun.COM 	int 				index;
7425*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table 	*frtp, *frtp_next, *frtp_prev;
7426*7836SJohn.Forte@Sun.COM 
7427*7836SJohn.Forte@Sun.COM 
7428*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_rt_mutex);
7429*7836SJohn.Forte@Sun.COM 	for (index = 0; index < FCIP_RT_HASH_ELEMS; index++) {
7430*7836SJohn.Forte@Sun.COM 		frtp = fptr->fcip_rtable[index];
7431*7836SJohn.Forte@Sun.COM 		frtp_prev = NULL;
7432*7836SJohn.Forte@Sun.COM 		while (frtp) {
7433*7836SJohn.Forte@Sun.COM 			frtp_next = frtp->fcipr_next;
7434*7836SJohn.Forte@Sun.COM 
7435*7836SJohn.Forte@Sun.COM 			if (frtp->fcipr_state == FCIP_RT_RETIRED) {
7436*7836SJohn.Forte@Sun.COM 
7437*7836SJohn.Forte@Sun.COM 				pwwn = &frtp->fcipr_pwwn;
7438*7836SJohn.Forte@Sun.COM 				/*
7439*7836SJohn.Forte@Sun.COM 				 * Get hold of destination pointer
7440*7836SJohn.Forte@Sun.COM 				 */
7441*7836SJohn.Forte@Sun.COM 				mutex_enter(&fptr->fcip_dest_mutex);
7442*7836SJohn.Forte@Sun.COM 
7443*7836SJohn.Forte@Sun.COM 				hash_bucket = FCIP_DEST_HASH(pwwn->raw_wwn);
7444*7836SJohn.Forte@Sun.COM 				ASSERT(hash_bucket < FCIP_DEST_HASH_ELEMS);
7445*7836SJohn.Forte@Sun.COM 
7446*7836SJohn.Forte@Sun.COM 				fdestp = fptr->fcip_dest[hash_bucket];
7447*7836SJohn.Forte@Sun.COM 				while (fdestp != NULL) {
7448*7836SJohn.Forte@Sun.COM 					mutex_enter(&fdestp->fcipd_mutex);
7449*7836SJohn.Forte@Sun.COM 					if (fdestp->fcipd_rtable) {
7450*7836SJohn.Forte@Sun.COM 						if (fcip_wwn_compare(pwwn,
7451*7836SJohn.Forte@Sun.COM 						    &fdestp->fcipd_pwwn,
7452*7836SJohn.Forte@Sun.COM 						    FCIP_COMPARE_PWWN) == 0) {
7453*7836SJohn.Forte@Sun.COM 							mutex_exit(
7454*7836SJohn.Forte@Sun.COM 							&fdestp->fcipd_mutex);
7455*7836SJohn.Forte@Sun.COM 							break;
7456*7836SJohn.Forte@Sun.COM 						}
7457*7836SJohn.Forte@Sun.COM 					}
7458*7836SJohn.Forte@Sun.COM 					mutex_exit(&fdestp->fcipd_mutex);
7459*7836SJohn.Forte@Sun.COM 					fdestp = fdestp->fcipd_next;
7460*7836SJohn.Forte@Sun.COM 				}
7461*7836SJohn.Forte@Sun.COM 
7462*7836SJohn.Forte@Sun.COM 				mutex_exit(&fptr->fcip_dest_mutex);
7463*7836SJohn.Forte@Sun.COM 				if (fdestp == NULL) {
7464*7836SJohn.Forte@Sun.COM 					frtp_prev = frtp;
7465*7836SJohn.Forte@Sun.COM 					frtp = frtp_next;
7466*7836SJohn.Forte@Sun.COM 					continue;
7467*7836SJohn.Forte@Sun.COM 				}
7468*7836SJohn.Forte@Sun.COM 
7469*7836SJohn.Forte@Sun.COM 				mutex_enter(&fdestp->fcipd_mutex);
7470*7836SJohn.Forte@Sun.COM 				if (fdestp->fcipd_ncmds) {
7471*7836SJohn.Forte@Sun.COM 					/*
7472*7836SJohn.Forte@Sun.COM 					 * Instead of waiting to drain commands
7473*7836SJohn.Forte@Sun.COM 					 * let us revisit this RT entry in
7474*7836SJohn.Forte@Sun.COM 					 * the next pass.
7475*7836SJohn.Forte@Sun.COM 					 */
7476*7836SJohn.Forte@Sun.COM 					mutex_exit(&fdestp->fcipd_mutex);
7477*7836SJohn.Forte@Sun.COM 					frtp_prev = frtp;
7478*7836SJohn.Forte@Sun.COM 					frtp = frtp_next;
7479*7836SJohn.Forte@Sun.COM 					continue;
7480*7836SJohn.Forte@Sun.COM 				}
7481*7836SJohn.Forte@Sun.COM 
7482*7836SJohn.Forte@Sun.COM 				/*
7483*7836SJohn.Forte@Sun.COM 				 * We are clean, so remove the RTE
7484*7836SJohn.Forte@Sun.COM 				 */
7485*7836SJohn.Forte@Sun.COM 				fdestp->fcipd_rtable = NULL;
7486*7836SJohn.Forte@Sun.COM 				mutex_exit(&fdestp->fcipd_mutex);
7487*7836SJohn.Forte@Sun.COM 
7488*7836SJohn.Forte@Sun.COM 				FCIP_TNF_PROBE_2((fcip_rte_remove_deferred,
7489*7836SJohn.Forte@Sun.COM 					"fcip io", /* CSTYLED */,
7490*7836SJohn.Forte@Sun.COM 					tnf_string, msg,
7491*7836SJohn.Forte@Sun.COM 					"remove retired routing entry",
7492*7836SJohn.Forte@Sun.COM 					tnf_int, index, index));
7493*7836SJohn.Forte@Sun.COM 
7494*7836SJohn.Forte@Sun.COM 				if (frtp_prev == NULL) {
7495*7836SJohn.Forte@Sun.COM 					/* first element */
7496*7836SJohn.Forte@Sun.COM 					fptr->fcip_rtable[index] =
7497*7836SJohn.Forte@Sun.COM 					    frtp->fcipr_next;
7498*7836SJohn.Forte@Sun.COM 				} else {
7499*7836SJohn.Forte@Sun.COM 					frtp_prev->fcipr_next =
7500*7836SJohn.Forte@Sun.COM 					    frtp->fcipr_next;
7501*7836SJohn.Forte@Sun.COM 				}
7502*7836SJohn.Forte@Sun.COM 				kmem_free(frtp,
7503*7836SJohn.Forte@Sun.COM 				    sizeof (struct fcip_routing_table));
7504*7836SJohn.Forte@Sun.COM 
7505*7836SJohn.Forte@Sun.COM 				frtp = frtp_next;
7506*7836SJohn.Forte@Sun.COM 			} else {
7507*7836SJohn.Forte@Sun.COM 				frtp_prev = frtp;
7508*7836SJohn.Forte@Sun.COM 				frtp = frtp_next;
7509*7836SJohn.Forte@Sun.COM 			}
7510*7836SJohn.Forte@Sun.COM 		}
7511*7836SJohn.Forte@Sun.COM 	}
7512*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_rt_mutex);
7513*7836SJohn.Forte@Sun.COM 	/*
7514*7836SJohn.Forte@Sun.COM 	 * Clear the RTE_REMOVING flag
7515*7836SJohn.Forte@Sun.COM 	 */
7516*7836SJohn.Forte@Sun.COM 	mutex_enter(&fptr->fcip_mutex);
7517*7836SJohn.Forte@Sun.COM 	fptr->fcip_flags &= ~FCIP_RTE_REMOVING;
7518*7836SJohn.Forte@Sun.COM 	mutex_exit(&fptr->fcip_mutex);
7519*7836SJohn.Forte@Sun.COM }
7520*7836SJohn.Forte@Sun.COM 
7521*7836SJohn.Forte@Sun.COM /*
7522*7836SJohn.Forte@Sun.COM  * Walk through all the dest hash table entries and count up the total
7523*7836SJohn.Forte@Sun.COM  * no. of packets outstanding against a given port
7524*7836SJohn.Forte@Sun.COM  */
7525*7836SJohn.Forte@Sun.COM static int
fcip_port_get_num_pkts(struct fcip * fptr)7526*7836SJohn.Forte@Sun.COM fcip_port_get_num_pkts(struct fcip *fptr)
7527*7836SJohn.Forte@Sun.COM {
7528*7836SJohn.Forte@Sun.COM 	int 			num_cmds = 0;
7529*7836SJohn.Forte@Sun.COM 	int 			i;
7530*7836SJohn.Forte@Sun.COM 	struct fcip_dest	*fdestp;
7531*7836SJohn.Forte@Sun.COM 
7532*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_dest_mutex));
7533*7836SJohn.Forte@Sun.COM 
7534*7836SJohn.Forte@Sun.COM 	for (i = 0; i < FCIP_DEST_HASH_ELEMS; i++) {
7535*7836SJohn.Forte@Sun.COM 		fdestp = fptr->fcip_dest[i];
7536*7836SJohn.Forte@Sun.COM 		while (fdestp != NULL) {
7537*7836SJohn.Forte@Sun.COM 			mutex_enter(&fdestp->fcipd_mutex);
7538*7836SJohn.Forte@Sun.COM 
7539*7836SJohn.Forte@Sun.COM 			ASSERT(fdestp->fcipd_ncmds >= 0);
7540*7836SJohn.Forte@Sun.COM 
7541*7836SJohn.Forte@Sun.COM 			if (fdestp->fcipd_ncmds > 0) {
7542*7836SJohn.Forte@Sun.COM 				num_cmds += fdestp->fcipd_ncmds;
7543*7836SJohn.Forte@Sun.COM 			}
7544*7836SJohn.Forte@Sun.COM 			mutex_exit(&fdestp->fcipd_mutex);
7545*7836SJohn.Forte@Sun.COM 			fdestp = fdestp->fcipd_next;
7546*7836SJohn.Forte@Sun.COM 		}
7547*7836SJohn.Forte@Sun.COM 	}
7548*7836SJohn.Forte@Sun.COM 
7549*7836SJohn.Forte@Sun.COM 	return (num_cmds);
7550*7836SJohn.Forte@Sun.COM }
7551*7836SJohn.Forte@Sun.COM 
7552*7836SJohn.Forte@Sun.COM 
7553*7836SJohn.Forte@Sun.COM /*
7554*7836SJohn.Forte@Sun.COM  * Walk through the routing table for this state instance and see if there is a
7555*7836SJohn.Forte@Sun.COM  * PLOGI in progress for any of the entries. Return success even if we find one.
7556*7836SJohn.Forte@Sun.COM  */
7557*7836SJohn.Forte@Sun.COM static int
fcip_plogi_in_progress(struct fcip * fptr)7558*7836SJohn.Forte@Sun.COM fcip_plogi_in_progress(struct fcip *fptr)
7559*7836SJohn.Forte@Sun.COM {
7560*7836SJohn.Forte@Sun.COM 	int				i;
7561*7836SJohn.Forte@Sun.COM 	struct fcip_routing_table	*frp;
7562*7836SJohn.Forte@Sun.COM 
7563*7836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fptr->fcip_rt_mutex));
7564*7836SJohn.Forte@Sun.COM 
7565*7836SJohn.Forte@Sun.COM 	for (i = 0; i < FCIP_RT_HASH_ELEMS; i++) {
7566*7836SJohn.Forte@Sun.COM 		frp = fptr->fcip_rtable[i];
7567*7836SJohn.Forte@Sun.COM 		while (frp) {
7568*7836SJohn.Forte@Sun.COM 			if (frp->fcipr_state == FCIP_RT_LOGIN_PROGRESS) {
7569*7836SJohn.Forte@Sun.COM 				/* Found an entry where PLOGI is in progress */
7570*7836SJohn.Forte@Sun.COM 				return (1);
7571*7836SJohn.Forte@Sun.COM 			}
7572*7836SJohn.Forte@Sun.COM 			frp = frp->fcipr_next;
7573*7836SJohn.Forte@Sun.COM 		}
7574*7836SJohn.Forte@Sun.COM 	}
7575*7836SJohn.Forte@Sun.COM 
7576*7836SJohn.Forte@Sun.COM 	return (0);
7577*7836SJohn.Forte@Sun.COM }
7578*7836SJohn.Forte@Sun.COM 
7579*7836SJohn.Forte@Sun.COM /*
7580*7836SJohn.Forte@Sun.COM  * Walk through the fcip port global list and check if the given port exists in
7581*7836SJohn.Forte@Sun.COM  * the list. Returns "0" if port exists and "1" if otherwise.
7582*7836SJohn.Forte@Sun.COM  */
7583*7836SJohn.Forte@Sun.COM static int
fcip_check_port_exists(struct fcip * fptr)7584*7836SJohn.Forte@Sun.COM fcip_check_port_exists(struct fcip *fptr)
7585*7836SJohn.Forte@Sun.COM {
7586*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*cur_fport;
7587*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport;
7588*7836SJohn.Forte@Sun.COM 
7589*7836SJohn.Forte@Sun.COM 	mutex_enter(&fcip_global_mutex);
7590*7836SJohn.Forte@Sun.COM 	fport = fptr->fcip_port_info;
7591*7836SJohn.Forte@Sun.COM 	cur_fport = fcip_port_head;
7592*7836SJohn.Forte@Sun.COM 	while (cur_fport != NULL) {
7593*7836SJohn.Forte@Sun.COM 		if (cur_fport == fport) {
7594*7836SJohn.Forte@Sun.COM 			/* Found */
7595*7836SJohn.Forte@Sun.COM 			mutex_exit(&fcip_global_mutex);
7596*7836SJohn.Forte@Sun.COM 			return (0);
7597*7836SJohn.Forte@Sun.COM 		} else {
7598*7836SJohn.Forte@Sun.COM 			cur_fport = cur_fport->fcipp_next;
7599*7836SJohn.Forte@Sun.COM 		}
7600*7836SJohn.Forte@Sun.COM 	}
7601*7836SJohn.Forte@Sun.COM 	mutex_exit(&fcip_global_mutex);
7602*7836SJohn.Forte@Sun.COM 
7603*7836SJohn.Forte@Sun.COM 	return (1);
7604*7836SJohn.Forte@Sun.COM }
7605*7836SJohn.Forte@Sun.COM 
7606*7836SJohn.Forte@Sun.COM /*
7607*7836SJohn.Forte@Sun.COM  * Constructor to initialize the sendup elements for callback into
7608*7836SJohn.Forte@Sun.COM  * modules upstream
7609*7836SJohn.Forte@Sun.COM  */
7610*7836SJohn.Forte@Sun.COM 
7611*7836SJohn.Forte@Sun.COM /* ARGSUSED */
7612*7836SJohn.Forte@Sun.COM static int
fcip_sendup_constructor(void * buf,void * arg,int flags)7613*7836SJohn.Forte@Sun.COM fcip_sendup_constructor(void *buf, void *arg, int flags)
7614*7836SJohn.Forte@Sun.COM {
7615*7836SJohn.Forte@Sun.COM 	struct fcip_sendup_elem	*msg_elem = (struct fcip_sendup_elem *)buf;
7616*7836SJohn.Forte@Sun.COM 	fcip_port_info_t	*fport = (fcip_port_info_t *)arg;
7617*7836SJohn.Forte@Sun.COM 
7618*7836SJohn.Forte@Sun.COM 	ASSERT(fport != NULL);
7619*7836SJohn.Forte@Sun.COM 
7620*7836SJohn.Forte@Sun.COM 	msg_elem->fcipsu_mp = NULL;
7621*7836SJohn.Forte@Sun.COM 	msg_elem->fcipsu_func = NULL;
7622*7836SJohn.Forte@Sun.COM 	msg_elem->fcipsu_next = NULL;
7623*7836SJohn.Forte@Sun.COM 
7624*7836SJohn.Forte@Sun.COM 	return (FCIP_SUCCESS);
7625*7836SJohn.Forte@Sun.COM }
7626