xref: /titanic_51/usr/src/uts/sun/io/socal.c (revision cd21e7c548ae2a3b5e522244bf798f2a6b4ba02d)
13db86aabSstevel /*
23db86aabSstevel  * CDDL HEADER START
33db86aabSstevel  *
43db86aabSstevel  * The contents of this file are subject to the terms of the
53db86aabSstevel  * Common Development and Distribution License (the "License").
63db86aabSstevel  * You may not use this file except in compliance with the License.
73db86aabSstevel  *
83db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
103db86aabSstevel  * See the License for the specific language governing permissions
113db86aabSstevel  * and limitations under the License.
123db86aabSstevel  *
133db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
143db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
163db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
173db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
183db86aabSstevel  *
193db86aabSstevel  * CDDL HEADER END
203db86aabSstevel  */
213db86aabSstevel 
223db86aabSstevel /*
2319397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243db86aabSstevel  * Use is subject to license terms.
253db86aabSstevel  */
26*cd21e7c5SGarrett D'Amore /*
27*cd21e7c5SGarrett D'Amore  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
28*cd21e7c5SGarrett D'Amore  */
293db86aabSstevel 
303db86aabSstevel /*
313db86aabSstevel  * socal - Serial Optical Channel Arbitrated Loop host adapter driver.
323db86aabSstevel  */
333db86aabSstevel 
343db86aabSstevel #include <sys/types.h>
353db86aabSstevel #include <sys/note.h>
363db86aabSstevel #include <sys/devops.h>
373db86aabSstevel #include <sys/param.h>
383db86aabSstevel #include <sys/systm.h>
393db86aabSstevel #include <sys/user.h>
403db86aabSstevel #include <sys/buf.h>
413db86aabSstevel #include <sys/ioctl.h>
423db86aabSstevel #include <sys/uio.h>
433db86aabSstevel #include <sys/fcntl.h>
443db86aabSstevel 
453db86aabSstevel #include <sys/cmn_err.h>
463db86aabSstevel #include <sys/stropts.h>
473db86aabSstevel #include <sys/kmem.h>
483db86aabSstevel 
493db86aabSstevel #include <sys/errno.h>
503db86aabSstevel #include <sys/open.h>
513db86aabSstevel #include <sys/varargs.h>
523db86aabSstevel #include <sys/var.h>
533db86aabSstevel #include <sys/thread.h>
543db86aabSstevel #include <sys/debug.h>
553db86aabSstevel #include <sys/cpu.h>
563db86aabSstevel #include <sys/autoconf.h>
573db86aabSstevel #include <sys/conf.h>
583db86aabSstevel #include <sys/stat.h>
593db86aabSstevel 
603db86aabSstevel #include <sys/file.h>
613db86aabSstevel #include <sys/syslog.h>
623db86aabSstevel 
633db86aabSstevel #include <sys/ddi.h>
643db86aabSstevel #include <sys/sunddi.h>
653db86aabSstevel #include <sys/ddi_impldefs.h>
663db86aabSstevel #include <sys/ksynch.h>
673db86aabSstevel #include <sys/ddidmareq.h>
683db86aabSstevel #include <sys/dditypes.h>
693db86aabSstevel #include <sys/ethernet.h>
703db86aabSstevel #include <sys/socalreg.h>
713db86aabSstevel #include <sys/socalmap.h>
723db86aabSstevel #include <sys/fc4/fcal.h>
733db86aabSstevel #include <sys/socal_cq_defs.h>
743db86aabSstevel #include <sys/fc4/fcal_linkapp.h>
753db86aabSstevel #include <sys/fc4/fcal_transport.h>
763db86aabSstevel #include <sys/socalio.h>
773db86aabSstevel #include <sys/socalvar.h>
783db86aabSstevel 
793db86aabSstevel /*
803db86aabSstevel  * Local Macros
813db86aabSstevel  */
823db86aabSstevel 
833db86aabSstevel #ifdef DEBUG
843db86aabSstevel #define	SOCAL_DEBUG 1
853db86aabSstevel #else
863db86aabSstevel #define	SOCAL_DEBUG 0
873db86aabSstevel #endif
883db86aabSstevel static uchar_t	socal_xrambuf[0x40000];
893db86aabSstevel static int 	socal_core = SOCAL_TAKE_CORE;
903db86aabSstevel #if SOCAL_DEBUG > 0 && !defined(lint)
913db86aabSstevel static	int soc_debug = SOCAL_DEBUG;
923db86aabSstevel static  int socal_read_stale_data = 0;
933db86aabSstevel #define	DEBUGF(level, args) \
943db86aabSstevel 	if (soc_debug >= (level)) cmn_err args;
953db86aabSstevel #define	SOCALDEBUG(level, args) \
963db86aabSstevel 	if (soc_debug >= level) args;
973db86aabSstevel #else
983db86aabSstevel #define	DEBUGF(level, args)	/* Nothing */
993db86aabSstevel #define	SOCALDEBUG(level, args)	/* Nothing */
1003db86aabSstevel #endif
1013db86aabSstevel 
1023db86aabSstevel 
1033db86aabSstevel /* defines for properties */
1043db86aabSstevel #define	SOCAL_PORT_NO_PROP		"socal_port"
1053db86aabSstevel #define	SOCAL_ALT_PORT_NO_PROP		"port#"
1063db86aabSstevel 
1073db86aabSstevel /* for socal_force_reset() */
1083db86aabSstevel #define	RESET_PORT			1
1093db86aabSstevel #define	DONT_RESET_PORT			0
1103db86aabSstevel 
1113db86aabSstevel /*
1123db86aabSstevel  * Driver Entry points.
1133db86aabSstevel  */
1143db86aabSstevel static int socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1153db86aabSstevel static int socal_bus_ctl(dev_info_t *dip, dev_info_t *rip,
1163db86aabSstevel 	ddi_ctl_enum_t op, void *a, void *v);
1173db86aabSstevel static int socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1183db86aabSstevel static int socal_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
1193db86aabSstevel 	void *arg, void **result);
1203db86aabSstevel static unsigned int socal_intr(caddr_t arg);
1213db86aabSstevel static unsigned int socal_dummy_intr(caddr_t arg);
1223db86aabSstevel static int socal_open(dev_t *devp, int flag, int otyp,
1233db86aabSstevel 	cred_t *cred_p);
1243db86aabSstevel static int socal_close(dev_t dev, int flag, int otyp,
1253db86aabSstevel 	cred_t *cred_p);
1263db86aabSstevel static int socal_ioctl(dev_t dev, int cmd, intptr_t arg,
1273db86aabSstevel 	int mode, cred_t *cred_p, int *rval_p);
1283db86aabSstevel 
1293db86aabSstevel /*
1303db86aabSstevel  * FC_AL transport functions.
1313db86aabSstevel  */
1323db86aabSstevel static uint_t socal_transport(fcal_packet_t *, fcal_sleep_t, int);
1333db86aabSstevel static uint_t socal_transport_poll(fcal_packet_t *, uint_t, int);
1343db86aabSstevel static uint_t socal_lilp_map(void *, uint_t, uint32_t, uint_t);
1353db86aabSstevel static uint_t socal_force_lip(void *, uint_t, uint_t, uint_t);
1363db86aabSstevel static uint_t socal_force_offline(void *, uint_t, uint_t);
1373db86aabSstevel static uint_t socal_abort_cmd(void *, uint_t, fcal_packet_t *, uint_t);
1383db86aabSstevel static uint_t socal_doit(fcal_packet_t *, socal_port_t *, int,
1393db86aabSstevel     void (*)(), int, int, uint_t *);
1403db86aabSstevel static uint_t socal_els(void *, uint_t, uint_t, uint_t,
1413db86aabSstevel 	void (*callback)(), void *, caddr_t, caddr_t *, uint_t);
1423db86aabSstevel static uint_t socal_bypass_dev(void *, uint_t, uint_t);
1433db86aabSstevel static void socal_force_reset(void *, uint_t, uint_t);
1443db86aabSstevel static void socal_add_ulp(void *, uint_t, uchar_t, void (*)(),
1453db86aabSstevel 	void (*)(), void (*)(), void *);
1463db86aabSstevel static void socal_remove_ulp(void *, uint_t, uchar_t, void *);
1473db86aabSstevel static void socal_take_core(void *);
1483db86aabSstevel 
1493db86aabSstevel /*
1503db86aabSstevel  * Driver internal functions.
1513db86aabSstevel  */
1523db86aabSstevel static void socal_intr_solicited(socal_state_t *, uint32_t srq);
1533db86aabSstevel static void socal_intr_unsolicited(socal_state_t *, uint32_t urq);
1543db86aabSstevel static void socal_lilp_map_done(fcal_packet_t *);
1553db86aabSstevel static void socal_force_lip_done(fcal_packet_t *);
1563db86aabSstevel static void socal_force_offline_done(fcal_packet_t *);
1573db86aabSstevel static void socal_abort_done(fcal_packet_t *);
1583db86aabSstevel static void socal_bypass_dev_done(fcal_packet_t *);
1593db86aabSstevel static fcal_packet_t *socal_packet_alloc(socal_state_t *, fcal_sleep_t);
1603db86aabSstevel static void socal_packet_free(fcal_packet_t *);
1613db86aabSstevel static void socal_disable(socal_state_t *socalp);
1623db86aabSstevel static void socal_init_transport_interface(socal_state_t *socalp);
1633db86aabSstevel static int socal_cqalloc_init(socal_state_t *socalp, uint32_t index);
1643db86aabSstevel static void socal_cqinit(socal_state_t *socalp, uint32_t index);
1653db86aabSstevel static int socal_start(socal_state_t *socalp);
1663db86aabSstevel static void socal_doreset(socal_state_t *socalp);
1673db86aabSstevel static int socal_dodetach(dev_info_t *dip);
1683db86aabSstevel static int socal_diag_request(socal_state_t *socalp, uint32_t port,
1693db86aabSstevel 	uint_t *diagcode, uint32_t cmd);
1703db86aabSstevel static void socal_download_ucode(socal_state_t *socalp);
1713db86aabSstevel static void socal_init_cq_desc(socal_state_t *socalp);
1723db86aabSstevel static void socal_init_wwn(socal_state_t *socalp);
1733db86aabSstevel static void socal_enable(socal_state_t *socalp);
1743db86aabSstevel static int socal_establish_pool(socal_state_t *socalp, uint32_t poolid);
1753db86aabSstevel static int socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid);
1763db86aabSstevel static int socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t
1773db86aabSstevel 	dest, la_els_adisc_t *adisc_pl, uint32_t polled);
1783db86aabSstevel static int socal_issue_lbf(socal_state_t *socalp, uint32_t port,
1793db86aabSstevel 	uchar_t *flb_pl, size_t length, uint32_t polled);
1803db86aabSstevel static int socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t
1813db86aabSstevel 	dest, la_els_rls_reply_t *rls_pl, uint32_t polled);
1823db86aabSstevel static void socal_us_els(socal_state_t *, cqe_t *, caddr_t);
1833db86aabSstevel static fcal_packet_t *socal_els_alloc(socal_state_t *, uint32_t, uint32_t,
1843db86aabSstevel 	uint32_t, uint32_t, caddr_t *, uint32_t);
1853db86aabSstevel static fcal_packet_t *socal_lbf_alloc(socal_state_t *, uint32_t,
1863db86aabSstevel 	uint32_t, uint32_t, caddr_t *, uint32_t);
1873db86aabSstevel static void socal_els_free(socal_priv_cmd_t *);
1883db86aabSstevel static void socal_lbf_free(socal_priv_cmd_t *);
1893db86aabSstevel static int socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
1903db86aabSstevel 	uint32_t polled, int);
1913db86aabSstevel static void socal_flush_overflowq(socal_state_t *, int, int);
1923db86aabSstevel static void socal_deferred_intr(void *);
1933db86aabSstevel static void socal_fix_harda(socal_state_t *socalp, int port);
1943db86aabSstevel 
1953db86aabSstevel /*
1963db86aabSstevel  * SOC+ Circular Queue Management routines.
1973db86aabSstevel  */
1983db86aabSstevel static int socal_cq_enque(socal_state_t *, socal_port_t *, cqe_t *, int,
1993db86aabSstevel 	fcal_sleep_t, fcal_packet_t *, int);
2003db86aabSstevel 
2013db86aabSstevel /*
2023db86aabSstevel  * Utility functions
2033db86aabSstevel  */
2043db86aabSstevel static void socal_disp_err(socal_state_t *, uint_t level, char *mid, char *msg);
2053db86aabSstevel static void socal_wcopy(uint_t *, uint_t *, int);
2063db86aabSstevel 
2073db86aabSstevel /*
2083db86aabSstevel  *  Set this bit to enable 64-bit sus mode
2093db86aabSstevel  */
2103db86aabSstevel static	int socal_64bitsbus = 1;
2113db86aabSstevel 
2123db86aabSstevel /*
2133db86aabSstevel  * Default soc dma limits
2143db86aabSstevel  */
2153db86aabSstevel 
2163db86aabSstevel static ddi_dma_lim_t default_socallim = {
2173db86aabSstevel 	(ulong_t)0, (ulong_t)0xffffffff, (uint_t)0xffffffff,
2183db86aabSstevel 	DEFAULT_BURSTSIZE | BURST32 | BURST64, 1, (25*1024)
2193db86aabSstevel };
2203db86aabSstevel 
2213db86aabSstevel static struct ddi_dma_attr socal_dma_attr = {
2223db86aabSstevel 	DMA_ATTR_V0,			/* version */
2233db86aabSstevel 	(unsigned long long)0,		/* addr_lo */
2243db86aabSstevel 	(unsigned long long)0xffffffff,	/* addr_hi */
2253db86aabSstevel 	(unsigned long long)0xffffffff,	/* count max */
2263db86aabSstevel 	(unsigned long long)4,		/* align */
2273db86aabSstevel 	DEFAULT_BURSTSIZE | BURST32 | BURST64, 	/* burst size */
2283db86aabSstevel 	1,				/* minxfer */
2293db86aabSstevel 	(unsigned long long)0xffffffff,	/* maxxfer */
2303db86aabSstevel 	(unsigned long long)0xffffffff,	/* seg */
2313db86aabSstevel 	1,				/* sgllen */
2323db86aabSstevel 	4,				/* granularity */
2333db86aabSstevel 	0				/* flags */
2343db86aabSstevel };
2353db86aabSstevel 
2363db86aabSstevel static struct ddi_device_acc_attr socal_acc_attr = {
2373db86aabSstevel 	(ushort_t)DDI_DEVICE_ATTR_V0,	/* version */
2383db86aabSstevel 	(uchar_t)DDI_STRUCTURE_BE_ACC,	/* endian flags */
2393db86aabSstevel 	(uchar_t)DDI_STRICTORDER_ACC	/* data order */
2403db86aabSstevel };
2413db86aabSstevel 
2423db86aabSstevel static struct fcal_transport_ops socal_transport_ops = {
2433db86aabSstevel 	socal_transport,
2443db86aabSstevel 	socal_transport_poll,
2453db86aabSstevel 	socal_lilp_map,
2463db86aabSstevel 	socal_force_lip,
2473db86aabSstevel 	socal_abort_cmd,
2483db86aabSstevel 	socal_els,
2493db86aabSstevel 	socal_bypass_dev,
2503db86aabSstevel 	socal_force_reset,
2513db86aabSstevel 	socal_add_ulp,
2523db86aabSstevel 	socal_remove_ulp,
2533db86aabSstevel 	socal_take_core
2543db86aabSstevel };
2553db86aabSstevel 
2563db86aabSstevel /*
2573db86aabSstevel  * Table used for setting the burst size in the soc+ config register
2583db86aabSstevel  */
2593db86aabSstevel static int socal_burst32_table[] = {
2603db86aabSstevel 	SOCAL_CR_BURST_4,
2613db86aabSstevel 	SOCAL_CR_BURST_4,
2623db86aabSstevel 	SOCAL_CR_BURST_4,
2633db86aabSstevel 	SOCAL_CR_BURST_4,
2643db86aabSstevel 	SOCAL_CR_BURST_16,
2653db86aabSstevel 	SOCAL_CR_BURST_32,
2663db86aabSstevel 	SOCAL_CR_BURST_64
2673db86aabSstevel };
2683db86aabSstevel 
2693db86aabSstevel /*
2703db86aabSstevel  * Table for setting the burst size for 64-bit sbus mode in soc+'s CR
2713db86aabSstevel  */
2723db86aabSstevel static int socal_burst64_table[] = {
2733db86aabSstevel 	(SOCAL_CR_BURST_8 << 8),
2743db86aabSstevel 	(SOCAL_CR_BURST_8 << 8),
2753db86aabSstevel 	(SOCAL_CR_BURST_8 << 8),
2763db86aabSstevel 	(SOCAL_CR_BURST_8 << 8),
2773db86aabSstevel 	(SOCAL_CR_BURST_8 << 8),
2783db86aabSstevel 	(SOCAL_CR_BURST_32 << 8),
2793db86aabSstevel 	(SOCAL_CR_BURST_64 << 8),
2803db86aabSstevel 	(SOCAL_CR_BURST_128 << 8)
2813db86aabSstevel };
2823db86aabSstevel 
2833db86aabSstevel /*
2843db86aabSstevel  * Tables used to define the sizes of the Circular Queues
2853db86aabSstevel  *
2863db86aabSstevel  * To conserve DVMA/IOPB space, we make some of these queues small...
2873db86aabSstevel  */
2883db86aabSstevel static int socal_req_entries[] = {
2893db86aabSstevel 	SOCAL_SMALL_CQ_ENTRIES,		/* Error (reset, lip) requests */
2903db86aabSstevel 	SOCAL_MAX_CQ_ENTRIES,		/* Most commands */
2913db86aabSstevel 	0,				/* Not currently used */
2923db86aabSstevel 	0				/* Not currently used */
2933db86aabSstevel };
2943db86aabSstevel 
2953db86aabSstevel static int socal_rsp_entries[] = {
2963db86aabSstevel 	SOCAL_MAX_CQ_ENTRIES,		/* Solicited  "SOC_OK" responses */
2973db86aabSstevel 	SOCAL_SMALL_CQ_ENTRIES,		/* Solicited error responses */
2983db86aabSstevel 	0,			/* Unsolicited responses */
2993db86aabSstevel 	0				/* Not currently used */
3003db86aabSstevel };
3013db86aabSstevel 
3023db86aabSstevel /*
3033db86aabSstevel  * Bus ops vector
3043db86aabSstevel  */
3053db86aabSstevel 
3063db86aabSstevel static struct bus_ops socal_bus_ops = {
3073db86aabSstevel 	BUSO_REV,		/* rev */
3083db86aabSstevel 	nullbusmap,		/* int (*bus_map)() */
3093db86aabSstevel 	0,			/* ddi_intrspec_t (*bus_get_intrspec)(); */
3103db86aabSstevel 	0,			/* int (*bus_add_intrspec)(); */
3113db86aabSstevel 	0,			/* void	(*bus_remove_intrspec)(); */
3123db86aabSstevel 	i_ddi_map_fault,	/* int (*bus_map_fault)() */
313*cd21e7c5SGarrett D'Amore 	0,			/* int (*bus_dma_map)() */
3143db86aabSstevel 	ddi_dma_allochdl,
3153db86aabSstevel 	ddi_dma_freehdl,
3163db86aabSstevel 	ddi_dma_bindhdl,
3173db86aabSstevel 	ddi_dma_unbindhdl,
3183db86aabSstevel 	ddi_dma_flush,
3193db86aabSstevel 	ddi_dma_win,
3203db86aabSstevel 	ddi_dma_mctl,		/* int (*bus_dma_ctl)() */
3213db86aabSstevel 	socal_bus_ctl,		/* int (*bus_ctl)() */
32219397407SSherry Moore 	ddi_bus_prop_op,	/* int (*bus_prop_op*)() */
3233db86aabSstevel };
3243db86aabSstevel 
3253db86aabSstevel static struct cb_ops socal_cb_ops = {
3263db86aabSstevel 	socal_open,		/* int (*cb_open)() */
3273db86aabSstevel 	socal_close,		/* int (*cb_close)() */
3283db86aabSstevel 	nodev,			/* int (*cb_strategy)() */
3293db86aabSstevel 	nodev,			/* int (*cb_print)() */
3303db86aabSstevel 	nodev,			/* int (*cb_dump)() */
3313db86aabSstevel 	nodev,			/* int (*cb_read)() */
3323db86aabSstevel 	nodev,			/* int (*cb_write)() */
3333db86aabSstevel 	socal_ioctl,		/* int (*cb_ioctl)() */
3343db86aabSstevel 	nodev,			/* int (*cb_devmap)() */
3353db86aabSstevel 	nodev,			/* int (*cb_mmap)() */
3363db86aabSstevel 	nodev,			/* int (*cb_segmap)() */
3373db86aabSstevel 	nochpoll,		/* int (*cb_chpoll)() */
3383db86aabSstevel 	ddi_prop_op,		/* int (*cb_prop_op)() */
3393db86aabSstevel 	0,			/* struct streamtab *cb_str */
3403db86aabSstevel 	D_MP|D_NEW|D_HOTPLUG,	/* cb_flag */
3413db86aabSstevel 	CB_REV,			/* rev */
3423db86aabSstevel 	nodev,			/* int (*cb_aread)() */
3433db86aabSstevel 	nodev			/* int (*cb_awrite)() */
3443db86aabSstevel };
3453db86aabSstevel 
3463db86aabSstevel /*
3473db86aabSstevel  * Soc driver ops structure.
3483db86aabSstevel  */
3493db86aabSstevel 
3503db86aabSstevel static struct dev_ops socal_ops = {
3513db86aabSstevel 	DEVO_REV,		/* devo_rev, */
3523db86aabSstevel 	0,			/* refcnt */
3533db86aabSstevel 	socal_getinfo,		/* get_dev_info */
3543db86aabSstevel 	nulldev,		/* identify */
3553db86aabSstevel 	nulldev,		/* probe */
3563db86aabSstevel 	socal_attach,		/* attach */
3573db86aabSstevel 	socal_detach,		/* detach */
3583db86aabSstevel 	nodev,			/* reset */
3593db86aabSstevel 	&socal_cb_ops,		/* driver operations */
36019397407SSherry Moore 	&socal_bus_ops,		/* bus operations */
36119397407SSherry Moore 	NULL,			/* power */
36219397407SSherry Moore 	ddi_quiesce_not_supported,	/* quiesce */
3633db86aabSstevel };
3643db86aabSstevel 
3653db86aabSstevel /*
3663db86aabSstevel  * Driver private variables.
3673db86aabSstevel  */
3683db86aabSstevel 
3693db86aabSstevel static void *socal_soft_state_p = NULL;
3703db86aabSstevel static ddi_dma_lim_t *socallim = NULL;
3713db86aabSstevel 
3723db86aabSstevel static uchar_t socal_switch_to_alpa[] = {
3733db86aabSstevel 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
3743db86aabSstevel 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
3753db86aabSstevel 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
3763db86aabSstevel 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
3773db86aabSstevel 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
3783db86aabSstevel 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
3793db86aabSstevel 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
3803db86aabSstevel 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
3813db86aabSstevel 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
3823db86aabSstevel 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
3833db86aabSstevel 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
3843db86aabSstevel 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
3853db86aabSstevel 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
3863db86aabSstevel };
3873db86aabSstevel 
3883db86aabSstevel /*
3893db86aabSstevel  * Firmware related externs
3903db86aabSstevel  */
3913db86aabSstevel extern uint32_t socal_ucode[];
3923db86aabSstevel extern size_t socal_ucode_size;
3933db86aabSstevel 
3943db86aabSstevel /*
3953db86aabSstevel  * This is the loadable module wrapper: "module configuration section".
3963db86aabSstevel  */
3973db86aabSstevel 
3983db86aabSstevel #include <sys/modctl.h>
3993db86aabSstevel extern struct mod_ops mod_driverops;
4003db86aabSstevel 
4013db86aabSstevel /*
4023db86aabSstevel  * Module linkage information for the kernel.
4033db86aabSstevel  */
4043db86aabSstevel #define	SOCAL_NAME "SOC+ FC-AL Host Adapter Driver"
40519397407SSherry Moore static	char	socal_version[] = "1.62 08/19/2008";
4063db86aabSstevel static struct modldrv modldrv = {
4073db86aabSstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
40819397407SSherry Moore 	SOCAL_NAME,
4093db86aabSstevel 	&socal_ops,		/* driver ops */
4103db86aabSstevel };
4113db86aabSstevel 
4123db86aabSstevel static struct modlinkage modlinkage = {
4133db86aabSstevel 	MODREV_1, (void *)&modldrv, NULL
4143db86aabSstevel };
4153db86aabSstevel 
4163db86aabSstevel /*
4173db86aabSstevel  * This is the module initialization/completion routines
4183db86aabSstevel  */
4193db86aabSstevel 
4203db86aabSstevel #if !defined(lint)
42119397407SSherry Moore static char socal_initmsg[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
4223db86aabSstevel #endif
4233db86aabSstevel 
4243db86aabSstevel int
4253db86aabSstevel _init(void)
4263db86aabSstevel {
4273db86aabSstevel 	int stat;
4283db86aabSstevel 
4293db86aabSstevel 	DEBUGF(4, (CE_CONT, socal_initmsg));
4303db86aabSstevel 
4313db86aabSstevel 	/* Allocate soft state.  */
4323db86aabSstevel 	stat = ddi_soft_state_init(&socal_soft_state_p,
4333db86aabSstevel 	    sizeof (socal_state_t), SOCAL_INIT_ITEMS);
4343db86aabSstevel 	if (stat != 0)
4353db86aabSstevel 		return (stat);
4363db86aabSstevel 
4373db86aabSstevel 	/* Install the module */
4383db86aabSstevel 	stat = mod_install(&modlinkage);
4393db86aabSstevel 	if (stat != 0)
4403db86aabSstevel 		ddi_soft_state_fini(&socal_soft_state_p);
4413db86aabSstevel 
4423db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal: _init: return=%d\n", stat));
4433db86aabSstevel 	return (stat);
4443db86aabSstevel }
4453db86aabSstevel 
4463db86aabSstevel int
4473db86aabSstevel _fini(void)
4483db86aabSstevel {
4493db86aabSstevel 	int stat;
4503db86aabSstevel 
4513db86aabSstevel 	if ((stat = mod_remove(&modlinkage)) != 0)
4523db86aabSstevel 		return (stat);
4533db86aabSstevel 
4543db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal: _fini: \n"));
4553db86aabSstevel 
4563db86aabSstevel 	ddi_soft_state_fini(&socal_soft_state_p);
4573db86aabSstevel 
4583db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal: _fini: return=%d\n", stat));
4593db86aabSstevel 	return (stat);
4603db86aabSstevel }
4613db86aabSstevel 
4623db86aabSstevel int
4633db86aabSstevel _info(struct modinfo *modinfop)
4643db86aabSstevel {
4653db86aabSstevel 	return (mod_info(&modlinkage, modinfop));
4663db86aabSstevel }
4673db86aabSstevel 
4683db86aabSstevel 
4693db86aabSstevel int
4703db86aabSstevel socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4713db86aabSstevel {
4723db86aabSstevel 	int			instance;
4733db86aabSstevel 	socal_state_t		*socalp;
4743db86aabSstevel 	struct ether_addr	ourmacaddr;
4753db86aabSstevel 	socal_port_t		*porta, *portb;
4763db86aabSstevel 	char			buf[MAXPATHLEN];
4773db86aabSstevel 	char			*cptr, *wwn;
4783db86aabSstevel 	int			y;
4793db86aabSstevel 	int			i, j;
4803db86aabSstevel 	int			burstsize;
4813db86aabSstevel 	short			s;
4823db86aabSstevel 	int			loop_id;
4833db86aabSstevel 
4843db86aabSstevel 	int			rval;
4853db86aabSstevel 
4863db86aabSstevel 
4873db86aabSstevel 	instance = ddi_get_instance(dip);
4883db86aabSstevel 
4893db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d entering attach: cmd=%x\n", instance,
4903db86aabSstevel 	    cmd));
4913db86aabSstevel 
4923db86aabSstevel 	if (cmd == DDI_RESUME) {
4933db86aabSstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
4943db86aabSstevel 			return (DDI_FAILURE);
4953db86aabSstevel 
4963db86aabSstevel 		if (!socalp->socal_shutdown) {
4973db86aabSstevel 			/* our work is already done */
4983db86aabSstevel 			return (DDI_SUCCESS);
4993db86aabSstevel 		}
5003db86aabSstevel 		if (socal_start(socalp) != FCAL_SUCCESS) {
5013db86aabSstevel 			return	(DDI_FAILURE);
5023db86aabSstevel 		}
5033db86aabSstevel 		DEBUGF(4, (CE_CONT, "socal%d resumed\n", instance));
5043db86aabSstevel 		return (DDI_SUCCESS);
5053db86aabSstevel 	}
5063db86aabSstevel 
5073db86aabSstevel 	if (cmd != DDI_ATTACH) {
5083db86aabSstevel 		return (DDI_FAILURE);
5093db86aabSstevel 	}
5103db86aabSstevel 
5113db86aabSstevel 	if (ddi_dev_is_sid(dip) != DDI_SUCCESS) {
5123db86aabSstevel 		cmn_err(CE_WARN, "socal%d probe: Not self-identifying",
5133db86aabSstevel 		    instance);
5143db86aabSstevel 		return (DDI_FAILURE);
5153db86aabSstevel 	}
5163db86aabSstevel 
5173db86aabSstevel 	/* If we are in a slave-slot, then we can't be used. */
5183db86aabSstevel 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
5193db86aabSstevel 		cmn_err(CE_WARN,
5203db86aabSstevel 		    "socal%d attach failed: device in slave-only slot",
5213db86aabSstevel 		    instance);
5223db86aabSstevel 		return (DDI_FAILURE);
5233db86aabSstevel 	}
5243db86aabSstevel 
5253db86aabSstevel 	if (ddi_intr_hilevel(dip, 0)) {
5263db86aabSstevel 		/*
5273db86aabSstevel 		 * Interrupt number '0' is a high-level interrupt.
5283db86aabSstevel 		 * At this point you either add a special interrupt
5293db86aabSstevel 		 * handler that triggers a soft interrupt at a lower level,
5303db86aabSstevel 		 * or - more simply and appropriately here - you just
5313db86aabSstevel 		 * fail the attach.
5323db86aabSstevel 		 */
5333db86aabSstevel 		cmn_err(CE_WARN,
5343db86aabSstevel 		"socal%d attach failed: hilevel interrupt unsupported",
5353db86aabSstevel 		    instance);
5363db86aabSstevel 		return (DDI_FAILURE);
5373db86aabSstevel 	}
5383db86aabSstevel 
5393db86aabSstevel 	/* Allocate soft state. */
5403db86aabSstevel 	if (ddi_soft_state_zalloc(socal_soft_state_p, instance)
5413db86aabSstevel 	    != DDI_SUCCESS) {
5423db86aabSstevel 		cmn_err(CE_WARN, "socal%d attach failed: alloc soft state",
5433db86aabSstevel 		    instance);
5443db86aabSstevel 		return (DDI_FAILURE);
5453db86aabSstevel 	}
5463db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: allocated soft state\n",
5473db86aabSstevel 	    instance));
5483db86aabSstevel 
5493db86aabSstevel 	/*
5503db86aabSstevel 	 * Initialize the state structure.
5513db86aabSstevel 	 */
5523db86aabSstevel 	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
5533db86aabSstevel 	if (socalp == (socal_state_t *)NULL) {
5543db86aabSstevel 		cmn_err(CE_WARN, "socal%d attach failed: bad soft state",
5553db86aabSstevel 		    instance);
5563db86aabSstevel 		return (DDI_FAILURE);
5573db86aabSstevel 	}
5583db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: soc soft state ptr=0x%p\n",
5593db86aabSstevel 	    instance, socalp));
5603db86aabSstevel 
5613db86aabSstevel 	socalp->dip = dip;
5623db86aabSstevel 	socallim = &default_socallim;
5633db86aabSstevel 	porta = &socalp->port_state[0];
5643db86aabSstevel 	portb = &socalp->port_state[1];
5653db86aabSstevel 
5663db86aabSstevel 	/* Get the full path name for displaying error messages */
5673db86aabSstevel 	cptr = ddi_pathname(dip, buf);
5683db86aabSstevel 	(void) strcpy(socalp->socal_name, cptr);
5693db86aabSstevel 
5703db86aabSstevel 	porta->sp_unsol_cb = NULL;
5713db86aabSstevel 	portb->sp_unsol_cb = NULL;
5723db86aabSstevel 	porta->sp_port = 0;
5733db86aabSstevel 	portb->sp_port = 1;
5743db86aabSstevel 	porta->sp_board = socalp;
5753db86aabSstevel 	portb->sp_board = socalp;
5763db86aabSstevel 
5773db86aabSstevel 	porta->sp_lilpmap_valid = 0;
5783db86aabSstevel 	portb->sp_lilpmap_valid = 0;
5793db86aabSstevel 
5803db86aabSstevel 	/*
5813db86aabSstevel 	 * If an hard loop-id property is present, then the port is going
5823db86aabSstevel 	 * to be used in target-mode so set the target-mode flag.
5833db86aabSstevel 	 */
5843db86aabSstevel 	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
5853db86aabSstevel 	    "port0-loop-id", 127);
5863db86aabSstevel 	if (loop_id >= 0 && loop_id <= 126) {
5873db86aabSstevel 		porta->sp_status |= PORT_TARGET_MODE;
5883db86aabSstevel 		porta->sp_hard_alpa = socal_switch_to_alpa[loop_id];
5893db86aabSstevel 	} else porta->sp_hard_alpa = 0xfe;
5903db86aabSstevel 
5913db86aabSstevel 	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
5923db86aabSstevel 	    "port1-loop-id", 127);
5933db86aabSstevel 	if (loop_id >= 0 && loop_id <= 126) {
5943db86aabSstevel 		portb->sp_status |= PORT_TARGET_MODE;
5953db86aabSstevel 		portb->sp_hard_alpa = socal_switch_to_alpa[loop_id];
5963db86aabSstevel 	} else portb->sp_hard_alpa = 0xfe;
5973db86aabSstevel 
5983db86aabSstevel 	/* Get out Node wwn and calculate port wwns */
5993db86aabSstevel 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip,
6003db86aabSstevel 	    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
6013db86aabSstevel 	    DDI_PROP_CANSLEEP, "wwn", (caddr_t)&wwn, &i);
6023db86aabSstevel 
6033db86aabSstevel 	if ((rval != DDI_PROP_SUCCESS) || (i < FC_WWN_SIZE) ||
6043db86aabSstevel 	    (bcmp(wwn, "00000000", FC_WWN_SIZE) == 0)) {
6053db86aabSstevel 		(void) localetheraddr((struct ether_addr *)NULL, &ourmacaddr);
6063db86aabSstevel 
6073db86aabSstevel 		bcopy((caddr_t)&ourmacaddr, (caddr_t)&s, sizeof (short));
6083db86aabSstevel 		socalp->socal_n_wwn.w.wwn_hi = s;
6093db86aabSstevel 		bcopy((caddr_t)&ourmacaddr+2,
6103db86aabSstevel 		    (caddr_t)&socalp->socal_n_wwn.w.wwn_lo,
6113db86aabSstevel 		    sizeof (uint_t));
6123db86aabSstevel 		socalp->socal_n_wwn.w.naa_id = NAA_ID_IEEE;
6133db86aabSstevel 		socalp->socal_n_wwn.w.nport_id = 0;
6143db86aabSstevel 	} else {
6153db86aabSstevel 		bcopy((caddr_t)wwn, (caddr_t)&socalp->socal_n_wwn, FC_WWN_SIZE);
6163db86aabSstevel 	}
6173db86aabSstevel 
6183db86aabSstevel 	if (rval == DDI_SUCCESS)
6193db86aabSstevel 		kmem_free((void *)wwn, i);
6203db86aabSstevel 
6213db86aabSstevel 	for (i = 0; i < FC_WWN_SIZE; i++) {
6223db86aabSstevel 		(void) sprintf(&socalp->socal_stats.node_wwn[i << 1],
6233db86aabSstevel 		    "%02x", socalp->socal_n_wwn.raw_wwn[i]);
6243db86aabSstevel 	}
6253db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: node wwn: %s\n",
6263db86aabSstevel 	    instance, socalp->socal_stats.node_wwn));
6273db86aabSstevel 
6283db86aabSstevel 	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&porta->sp_p_wwn,
6293db86aabSstevel 	    sizeof (la_wwn_t));
6303db86aabSstevel 	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&portb->sp_p_wwn,
6313db86aabSstevel 	    sizeof (la_wwn_t));
6323db86aabSstevel 	porta->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
6333db86aabSstevel 	portb->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
6343db86aabSstevel 	porta->sp_p_wwn.w.nport_id = instance*2;
6353db86aabSstevel 	portb->sp_p_wwn.w.nport_id = instance*2+1;
6363db86aabSstevel 
6373db86aabSstevel 	for (i = 0; i < FC_WWN_SIZE; i++) {
6383db86aabSstevel 		(void) sprintf(&socalp->socal_stats.port_wwn[0][i << 1],
6393db86aabSstevel 		    "%02x", porta->sp_p_wwn.raw_wwn[i]);
6403db86aabSstevel 		(void) sprintf(&socalp->socal_stats.port_wwn[1][i << 1],
6413db86aabSstevel 		    "%02x", portb->sp_p_wwn.raw_wwn[i]);
6423db86aabSstevel 	}
6433db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: porta wwn: %s\n",
6443db86aabSstevel 	    instance, socalp->socal_stats.port_wwn[0]));
6453db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: portb wwn: %s\n",
6463db86aabSstevel 	    instance, socalp->socal_stats.port_wwn[1]));
6473db86aabSstevel 
6483db86aabSstevel 	if ((porta->sp_transport = (fcal_transport_t *)
6493db86aabSstevel 	    kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
6503db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4011",
6513db86aabSstevel 		    "attach failed: unable to alloc xport struct");
6523db86aabSstevel 		goto fail;
6533db86aabSstevel 	}
6543db86aabSstevel 
6553db86aabSstevel 	if ((portb->sp_transport = (fcal_transport_t *)
6563db86aabSstevel 	    kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
6573db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4012",
6583db86aabSstevel 		    "attach failed: unable to alloc xport struct");
6593db86aabSstevel 		goto fail;
6603db86aabSstevel 	}
6613db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: allocated transport structs\n",
6623db86aabSstevel 	    instance));
6633db86aabSstevel 
6643db86aabSstevel 	/*
6653db86aabSstevel 	 * Map the external ram and registers for SOC+.
6663db86aabSstevel 	 * Note: Soc+ sbus host adapter provides 3 register definition
6673db86aabSstevel 	 * but on-board Soc+'s  may have only one register definition.
6683db86aabSstevel 	 */
6693db86aabSstevel 	if ((ddi_dev_nregs(dip, &i) == DDI_SUCCESS) && (i == 1)) {
6703db86aabSstevel 		/* Map XRAM */
6713db86aabSstevel 		if (ddi_map_regs(dip, 0, &socalp->socal_xrp, 0, 0)
6723db86aabSstevel 		    != DDI_SUCCESS) {
6733db86aabSstevel 			socalp->socal_xrp = NULL;
6743db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4020",
6753db86aabSstevel 			    "attach failed: unable to map XRAM");
6763db86aabSstevel 			goto fail;
6773db86aabSstevel 		}
6783db86aabSstevel 		/* Map registers */
6793db86aabSstevel 		socalp->socal_rp = (socal_reg_t *)(socalp->socal_xrp +
6803db86aabSstevel 		    SOCAL_XRAM_SIZE);
6813db86aabSstevel 	} else {
6823db86aabSstevel 		/* Map EEPROM */
6833db86aabSstevel 		if (ddi_map_regs(dip, 0, &socalp->socal_eeprom, 0, 0) !=
6843db86aabSstevel 		    DDI_SUCCESS) {
6853db86aabSstevel 			socalp->socal_eeprom = NULL;
6863db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4010",
6873db86aabSstevel 			    "attach failed: unable to map eeprom");
6883db86aabSstevel 			goto fail;
6893db86aabSstevel 		}
6903db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped eeprom 0x%p\n",
6913db86aabSstevel 	    instance, socalp->socal_eeprom));
6923db86aabSstevel 		/* Map XRAM */
6933db86aabSstevel 		if (ddi_map_regs(dip, 1, &socalp->socal_xrp, 0, 0) !=
6943db86aabSstevel 		    DDI_SUCCESS) {
6953db86aabSstevel 			socalp->socal_xrp = NULL;
6963db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4020",
6973db86aabSstevel 			    "attach failed: unable to map XRAM");
6983db86aabSstevel 			goto fail;
6993db86aabSstevel 		}
7003db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped xram 0x%p\n",
7013db86aabSstevel 	    instance, socalp->socal_xrp));
7023db86aabSstevel 		/* Map registers */
7033db86aabSstevel 		if (ddi_map_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0) !=
7043db86aabSstevel 		    DDI_SUCCESS) {
7053db86aabSstevel 			socalp->socal_rp = NULL;
7063db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4030",
7073db86aabSstevel 			    "attach failed: unable to map registers");
7083db86aabSstevel 			goto fail;
7093db86aabSstevel 		}
7103db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped regs 0x%p\n",
7113db86aabSstevel 	    instance, socalp->socal_rp));
7123db86aabSstevel 	}
7133db86aabSstevel 	/*
7143db86aabSstevel 	 * Check to see we really have a SOC+ Host Adapter card installed
7153db86aabSstevel 	 */
7163db86aabSstevel 	if (ddi_peek32(dip, (int32_t *)&socalp->socal_rp->socal_csr.w,
7173db86aabSstevel 	    (int32_t *)NULL) != DDI_SUCCESS) {
7183db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4040",
7193db86aabSstevel 		    "attach failed: unable to access status register");
7203db86aabSstevel 		goto fail;
7213db86aabSstevel 	}
7223db86aabSstevel 	/* now that we have our registers mapped make sure soc+ reset */
7233db86aabSstevel 	socal_disable(socalp);
7243db86aabSstevel 
7253db86aabSstevel 	/* try defacing a spot in XRAM */
7263db86aabSstevel 	if (ddi_poke32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
7273db86aabSstevel 	    0xdefaced) != DDI_SUCCESS) {
7283db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4050",
7293db86aabSstevel 		    "attach failed: unable to write host adapter XRAM");
7303db86aabSstevel 		goto fail;
7313db86aabSstevel 	}
7323db86aabSstevel 
7333db86aabSstevel 	/* see if it stayed defaced */
7343db86aabSstevel 	if (ddi_peek32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
7353db86aabSstevel 	    (int32_t *)&y)
7363db86aabSstevel 	    != DDI_SUCCESS) {
7373db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4051",
7383db86aabSstevel 		    "attach failed: unable to access host adapter XRAM");
7393db86aabSstevel 		goto fail;
7403db86aabSstevel 	}
7413db86aabSstevel 
7423db86aabSstevel #ifdef DEBUG
7433db86aabSstevel 	for (i = 0; i < 4; i++) {
7443db86aabSstevel 		socalp->socal_rp->socal_cr.w &=
7453db86aabSstevel 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
7463db86aabSstevel 		socalp->socal_rp->socal_cr.w |= i<<24;
7473db86aabSstevel 		cptr = (char *)(socal_xrambuf + (i*0x10000));
7483db86aabSstevel 		bcopy((caddr_t)socalp->socal_xrp, (caddr_t)cptr, 0x10000);
7493db86aabSstevel 	}
7503db86aabSstevel 	socalp->socal_rp->socal_cr.w &= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
7513db86aabSstevel #endif
7523db86aabSstevel 
7533db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: read xram\n", instance));
7543db86aabSstevel 
7553db86aabSstevel 	if (y != 0xdefaced) {
7563db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4052",
7573db86aabSstevel 		    "attach failed: read/write mismatch in XRAM");
7583db86aabSstevel 		goto fail;
7593db86aabSstevel 	}
7603db86aabSstevel 
7613db86aabSstevel 	/* Point to the SOC XRAM CQ Descriptor locations. */
7623db86aabSstevel 	socalp->xram_reqp = (soc_cq_t *)(socalp->socal_xrp +
7633db86aabSstevel 	    SOCAL_XRAM_REQ_DESC);
7643db86aabSstevel 	socalp->xram_rspp = (soc_cq_t *)(socalp->socal_xrp +
7653db86aabSstevel 	    SOCAL_XRAM_RSP_DESC);
7663db86aabSstevel 
7673db86aabSstevel 	if ((socalp->socal_ksp = kstat_create("socal", instance, "statistics",
7683db86aabSstevel 	    "controller", KSTAT_TYPE_RAW, sizeof (struct socal_stats),
7693db86aabSstevel 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
7703db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "attach.4053",
7713db86aabSstevel 		    "unable to create kstats");
7723db86aabSstevel 	} else {
7733db86aabSstevel 		socalp->socal_stats.version = 2;
7743db86aabSstevel 		(void) sprintf(socalp->socal_stats.drvr_name,
7753db86aabSstevel 		    "%s: %s", SOCAL_NAME, socal_version);
7763db86aabSstevel 		socalp->socal_stats.pstats[0].port = 0;
7773db86aabSstevel 		socalp->socal_stats.pstats[1].port = 1;
7783db86aabSstevel 		socalp->socal_ksp->ks_data = (void *)&socalp->socal_stats;
7793db86aabSstevel 		kstat_install(socalp->socal_ksp);
7803db86aabSstevel 	}
7813db86aabSstevel 
7823db86aabSstevel 	/*
7833db86aabSstevel 	 * Install a dummy interrupt routine.
7843db86aabSstevel 	 */
7853db86aabSstevel 	if (ddi_add_intr(dip,
7863db86aabSstevel 	    (uint_t)0,
7873db86aabSstevel 	    &socalp->iblkc,
7883db86aabSstevel 	    &socalp->idevc,
7893db86aabSstevel 	    socal_dummy_intr,
7903db86aabSstevel 	    (caddr_t)socalp) != DDI_SUCCESS) {
7913db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4060",
7923db86aabSstevel 			"attach failed: unable to install interrupt handler");
7933db86aabSstevel 			goto fail;
7943db86aabSstevel 	}
7953db86aabSstevel 
7963db86aabSstevel 	ddi_set_driver_private(dip, socalp);
7973db86aabSstevel 
7983db86aabSstevel 	/* initialize the interrupt mutex */
7993db86aabSstevel 	mutex_init(&socalp->k_imr_mtx, NULL, MUTEX_DRIVER,
8003db86aabSstevel 	    (void *)socalp->iblkc);
8013db86aabSstevel 
8023db86aabSstevel 	mutex_init(&socalp->board_mtx, NULL, MUTEX_DRIVER,
8033db86aabSstevel 	    (void *)socalp->iblkc);
8043db86aabSstevel 	mutex_init(&socalp->ioctl_mtx, NULL, MUTEX_DRIVER,
8053db86aabSstevel 	    (void *)socalp->iblkc);
8063db86aabSstevel 
8073db86aabSstevel 	/* initialize the abort mutex */
8083db86aabSstevel 	mutex_init(&socalp->abort_mtx, NULL, MUTEX_DRIVER,
8093db86aabSstevel 	    (void *)socalp->iblkc);
8103db86aabSstevel 
8113db86aabSstevel 	cv_init(&socalp->board_cv, NULL, CV_DRIVER, NULL);
8123db86aabSstevel 	DEBUGF(4, (CE_CONT,
8133db86aabSstevel 	    "socal%d: attach: inited imr mutex, board mutex, board cv\n",
8143db86aabSstevel 	    instance));
8153db86aabSstevel 
8163db86aabSstevel 	/* init the port mutexes */
8173db86aabSstevel 	mutex_init(&porta->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
8183db86aabSstevel 	cv_init(&porta->sp_cv, NULL, CV_DRIVER, NULL);
8193db86aabSstevel 	mutex_init(&portb->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
8203db86aabSstevel 	cv_init(&portb->sp_cv, NULL, CV_DRIVER, NULL);
8213db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: inited port mutexes and cvs\n",
8223db86aabSstevel 	    instance));
8233db86aabSstevel 
8243db86aabSstevel 	/* get local copy of service params */
8253db86aabSstevel 	socal_wcopy((uint_t *)socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS,
8263db86aabSstevel 	    (uint_t *)socalp->socal_service_params, SOCAL_SVC_LENGTH);
8273db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: got service params\n", instance));
8283db86aabSstevel 	/*
8293db86aabSstevel 	 * Initailize the FCAL transport interface.
8303db86aabSstevel 	 */
8313db86aabSstevel 	socal_init_transport_interface(socalp);
8323db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: initalized transport interface\n",
8333db86aabSstevel 	    instance));
8343db86aabSstevel 
8353db86aabSstevel 	/*
8363db86aabSstevel 	 * Allocate request and response queues and init their mutexs.
8373db86aabSstevel 	 */
8383db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
8393db86aabSstevel 		if (socal_cqalloc_init(socalp, i) != FCAL_SUCCESS) {
8403db86aabSstevel 			goto fail;
8413db86aabSstevel 		}
8423db86aabSstevel 	}
8433db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: allocated cqs\n", instance));
8443db86aabSstevel 
8453db86aabSstevel 	/*
8463db86aabSstevel 	 * Adjust the burst size we'll use.
8473db86aabSstevel 	 */
8483db86aabSstevel 	burstsize = ddi_dma_burstsizes(socalp->request[0].skc_dhandle);
8493db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: burstsize = 0x%x\n",
8503db86aabSstevel 	    instance, burstsize));
8513db86aabSstevel 	j = burstsize & BURSTSIZE_MASK;
8523db86aabSstevel 	for (i = 0; socal_burst32_table[i] != SOCAL_CR_BURST_64; i++)
8533db86aabSstevel 		if (!(j >>= 1)) break;
8543db86aabSstevel 
8553db86aabSstevel 	socalp->socal_cfg = (socalp->socal_cfg & ~SOCAL_CR_SBUS_BURST_SIZE_MASK)
8563db86aabSstevel 	    | socal_burst32_table[i];
8573db86aabSstevel 
8583db86aabSstevel 	if (socal_64bitsbus) {
8593db86aabSstevel 		if (ddi_dma_set_sbus64(socalp->request[0].skc_dhandle,
86019397407SSherry Moore 		    socal_dma_attr.dma_attr_burstsizes | BURST128) ==
86119397407SSherry Moore 		    DDI_SUCCESS) {
8623db86aabSstevel 			DEBUGF(4, (CE_CONT, "socal%d: enabled 64 bit sbus\n",
8633db86aabSstevel 			    instance));
8643db86aabSstevel 			socalp->socal_cfg |= SOCAL_CR_SBUS_ENHANCED;
8653db86aabSstevel 			burstsize = ddi_dma_burstsizes(socalp->request[0].
8663db86aabSstevel 			    skc_dhandle);
8673db86aabSstevel 		DEBUGF(4, (CE_CONT, "socal%d: attach: 64bit burstsize = 0x%x\n",
8683db86aabSstevel 		    instance, burstsize));
8693db86aabSstevel 			j = burstsize & BURSTSIZE_MASK;
8703db86aabSstevel 			for (i = 0; socal_burst64_table[i] !=
8713db86aabSstevel 			    (SOCAL_CR_BURST_128 << 8); i++)
8723db86aabSstevel 				if (!(j >>= 1))
8733db86aabSstevel 					break;
8743db86aabSstevel 
8753db86aabSstevel 			socalp->socal_cfg = (socalp->socal_cfg &
8763db86aabSstevel 			    ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK) |
8773db86aabSstevel 			    socal_burst64_table[i];
8783db86aabSstevel 		}
8793db86aabSstevel 	}
8803db86aabSstevel 
8813db86aabSstevel 	ddi_remove_intr(dip, 0, socalp->iblkc);
8823db86aabSstevel 	socalp->iblkc = (void *)NULL;
8833db86aabSstevel 	/*
8843db86aabSstevel 	 * Install the interrupt routine.
8853db86aabSstevel 	 */
8863db86aabSstevel 	if (ddi_add_intr(dip,
8873db86aabSstevel 	    (uint_t)0,
8883db86aabSstevel 	    &socalp->iblkc,
8893db86aabSstevel 	    &socalp->idevc,
8903db86aabSstevel 	    socal_intr,
8913db86aabSstevel 	    (caddr_t)socalp) != DDI_SUCCESS) {
8923db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "attach.4060",
8933db86aabSstevel 			"attach failed: unable to install interrupt handler");
8943db86aabSstevel 			goto fail;
8953db86aabSstevel 	}
8963db86aabSstevel 
8973db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: set config reg %x\n",
8983db86aabSstevel 	    instance, socalp->socal_cfg));
8993db86aabSstevel 
9003db86aabSstevel 	if (ddi_create_minor_node(dip, SOCAL_PORTA_NAME, S_IFCHR,
9013db86aabSstevel 	    instance*N_SOCAL_NPORTS, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
9023db86aabSstevel 		goto fail;
9033db86aabSstevel 	if (ddi_create_minor_node(dip, SOCAL_PORTB_NAME, S_IFCHR,
9043db86aabSstevel 	    instance*N_SOCAL_NPORTS+1, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
9053db86aabSstevel 		goto fail;
9063db86aabSstevel 
9073db86aabSstevel 	if (socal_start(socalp) != FCAL_SUCCESS)
9083db86aabSstevel 		goto fail;
9093db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: soc+ started\n", instance));
9103db86aabSstevel 
9113db86aabSstevel 	ddi_report_dev(dip);
9123db86aabSstevel 
9133db86aabSstevel 	DEBUGF(2, (CE_CONT, "socal%d: attach O.K.\n\n", instance));
9143db86aabSstevel 
9153db86aabSstevel 	return (DDI_SUCCESS);
9163db86aabSstevel 
9173db86aabSstevel fail:
9183db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: DDI_FAILURE\n", instance));
9193db86aabSstevel 
9203db86aabSstevel 	/* Make sure soc reset */
9213db86aabSstevel 	socal_disable(socalp);
9223db86aabSstevel 
9233db86aabSstevel 	/* let detach do the dirty work */
9243db86aabSstevel 	(void) socal_dodetach(dip);
9253db86aabSstevel 
9263db86aabSstevel 	return (DDI_FAILURE);
9273db86aabSstevel }
9283db86aabSstevel 
9293db86aabSstevel static int
9303db86aabSstevel socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9313db86aabSstevel {
9323db86aabSstevel 	int		resp;
9333db86aabSstevel 	socal_state_t	*socalp;
9343db86aabSstevel 	int		i;
9353db86aabSstevel 
9363db86aabSstevel 
9373db86aabSstevel 	switch (cmd) {
9383db86aabSstevel 
9393db86aabSstevel 	case DDI_SUSPEND:
9403db86aabSstevel 		DEBUGF(4, (CE_CONT, "socal: suspend called\n"));
9413db86aabSstevel 
9423db86aabSstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
9433db86aabSstevel 			return (DDI_FAILURE);
9443db86aabSstevel 
9453db86aabSstevel 		/*
9463db86aabSstevel 		 * If any of the ports are in target-mode, don't suspend
9473db86aabSstevel 		 */
9483db86aabSstevel 		for (i = 0; i < N_SOCAL_NPORTS; i++) {
9493db86aabSstevel 			if (socalp->port_state[i].sp_status & PORT_TARGET_MODE)
9503db86aabSstevel 				return (DDI_FAILURE);
9513db86aabSstevel 		}
9523db86aabSstevel 
9533db86aabSstevel 		/* do not restart socal after reset */
9543db86aabSstevel 		socal_force_reset((void *)socalp, 0, DONT_RESET_PORT);
9553db86aabSstevel 
9563db86aabSstevel 		return (DDI_SUCCESS);
9573db86aabSstevel 
9583db86aabSstevel 	case DDI_DETACH:
9593db86aabSstevel 		DEBUGF(4, (CE_CONT, "socal: detach called\n"));
9603db86aabSstevel 		resp = socal_dodetach(dip);
9613db86aabSstevel 		if (resp == DDI_SUCCESS)
9623db86aabSstevel 			ddi_set_driver_private(dip, NULL);
9633db86aabSstevel 		return (resp);
9643db86aabSstevel 
9653db86aabSstevel 	default:
9663db86aabSstevel 		return (DDI_FAILURE);
9673db86aabSstevel 	}
9683db86aabSstevel }
9693db86aabSstevel 
9703db86aabSstevel static int
9713db86aabSstevel socal_dodetach(dev_info_t *dip)
9723db86aabSstevel {
9733db86aabSstevel 
9743db86aabSstevel 	int		instance = ddi_get_instance(dip);
9753db86aabSstevel 	int		i;
9763db86aabSstevel 	socal_state_t	*socalp;
9773db86aabSstevel 	socal_port_t	*portp;
9783db86aabSstevel 	socal_unsol_cb_t	*cb, *cbn = NULL;
9793db86aabSstevel 
9803db86aabSstevel 	/* Get the soft state struct. */
9813db86aabSstevel 	if ((socalp = ddi_get_soft_state(socal_soft_state_p, instance)) == 0) {
9823db86aabSstevel 		return (DDI_FAILURE);
9833db86aabSstevel 	}
9843db86aabSstevel 
9853db86aabSstevel 	/*
9863db86aabSstevel 	 * If somebody is still attached to us from above fail
9873db86aabSstevel 	 * detach.
9883db86aabSstevel 	 */
9893db86aabSstevel 	mutex_enter(&socalp->board_mtx);
9903db86aabSstevel 	if (socalp->socal_busy > 0) {
9913db86aabSstevel 		mutex_exit(&socalp->board_mtx);
9923db86aabSstevel 		return (DDI_FAILURE);
9933db86aabSstevel 	}
9943db86aabSstevel 	/* mark socal_busy = -1 to disallow sftm attach */
9953db86aabSstevel 	socalp->socal_busy = -1;
9963db86aabSstevel 	mutex_exit(&socalp->board_mtx);
9973db86aabSstevel 
9983db86aabSstevel 	/* Make sure soc+ reset */
9993db86aabSstevel 	mutex_enter(&socalp->k_imr_mtx);
10003db86aabSstevel 	socal_disable(socalp);
10013db86aabSstevel 	mutex_exit(&socalp->k_imr_mtx);
10023db86aabSstevel 
10033db86aabSstevel 	/* remove soc+ interrupt */
10043db86aabSstevel 	if (socalp->iblkc != (void *)NULL) {
10053db86aabSstevel 		ddi_remove_intr(dip, (uint_t)0, socalp->iblkc);
10063db86aabSstevel 		DEBUGF(2, (CE_CONT,
10073db86aabSstevel 		    "socal%d: detach: Removed SOC+ interrupt from ddi\n",
10083db86aabSstevel 		    instance));
10093db86aabSstevel 	}
10103db86aabSstevel 
10113db86aabSstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
10123db86aabSstevel 		portp = &socalp->port_state[i];
10133db86aabSstevel 		mutex_destroy(&portp->sp_mtx);
10143db86aabSstevel 		cv_destroy(&portp->sp_cv);
10153db86aabSstevel 		mutex_destroy(&portp->sp_transport->fcal_mtx);
10163db86aabSstevel 		cv_destroy(&portp->sp_transport->fcal_cv);
10173db86aabSstevel 		kmem_free((void *)portp->sp_transport,
10183db86aabSstevel 		    sizeof (fcal_transport_t));
10193db86aabSstevel 		for (cb = portp->sp_unsol_cb; cb != (socal_unsol_cb_t *)NULL;
10203db86aabSstevel 		    cb = cbn) {
10213db86aabSstevel 			cbn = cb->next;
10223db86aabSstevel 			kmem_free((void *)cb, sizeof (socal_unsol_cb_t));
10233db86aabSstevel 		}
10243db86aabSstevel 		portp->sp_unsol_cb = (socal_unsol_cb_t *)NULL;
10253db86aabSstevel 	}
10263db86aabSstevel 
10273db86aabSstevel 	/*
10283db86aabSstevel 	 * Free request queues, if allocated
10293db86aabSstevel 	 */
10303db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
10313db86aabSstevel 		/* Free the queues and destroy their mutexes. */
10323db86aabSstevel 		mutex_destroy(&socalp->request[i].skc_mtx);
10333db86aabSstevel 		mutex_destroy(&socalp->response[i].skc_mtx);
10343db86aabSstevel 		cv_destroy(&socalp->request[i].skc_cv);
10353db86aabSstevel 		cv_destroy(&socalp->response[i].skc_cv);
10363db86aabSstevel 
10373db86aabSstevel 		if (socalp->request[i].skc_dhandle) {
10383db86aabSstevel 			(void) ddi_dma_unbind_handle(socalp->
10393db86aabSstevel 			    request[i].skc_dhandle);
10403db86aabSstevel 			ddi_dma_free_handle(&socalp->request[i].skc_dhandle);
10413db86aabSstevel 		}
10423db86aabSstevel 		if (socalp->request[i].skc_cq_raw) {
10433db86aabSstevel 			ddi_dma_mem_free(&socalp->request[i].skc_acchandle);
10443db86aabSstevel 			socalp->request[i].skc_cq_raw = NULL;
10453db86aabSstevel 			socalp->request[i].skc_cq = NULL;
10463db86aabSstevel 		}
10473db86aabSstevel 		if (socalp->response[i].skc_dhandle) {
10483db86aabSstevel 			(void) ddi_dma_unbind_handle(socalp->
10493db86aabSstevel 			    response[i].skc_dhandle);
10503db86aabSstevel 			ddi_dma_free_handle(&socalp->response[i].skc_dhandle);
10513db86aabSstevel 		}
10523db86aabSstevel 		if (socalp->response[i].skc_cq_raw) {
10533db86aabSstevel 			ddi_dma_mem_free(&socalp->response[i].skc_acchandle);
10543db86aabSstevel 			socalp->response[i].skc_cq_raw = NULL;
10553db86aabSstevel 			socalp->response[i].skc_cq = NULL;
10563db86aabSstevel 		}
10573db86aabSstevel 		if (socalp->request[i].deferred_intr_timeoutid) {
10583db86aabSstevel 			(void) untimeout(socalp->
10593db86aabSstevel 			    request[i].deferred_intr_timeoutid);
10603db86aabSstevel 		}
10613db86aabSstevel 		if (socalp->response[i].deferred_intr_timeoutid) {
10623db86aabSstevel 			(void) untimeout(socalp->
10633db86aabSstevel 			    response[i].deferred_intr_timeoutid);
10643db86aabSstevel 		}
10653db86aabSstevel 	}
10663db86aabSstevel 
10673db86aabSstevel 	mutex_destroy(&socalp->abort_mtx);
10683db86aabSstevel 	mutex_destroy(&socalp->board_mtx);
10693db86aabSstevel 	mutex_destroy(&socalp->ioctl_mtx);
10703db86aabSstevel 	cv_destroy(&socalp->board_cv);
10713db86aabSstevel 
10723db86aabSstevel 	/*
10733db86aabSstevel 	 * Free soc data buffer pool
10743db86aabSstevel 	 */
10753db86aabSstevel 	if (socalp->pool_dhandle) {
10763db86aabSstevel 		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
10773db86aabSstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
10783db86aabSstevel 	}
10793db86aabSstevel 	if (socalp->pool) {
10803db86aabSstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
10813db86aabSstevel 	}
10823db86aabSstevel 
10833db86aabSstevel 	/* release register maps */
10843db86aabSstevel 	/* Unmap EEPROM */
10853db86aabSstevel 	if (socalp->socal_eeprom != NULL) {
10863db86aabSstevel 		ddi_unmap_regs(dip, 0, &socalp->socal_eeprom, 0, 0);
10873db86aabSstevel 	}
10883db86aabSstevel 
10893db86aabSstevel 	/* Unmap XRAM */
10903db86aabSstevel 	if (socalp->socal_xrp != NULL) {
10913db86aabSstevel 		ddi_unmap_regs(dip, 1, &socalp->socal_xrp, 0, 0);
10923db86aabSstevel 	}
10933db86aabSstevel 
10943db86aabSstevel 	/* Unmap registers */
10953db86aabSstevel 	if (socalp->socal_rp != NULL) {
10963db86aabSstevel 		ddi_unmap_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0);
10973db86aabSstevel 	}
10983db86aabSstevel 
10993db86aabSstevel 	if (socalp->socal_ksp != NULL)
11003db86aabSstevel 		kstat_delete(socalp->socal_ksp);
11013db86aabSstevel 
11023db86aabSstevel 	mutex_destroy(&socalp->k_imr_mtx);
11033db86aabSstevel 
11043db86aabSstevel 	ddi_remove_minor_node(dip, NULL);
11053db86aabSstevel 
11063db86aabSstevel 	ddi_soft_state_free(socal_soft_state_p, instance);
11073db86aabSstevel 
11083db86aabSstevel 	return (DDI_SUCCESS);
11093db86aabSstevel }
11103db86aabSstevel 
11113db86aabSstevel 
11123db86aabSstevel int
11133db86aabSstevel socal_bus_ctl(dev_info_t *dip, dev_info_t *rip, ddi_ctl_enum_t op,
11143db86aabSstevel 	void *a, void *v)
11153db86aabSstevel {
11163db86aabSstevel 	int		port;
11173db86aabSstevel 
11183db86aabSstevel 
11193db86aabSstevel 	switch (op) {
11203db86aabSstevel 	case DDI_CTLOPS_REPORTDEV:
11213db86aabSstevel 		port = ddi_getprop(DDI_DEV_T_ANY, rip, DDI_PROP_DONTPASS,
11223db86aabSstevel 		    SOCAL_PORT_NO_PROP, -1);
11233db86aabSstevel 		if ((port < 0) || (port > 1)) {
11243db86aabSstevel 			port = ddi_getprop(DDI_DEV_T_ANY, rip,
11253db86aabSstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11263db86aabSstevel 		}
11273db86aabSstevel 		/* log text identifying this driver (d) & its child (r) */
11283db86aabSstevel 		cmn_err(CE_CONT, "?%s%d at %s%d: socal_port %d\n",
11293db86aabSstevel 		    ddi_driver_name(rip), ddi_get_instance(rip),
11303db86aabSstevel 		    ddi_driver_name(dip), ddi_get_instance(dip),
11313db86aabSstevel 		    port);
11323db86aabSstevel 		break;
11333db86aabSstevel 
11343db86aabSstevel 	case DDI_CTLOPS_INITCHILD: {
11353db86aabSstevel 		dev_info_t	*child_dip = (dev_info_t *)a;
11363db86aabSstevel 		char		name[MAXNAMELEN];
11373db86aabSstevel 		socal_state_t	*socalp;
11383db86aabSstevel 
11393db86aabSstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
11403db86aabSstevel 			return (DDI_FAILURE);
11413db86aabSstevel 
11423db86aabSstevel 		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11433db86aabSstevel 		    DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
11443db86aabSstevel 
11453db86aabSstevel 		if ((port < 0) || (port > 1)) {
11463db86aabSstevel 			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11473db86aabSstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11483db86aabSstevel 			if ((port < 0) || (port > 1)) {
11493db86aabSstevel 				return (DDI_NOT_WELL_FORMED);
11503db86aabSstevel 			}
11513db86aabSstevel 		}
11523db86aabSstevel 		mutex_enter(&socalp->board_mtx);
11533db86aabSstevel 		mutex_enter(&socalp->port_state[port].sp_mtx);
11543db86aabSstevel 		if (socalp->port_state[port].sp_status &
11553db86aabSstevel 		    (PORT_CHILD_INIT | PORT_TARGET_MODE)) {
11563db86aabSstevel 			mutex_exit(&socalp->port_state[port].sp_mtx);
11573db86aabSstevel 			mutex_exit(&socalp->board_mtx);
11583db86aabSstevel 			return (DDI_FAILURE);
11593db86aabSstevel 		}
11603db86aabSstevel 		socalp->socal_busy++;
11613db86aabSstevel 		socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
11623db86aabSstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
11633db86aabSstevel 		mutex_exit(&socalp->board_mtx);
11643db86aabSstevel 		ddi_set_parent_data(child_dip,
11653db86aabSstevel 		    socalp->port_state[port].sp_transport);
11663db86aabSstevel 		(void) sprintf((char *)name, "%x,0", port);
11673db86aabSstevel 		ddi_set_name_addr(child_dip, name);
11683db86aabSstevel 		break;
11693db86aabSstevel 	}
11703db86aabSstevel 
11713db86aabSstevel 	case DDI_CTLOPS_UNINITCHILD: {
11723db86aabSstevel 		dev_info_t	*child_dip = (dev_info_t *)a;
11733db86aabSstevel 		socal_state_t	*socalp;
11743db86aabSstevel 
11753db86aabSstevel 		socalp = ddi_get_driver_private(dip);
11763db86aabSstevel 		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11773db86aabSstevel 		    DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
11783db86aabSstevel 
11793db86aabSstevel 		if ((port < 0) || (port > 1)) {
11803db86aabSstevel 			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11813db86aabSstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11823db86aabSstevel 			if ((port < 0) || (port > 1)) {
11833db86aabSstevel 				return (DDI_NOT_WELL_FORMED);
11843db86aabSstevel 			}
11853db86aabSstevel 		}
11863db86aabSstevel 
11873db86aabSstevel 		ddi_set_parent_data(child_dip, NULL);
11883db86aabSstevel 		(void) ddi_set_name_addr(child_dip, NULL);
11893db86aabSstevel 		mutex_enter(&socalp->board_mtx);
11903db86aabSstevel 		mutex_enter(&socalp->port_state[port].sp_mtx);
11913db86aabSstevel 		socalp->socal_busy--;
11923db86aabSstevel 		socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
11933db86aabSstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
11943db86aabSstevel 		mutex_exit(&socalp->board_mtx);
11953db86aabSstevel 
11963db86aabSstevel 		break;
11973db86aabSstevel 	}
11983db86aabSstevel 
11993db86aabSstevel 	case DDI_CTLOPS_IOMIN: {
12003db86aabSstevel 		int val;
12013db86aabSstevel 
12023db86aabSstevel 		val = *((int *)v);
12033db86aabSstevel 		val = maxbit(val, socallim->dlim_minxfer);
12043db86aabSstevel 		/*
12053db86aabSstevel 		 * The 'arg' value of nonzero indicates 'streaming' mode.
12063db86aabSstevel 		 * If in streaming mode, pick the largest of our burstsizes
12073db86aabSstevel 		 * available and say that that is our minimum value (modulo
12083db86aabSstevel 		 * what minxfer is).
12093db86aabSstevel 		 */
12103db86aabSstevel 		if ((int)(uintptr_t)a) {
12113db86aabSstevel 			val = maxbit(val,
12123db86aabSstevel 			    1<<(ddi_fls(socallim->dlim_burstsizes)-1));
12133db86aabSstevel 		} else {
12143db86aabSstevel 			val = maxbit(val,
12153db86aabSstevel 			    1<<(ddi_ffs(socallim->dlim_burstsizes)-1));
12163db86aabSstevel 		}
12173db86aabSstevel 
12183db86aabSstevel 		*((int *)v) = val;
12193db86aabSstevel 		return (ddi_ctlops(dip, rip, op, a, v));
12203db86aabSstevel 	}
12213db86aabSstevel 
12223db86aabSstevel 	/*
12233db86aabSstevel 	 * These ops are not available on this nexus.
12243db86aabSstevel 	 */
12253db86aabSstevel 
12263db86aabSstevel 	case DDI_CTLOPS_DMAPMAPC:
12273db86aabSstevel 	case DDI_CTLOPS_REGSIZE:
12283db86aabSstevel 	case DDI_CTLOPS_NREGS:
12293db86aabSstevel 	case DDI_CTLOPS_AFFINITY:
12303db86aabSstevel 	case DDI_CTLOPS_SIDDEV:
12313db86aabSstevel 	case DDI_CTLOPS_POKE:
12323db86aabSstevel 	case DDI_CTLOPS_PEEK:
12333db86aabSstevel 		return (DDI_FAILURE);
12343db86aabSstevel 
12353db86aabSstevel 	case DDI_CTLOPS_SLAVEONLY:
12363db86aabSstevel 	case DDI_CTLOPS_REPORTINT:
12373db86aabSstevel 	default:
12383db86aabSstevel 		/*
12393db86aabSstevel 		 * Remaining requests get passed up to our parent
12403db86aabSstevel 		 */
12413db86aabSstevel 		DEBUGF(2, (CE_CONT, "%s%d: op (%d) from %s%d\n",
12423db86aabSstevel 		    ddi_get_name(dip), ddi_get_instance(dip),
12433db86aabSstevel 		    op, ddi_get_name(rip), ddi_get_instance(rip)));
12443db86aabSstevel 		return (ddi_ctlops(dip, rip, op, a, v));
12453db86aabSstevel 	}
12463db86aabSstevel 
12473db86aabSstevel 	return (DDI_SUCCESS);
12483db86aabSstevel }
12493db86aabSstevel 
12503db86aabSstevel 
12513db86aabSstevel /*ARGSUSED*/
12523db86aabSstevel /*
12533db86aabSstevel  * int
12543db86aabSstevel  * socal_getinfo() - Given the device number, return the devinfo
12553db86aabSstevel  * 	pointer or the instance number.  Note: this routine must be
12563db86aabSstevel  * 	successful on DDI_INFO_DEVT2INSTANCE even before attach.
12573db86aabSstevel  */
12583db86aabSstevel int
12593db86aabSstevel socal_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
12603db86aabSstevel 	void **result)
12613db86aabSstevel {
12623db86aabSstevel 	int instance;
12633db86aabSstevel 	socal_state_t *socalp;
12643db86aabSstevel 
12653db86aabSstevel 	instance = getminor((dev_t)arg) / 2;
12663db86aabSstevel 
12673db86aabSstevel 	switch (cmd) {
12683db86aabSstevel 	case DDI_INFO_DEVT2DEVINFO:
12693db86aabSstevel 		socalp = ddi_get_soft_state(socal_soft_state_p, instance);
12703db86aabSstevel 		if (socalp)
12713db86aabSstevel 			*result = socalp->dip;
12723db86aabSstevel 		else
12733db86aabSstevel 			*result = NULL;
12743db86aabSstevel 		break;
12753db86aabSstevel 
12763db86aabSstevel 	case DDI_INFO_DEVT2INSTANCE:
12773db86aabSstevel 		*result = (void *)(uintptr_t)instance;
12783db86aabSstevel 		break;
12793db86aabSstevel 
12803db86aabSstevel 	default:
12813db86aabSstevel 		return (DDI_FAILURE);
12823db86aabSstevel 	}
12833db86aabSstevel 
12843db86aabSstevel 	return (DDI_SUCCESS);
12853db86aabSstevel }
12863db86aabSstevel 
12873db86aabSstevel /*ARGSUSED*/
12883db86aabSstevel int
12893db86aabSstevel socal_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
12903db86aabSstevel {
12913db86aabSstevel 	int 	instance = getminor(*devp)/2;
12923db86aabSstevel 	socal_state_t	*socalp =
12933db86aabSstevel 	    ddi_get_soft_state(socal_soft_state_p, instance);
12943db86aabSstevel 	socal_port_t	*port_statep;
12953db86aabSstevel 	int		port;
12963db86aabSstevel 
12973db86aabSstevel 	if (socalp == NULL)
12983db86aabSstevel 		return (ENXIO);
12993db86aabSstevel 
13003db86aabSstevel 	port = getminor(*devp)%2;
13013db86aabSstevel 	port_statep = &socalp->port_state[port];
13023db86aabSstevel 
13033db86aabSstevel 	mutex_enter(&port_statep->sp_mtx);
13043db86aabSstevel 	port_statep->sp_status |= PORT_OPEN;
13053db86aabSstevel 	mutex_exit(&port_statep->sp_mtx);
13063db86aabSstevel 	DEBUGF(2, (CE_CONT,
13073db86aabSstevel 	    "socal%d: open of port %d\n", instance, port));
13083db86aabSstevel 	return (0);
13093db86aabSstevel }
13103db86aabSstevel 
13113db86aabSstevel /*ARGSUSED*/
13123db86aabSstevel int
13133db86aabSstevel socal_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
13143db86aabSstevel {
13153db86aabSstevel 	int 	instance = getminor(dev)/2;
13163db86aabSstevel 	socal_state_t	*socalp =
13173db86aabSstevel 	    ddi_get_soft_state(socal_soft_state_p, instance);
13183db86aabSstevel 	socal_port_t	*port_statep;
13193db86aabSstevel 	int		port;
13203db86aabSstevel 
13213db86aabSstevel 	port = getminor(dev)%2;
13223db86aabSstevel 	port_statep = &socalp->port_state[port];
13233db86aabSstevel 
13243db86aabSstevel 	mutex_enter(&port_statep->sp_mtx);
13253db86aabSstevel 	port_statep->sp_status &= ~PORT_OPEN;
13263db86aabSstevel 	mutex_exit(&port_statep->sp_mtx);
13273db86aabSstevel 	DEBUGF(2, (CE_CONT,
13283db86aabSstevel 	    "socal%d: clsoe of port %d\n", instance, port));
13293db86aabSstevel 	return (0);
13303db86aabSstevel }
13313db86aabSstevel 
13323db86aabSstevel /*ARGSUSED*/
13333db86aabSstevel int
13343db86aabSstevel socal_ioctl(dev_t dev,
13353db86aabSstevel     int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
13363db86aabSstevel {
13373db86aabSstevel 	int 	instance = getminor(dev)/2;
13383db86aabSstevel 	socal_state_t	*socalp =
13393db86aabSstevel 	    ddi_get_soft_state(socal_soft_state_p, instance);
13403db86aabSstevel 	int		port;
13413db86aabSstevel 	socal_port_t	*port_statep;
13423db86aabSstevel 	int 		i;
13433db86aabSstevel 	uint_t		r;
13443db86aabSstevel 	int		offset;
13453db86aabSstevel 	int 		retval = FCAL_SUCCESS;
13463db86aabSstevel 	la_els_adisc_t		*adisc_pl;
13473db86aabSstevel 	la_els_rls_reply_t	*rls_pl;
13483db86aabSstevel 	dev_info_t	*dip;
13493db86aabSstevel 	char		*buffer, tmp[10];
13503db86aabSstevel 	struct socal_fm_version ver;
13513db86aabSstevel #ifdef _MULTI_DATAMODEL
13523db86aabSstevel 	struct socal_fm_version32 {
13533db86aabSstevel 		uint_t	fcode_ver_len;
13543db86aabSstevel 		uint_t	mcode_ver_len;
13553db86aabSstevel 		uint_t	prom_ver_len;
13563db86aabSstevel 		caddr32_t	fcode_ver;
13573db86aabSstevel 		caddr32_t	mcode_ver;
13583db86aabSstevel 		caddr32_t	prom_ver;
13593db86aabSstevel 	} ver32;
13603db86aabSstevel 	uint_t		dm32 = 0;
13613db86aabSstevel #endif
13623db86aabSstevel 
13633db86aabSstevel 	uchar_t		*flb_pl;
13643db86aabSstevel 	flb_hdr_t	*flb_hdr;
13653db86aabSstevel 	uint_t		flb_size;
13663db86aabSstevel 
13673db86aabSstevel 	if (socalp == NULL)
13683db86aabSstevel 		return (ENXIO);
13693db86aabSstevel 
13703db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d ioctl: got command %x\n", instance, cmd));
13713db86aabSstevel 	port = getminor(dev)%2;
13723db86aabSstevel 
13733db86aabSstevel 	switch (cmd) {
13743db86aabSstevel 	case FCIO_FCODE_MCODE_VERSION:
13753db86aabSstevel #ifdef _MULTI_DATAMODEL
13763db86aabSstevel 		switch (ddi_model_convert_from(mode & FMODELS)) {
13773db86aabSstevel 			case DDI_MODEL_ILP32:
13783db86aabSstevel 				dm32 = 1;
13793db86aabSstevel 				if (ddi_copyin((caddr_t)arg,
13803db86aabSstevel 				    (caddr_t)&ver32, sizeof (ver32),
13813db86aabSstevel 				    mode) == -1)
13823db86aabSstevel 					return (EFAULT);
13833db86aabSstevel 				ver.fcode_ver_len =
13843db86aabSstevel 				    ver32.fcode_ver_len;
13853db86aabSstevel 				ver.mcode_ver_len =
13863db86aabSstevel 				    ver32.mcode_ver_len;
13873db86aabSstevel 				ver.prom_ver_len =
13883db86aabSstevel 				    ver32.prom_ver_len;
13893db86aabSstevel 				ver.fcode_ver =
13903db86aabSstevel 				    (caddr_t)(uintptr_t)ver32.fcode_ver;
13913db86aabSstevel 				ver.mcode_ver =
13923db86aabSstevel 				    (caddr_t)(uintptr_t)ver32.mcode_ver;
13933db86aabSstevel 				ver.prom_ver =
13943db86aabSstevel 				    (caddr_t)(uintptr_t)ver32.prom_ver;
13953db86aabSstevel 				break;
13963db86aabSstevel 			case DDI_MODEL_NONE:
13973db86aabSstevel 				if (ddi_copyin((caddr_t)arg,
13983db86aabSstevel 				    (caddr_t)&ver, sizeof (ver),
13993db86aabSstevel 				    mode) == -1)
14003db86aabSstevel 					return (EFAULT);
14013db86aabSstevel 		}
14023db86aabSstevel #else /* _MULTI_DATAMODEL */
14033db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ver,
14043db86aabSstevel 		    sizeof (ver), mode) == -1)
14053db86aabSstevel 			return (EFAULT);
14063db86aabSstevel #endif /* _MULTI_DATAMODEL */
14073db86aabSstevel 		dip = socalp->dip;
14083db86aabSstevel 		if (ddi_prop_op(DDI_DEV_T_ANY, dip,
14093db86aabSstevel 		    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
14103db86aabSstevel 		    DDI_PROP_CANSLEEP, "version", (caddr_t)&buffer,
14113db86aabSstevel 		    &i) != DDI_PROP_SUCCESS)
14123db86aabSstevel 			return (EIO);
14133db86aabSstevel 		if (i < ver.fcode_ver_len)
14143db86aabSstevel 			ver.fcode_ver_len = i;
14153db86aabSstevel 		if (ddi_copyout((caddr_t)buffer,
14163db86aabSstevel 		    (caddr_t)ver.fcode_ver, ver.fcode_ver_len,
14173db86aabSstevel 		    mode) == -1) {
14183db86aabSstevel 			kmem_free((caddr_t)buffer, i);
14193db86aabSstevel 			return (EFAULT);
14203db86aabSstevel 		}
14213db86aabSstevel 		kmem_free((caddr_t)buffer, i);
14223db86aabSstevel 		if (socalp->socal_eeprom) {
14233db86aabSstevel 			for (i = 0; i < SOCAL_N_CQS; i++) {
14243db86aabSstevel 				mutex_enter(
14253db86aabSstevel 				    &socalp->request[i].skc_mtx);
14263db86aabSstevel 				mutex_enter(
14273db86aabSstevel 				    &socalp->response[i].skc_mtx);
14283db86aabSstevel 			}
14293db86aabSstevel 			i = socalp->socal_rp->socal_cr.w;
14303db86aabSstevel 			socalp->socal_rp->socal_cr.w &=
14313db86aabSstevel 			    ~SOCAL_CR_EEPROM_BANK_MASK;
14323db86aabSstevel 			socalp->socal_rp->socal_cr.w |= 3 << 16;
14333db86aabSstevel 			if (ver.prom_ver_len > 10)
14343db86aabSstevel 				ver.prom_ver_len = 10;
14353db86aabSstevel 			bcopy((caddr_t)socalp->socal_eeprom + (unsigned)
14363db86aabSstevel 			    0xfff6, tmp, 10);
14373db86aabSstevel 			socalp->socal_rp->socal_cr.w  = i;
14383db86aabSstevel 			for (i = SOCAL_N_CQS-1; i >= 0; i--) {
14393db86aabSstevel 				mutex_exit(&socalp->request[i].skc_mtx);
14403db86aabSstevel 				mutex_exit(
14413db86aabSstevel 				    &socalp->response[i].skc_mtx);
14423db86aabSstevel 			}
14433db86aabSstevel 			if (ddi_copyout((caddr_t)tmp,
14443db86aabSstevel 			    (caddr_t)ver.prom_ver,
14453db86aabSstevel 			    ver.prom_ver_len, mode) == -1)
14463db86aabSstevel 				return (EFAULT);
14473db86aabSstevel 		} else {
14483db86aabSstevel 			ver.prom_ver_len = 0;
14493db86aabSstevel 		}
14503db86aabSstevel 		ver.mcode_ver_len = 0;
14513db86aabSstevel #ifdef _MULTI_DATAMODEL
14523db86aabSstevel 		if (dm32) {
14533db86aabSstevel 			ver32.fcode_ver_len = ver.fcode_ver_len;
14543db86aabSstevel 			ver32.mcode_ver_len = ver.mcode_ver_len;
14553db86aabSstevel 			ver32.prom_ver_len = ver.prom_ver_len;
14563db86aabSstevel 			ver32.fcode_ver = (caddr32_t)(uintptr_t)
14573db86aabSstevel 			    ver.fcode_ver;
14583db86aabSstevel 			ver32.mcode_ver = (caddr32_t)(uintptr_t)
14593db86aabSstevel 			    ver.mcode_ver;
14603db86aabSstevel 			ver32.prom_ver = (caddr32_t)(uintptr_t)
14613db86aabSstevel 			    ver.prom_ver;
14623db86aabSstevel 			if (ddi_copyout((caddr_t)&ver32,
14633db86aabSstevel 			    (caddr_t)arg, sizeof (ver32),
14643db86aabSstevel 			    mode) == -1)
14653db86aabSstevel 				return (EFAULT);
14663db86aabSstevel 		} else
14673db86aabSstevel #endif /* _MULTI_DATAMODEL */
14683db86aabSstevel 		if (ddi_copyout((caddr_t)&ver, (caddr_t)arg,
14693db86aabSstevel 		    sizeof (struct socal_fm_version), mode) == -1)
14703db86aabSstevel 			return (EFAULT);
14713db86aabSstevel 		break;
14723db86aabSstevel 	case FCIO_LOADUCODE:
14733db86aabSstevel 		mutex_enter(&socalp->k_imr_mtx);
14743db86aabSstevel 		socal_disable(socalp);
14753db86aabSstevel 		mutex_exit(&socalp->k_imr_mtx);
14763db86aabSstevel 		if (copyin((caddr_t)arg, (caddr_t)socal_ucode, 0x10000)
14773db86aabSstevel 		    == -1)
14783db86aabSstevel 			return (EFAULT);
14793db86aabSstevel 		/* restart socal after resetting */
14803db86aabSstevel 		(void) socal_force_reset((void *)socalp, 0,
14813db86aabSstevel 		    RESET_PORT);
14823db86aabSstevel 		break;
14833db86aabSstevel 	case FCIO_DUMPXRAM:
14843db86aabSstevel 		for (i = 0; i < SOCAL_N_CQS; i++) {
14853db86aabSstevel 			mutex_enter(&socalp->request[i].skc_mtx);
14863db86aabSstevel 			mutex_enter(&socalp->response[i].skc_mtx);
14873db86aabSstevel 		}
14883db86aabSstevel 		for (i = 0; i < 4; i++) {
14893db86aabSstevel 			offset = arg+(0x10000 * i);
14903db86aabSstevel 			socalp->socal_rp->socal_cr.w &=
14913db86aabSstevel 			    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
14923db86aabSstevel 			socalp->socal_rp->socal_cr.w |= i<<24;
14933db86aabSstevel 			(void) copyout((caddr_t)socalp->socal_xrp,
14943db86aabSstevel 			    (caddr_t)(uintptr_t)offset, 0x10000);
14953db86aabSstevel 		}
14963db86aabSstevel 		socalp->socal_rp->socal_cr.w &=
14973db86aabSstevel 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
14983db86aabSstevel 		for (i = SOCAL_N_CQS-1; i >= 0; i--) {
14993db86aabSstevel 			mutex_exit(&socalp->request[i].skc_mtx);
15003db86aabSstevel 			mutex_exit(&socalp->response[i].skc_mtx);
15013db86aabSstevel 		}
15023db86aabSstevel 		break;
15033db86aabSstevel #ifdef DEBUG
15043db86aabSstevel 	case FCIO_DUMPXRAMBUF:
15053db86aabSstevel 		(void) copyout((caddr_t)socal_xrambuf, (caddr_t)arg,
15063db86aabSstevel 		    0x40000);
15073db86aabSstevel 		break;
15083db86aabSstevel #endif
15093db86aabSstevel 	case FCIO_GETMAP:
15103db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
15113db86aabSstevel 		if (socal_getmap(socalp, port, (caddr_t)arg, 0, 0) ==
15123db86aabSstevel 		    -1)
15133db86aabSstevel 			retval = FCAL_ALLOC_FAILED;
15143db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15153db86aabSstevel 		break;
15163db86aabSstevel 	case FCIO_BYPASS_DEV:
15173db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
15183db86aabSstevel 		retval = socal_bypass_dev((void *)socalp, port, arg);
15193db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15203db86aabSstevel 		break;
15213db86aabSstevel 	case FCIO_FORCE_LIP:
15223db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
15233db86aabSstevel 		retval = socal_force_lip((void *)socalp, port, 0,
15243db86aabSstevel 		    FCAL_FORCE_LIP);
15253db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15263db86aabSstevel 		break;
15273db86aabSstevel 	case FCIO_FORCE_OFFLINE:
15283db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
15293db86aabSstevel 		retval = socal_force_offline((void *)socalp, port, 0);
15303db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15313db86aabSstevel 		break;
15323db86aabSstevel 	case FCIO_ADISC_ELS:
15333db86aabSstevel 	{
15343db86aabSstevel 		if ((adisc_pl =
153519397407SSherry Moore 		    (la_els_adisc_t *)kmem_zalloc(
153619397407SSherry Moore 		    sizeof (la_els_adisc_t),
15373db86aabSstevel 		    KM_NOSLEEP)) == NULL)
15383db86aabSstevel 			return (ENOMEM);
15393db86aabSstevel 
15403db86aabSstevel 		if (copyin((caddr_t)arg, (caddr_t)adisc_pl,
15413db86aabSstevel 		    sizeof (la_els_adisc_t)) == -1) {
154219397407SSherry Moore 			kmem_free((void *)adisc_pl,
154319397407SSherry Moore 			    sizeof (la_els_adisc_t));
15443db86aabSstevel 			return (EFAULT);
15453db86aabSstevel 		}
15463db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
154719397407SSherry Moore 		retval = socal_issue_adisc(socalp, port,
154819397407SSherry Moore 		    adisc_pl->nport_id,
15493db86aabSstevel 		    adisc_pl, 0);
15503db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15513db86aabSstevel 
15523db86aabSstevel 		if (retval == FCAL_SUCCESS) {
15533db86aabSstevel 		if (copyout((caddr_t)adisc_pl, (caddr_t)arg,
15543db86aabSstevel 		    sizeof (la_els_adisc_t)) == -1) {
15553db86aabSstevel 			kmem_free((void *)adisc_pl,
15563db86aabSstevel 			    sizeof (la_els_adisc_t));
15573db86aabSstevel 			return (EFAULT);
15583db86aabSstevel 		}
15593db86aabSstevel 		}
15603db86aabSstevel 
15613db86aabSstevel 		kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
15623db86aabSstevel 		break;
15633db86aabSstevel 	}
15643db86aabSstevel 	case FCIO_LINKSTATUS:
15653db86aabSstevel 	{
15663db86aabSstevel 		int dest;
15673db86aabSstevel 		if ((rls_pl =
15683db86aabSstevel 		    (la_els_rls_reply_t *)
15693db86aabSstevel 		    kmem_zalloc(sizeof (la_els_rls_reply_t),
15703db86aabSstevel 		    KM_NOSLEEP)) == NULL)
15713db86aabSstevel 			return (ENOMEM);
15723db86aabSstevel 
15733db86aabSstevel 		if (copyin((caddr_t)arg, (caddr_t)rls_pl,
15743db86aabSstevel 		    sizeof (la_els_rls_reply_t)) == -1) {
157519397407SSherry Moore 			kmem_free((void *)rls_pl,
157619397407SSherry Moore 			    sizeof (la_els_rls_reply_t));
15773db86aabSstevel 		return (EFAULT);
15783db86aabSstevel 		}
15793db86aabSstevel 		dest = (rls_pl->mbz[0] << 16) + (rls_pl->mbz[1] << 8) +
15803db86aabSstevel 		    rls_pl->mbz[2];
15813db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
15823db86aabSstevel 		retval = socal_issue_rls(socalp, port, dest,
15833db86aabSstevel 		    rls_pl, 0);
15843db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
15853db86aabSstevel 
15863db86aabSstevel 		if (retval == FCAL_SUCCESS) {
15873db86aabSstevel 		if (copyout((caddr_t)rls_pl, (caddr_t)arg,
15883db86aabSstevel 		    sizeof (la_els_rls_reply_t)) == -1) {
15893db86aabSstevel 			kmem_free((void *)rls_pl,
15903db86aabSstevel 			    sizeof (la_els_rls_reply_t));
15913db86aabSstevel 			return (EFAULT);
15923db86aabSstevel 		}
15933db86aabSstevel 		}
15943db86aabSstevel 		kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
15953db86aabSstevel 		break;
15963db86aabSstevel 	}
15973db86aabSstevel 	case FCIO_LOOPBACK_INTERNAL:
15983db86aabSstevel 		/*
15993db86aabSstevel 		 * If userland doesn't provide a location for a return
16003db86aabSstevel 		 * value the driver will permanently offline the port,
16013db86aabSstevel 		 * ignoring any checks for devices on the loop.
16023db86aabSstevel 		 */
16033db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16043db86aabSstevel 		if (arg == 0) {
16053db86aabSstevel 			port_statep = &socalp->port_state[port];
16063db86aabSstevel 			mutex_enter(&port_statep->sp_mtx);
16073db86aabSstevel 			if (port_statep->sp_status & PORT_DISABLED) {
16083db86aabSstevel 				/* Already disabled */
16093db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
16103db86aabSstevel 				mutex_exit(&socalp->ioctl_mtx);
16113db86aabSstevel 				return (EALREADY);
16123db86aabSstevel 			}
16133db86aabSstevel 			port_statep->sp_status |= PORT_DISABLED;
16143db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
16153db86aabSstevel 		}
16163db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16173db86aabSstevel 		    SOC_DIAG_INT_LOOP);
16183db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16193db86aabSstevel 		if (arg == 0) break;
16203db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16213db86aabSstevel 		    == -1)
16223db86aabSstevel 			return (EFAULT);
16233db86aabSstevel 		break;
16243db86aabSstevel 	case FCIO_LOOPBACK_MANUAL:
16253db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16263db86aabSstevel 		port_statep = &socalp->port_state[port];
16273db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
16283db86aabSstevel 		if (port_statep->sp_status & PORT_DISABLED) {
16293db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
16303db86aabSstevel 			mutex_exit(&socalp->ioctl_mtx);
16313db86aabSstevel 			return (EBUSY);
16323db86aabSstevel 		}
16333db86aabSstevel 		mutex_exit(&port_statep->sp_mtx);
16343db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16353db86aabSstevel 		    SOC_DIAG_EXT_LOOP);
16363db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16373db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16383db86aabSstevel 		    == -1)
16393db86aabSstevel 			return (EFAULT);
16403db86aabSstevel 		break;
16413db86aabSstevel 	case FCIO_NO_LOOPBACK:
16423db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16433db86aabSstevel 		port_statep = &socalp->port_state[port];
16443db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
16453db86aabSstevel 		/* Do not allow online if we're disabled */
16463db86aabSstevel 		if (port_statep->sp_status & PORT_DISABLED) {
16473db86aabSstevel 			if (arg != 0) {
16483db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
16493db86aabSstevel 				mutex_exit(&socalp->ioctl_mtx);
16503db86aabSstevel 				/*
16513db86aabSstevel 				 * It's permanently disabled -- Need to
16523db86aabSstevel 				 * enable it first
16533db86aabSstevel 				 */
16543db86aabSstevel 				return (EBUSY);
16553db86aabSstevel 			}
16563db86aabSstevel 			/* This was a request to online. */
16573db86aabSstevel 			port_statep->sp_status &= ~PORT_DISABLED;
16583db86aabSstevel 		}
16593db86aabSstevel 		mutex_exit(&port_statep->sp_mtx);
16603db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16613db86aabSstevel 		    SOC_DIAG_REM_LOOP);
16623db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16633db86aabSstevel 		if (arg == 0) break;
16643db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16653db86aabSstevel 		    == -1)
16663db86aabSstevel 			return (EFAULT);
16673db86aabSstevel 		break;
16683db86aabSstevel 	case FCIO_DIAG_NOP:
16693db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16703db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16713db86aabSstevel 		    SOC_DIAG_NOP);
16723db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16733db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16743db86aabSstevel 		    == -1)
16753db86aabSstevel 			return (EFAULT);
16763db86aabSstevel 		break;
16773db86aabSstevel 	case FCIO_DIAG_XRAM:
16783db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16793db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16803db86aabSstevel 		    SOC_DIAG_XRAM_TEST);
16813db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16823db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16833db86aabSstevel 		    == -1)
16843db86aabSstevel 			return (EFAULT);
16853db86aabSstevel 		break;
16863db86aabSstevel 	case FCIO_DIAG_SOC:
16873db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16883db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16893db86aabSstevel 		    SOC_DIAG_SOC_TEST);
16903db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
16913db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
16923db86aabSstevel 		    == -1)
16933db86aabSstevel 			return (EFAULT);
16943db86aabSstevel 		break;
16953db86aabSstevel 	case FCIO_DIAG_HCB:
16963db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
16973db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
16983db86aabSstevel 		    SOC_DIAG_HCB_TEST);
16993db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17003db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
17013db86aabSstevel 		    == -1)
17023db86aabSstevel 			return (EFAULT);
17033db86aabSstevel 		break;
17043db86aabSstevel 	case FCIO_DIAG_SOCLB:
17053db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
17063db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
17073db86aabSstevel 		    SOC_DIAG_SOCLB_TEST);
17083db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17093db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
17103db86aabSstevel 		    == -1)
17113db86aabSstevel 			return (EFAULT);
17123db86aabSstevel 		break;
17133db86aabSstevel 	case FCIO_DIAG_SRDSLB:
17143db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
17153db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
17163db86aabSstevel 		    SOC_DIAG_SRDSLB_TEST);
17173db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17183db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
17193db86aabSstevel 		    == -1)
17203db86aabSstevel 			return (EFAULT);
17213db86aabSstevel 		break;
17223db86aabSstevel 	case FCIO_DIAG_EXTLB:
17233db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
17243db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
17253db86aabSstevel 		    SOC_DIAG_EXTOE_TEST);
17263db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17273db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
17283db86aabSstevel 		    == -1)
17293db86aabSstevel 			return (EFAULT);
17303db86aabSstevel 		break;
17313db86aabSstevel 	case FCIO_DIAG_RAW:
17323db86aabSstevel 		if (copyin((caddr_t)arg, (caddr_t)&i, sizeof (uint_t))
17333db86aabSstevel 		    == -1)
17343db86aabSstevel 			return (EFAULT);
17353db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
17363db86aabSstevel 		retval = socal_diag_request((void *)socalp, port, &r,
17373db86aabSstevel 		    (uint_t)i);
17383db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17393db86aabSstevel 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
17403db86aabSstevel 		    == -1)
17413db86aabSstevel 			return (EFAULT);
17423db86aabSstevel 		break;
17433db86aabSstevel 	case FCIO_LOOPBACK_FRAME:
17443db86aabSstevel 		if ((flb_hdr = (flb_hdr_t *)kmem_zalloc(sizeof (flb_hdr_t),
17453db86aabSstevel 		    KM_NOSLEEP)) == NULL)
17463db86aabSstevel 			return (ENOMEM);
17473db86aabSstevel 
17483db86aabSstevel 		if (copyin((caddr_t)arg,
17493db86aabSstevel 		    (caddr_t)flb_hdr, sizeof (flb_hdr_t)) == -1) {
17503db86aabSstevel 		kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
17513db86aabSstevel 		return (EFAULT);
17523db86aabSstevel 		}
17533db86aabSstevel 
17543db86aabSstevel 		flb_size = flb_hdr->length;
17553db86aabSstevel 
17563db86aabSstevel 		if ((flb_pl =
17573db86aabSstevel 		    (uchar_t *)kmem_zalloc(flb_size, KM_NOSLEEP)) == NULL)
17583db86aabSstevel 			return (ENOMEM);
17593db86aabSstevel 
17603db86aabSstevel 		if (copyin((caddr_t)(arg + sizeof (flb_hdr_t)),
17613db86aabSstevel 		    (caddr_t)flb_pl, flb_size) == -1) {
17623db86aabSstevel 			kmem_free((void *)flb_pl, flb_size);
17633db86aabSstevel 			return (EFAULT);
17643db86aabSstevel 		}
17653db86aabSstevel 		mutex_enter(&socalp->ioctl_mtx);
17663db86aabSstevel 		retval = socal_issue_lbf(socalp, port, flb_pl,
17673db86aabSstevel 		    flb_size, 1);
17683db86aabSstevel 		mutex_exit(&socalp->ioctl_mtx);
17693db86aabSstevel 
17703db86aabSstevel 		if (retval == FCAL_SUCCESS) {
17713db86aabSstevel 		if (copyout((caddr_t)flb_pl,
17723db86aabSstevel 		    (caddr_t)(arg + sizeof (flb_hdr_t) +
17733db86aabSstevel 		    flb_hdr->max_length), flb_size) == -1) {
17743db86aabSstevel 			kmem_free((void *)flb_pl, flb_size);
17753db86aabSstevel 			kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
17763db86aabSstevel 			return (EFAULT);
17773db86aabSstevel 		}
17783db86aabSstevel 		}
17793db86aabSstevel 
17803db86aabSstevel 		kmem_free((void *)flb_pl, flb_size);
17813db86aabSstevel 		kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
17823db86aabSstevel 		break;
17833db86aabSstevel 	default:
17843db86aabSstevel 		return (ENOTTY);
17853db86aabSstevel 
17863db86aabSstevel 	}
17873db86aabSstevel 	switch (retval) {
17883db86aabSstevel 		case FCAL_SUCCESS:
17893db86aabSstevel 			return (0);
17903db86aabSstevel 		case FCAL_ALLOC_FAILED:
17913db86aabSstevel 			return (ENOMEM);
17923db86aabSstevel 		case FCAL_STATUS_DIAG_BUSY:
17933db86aabSstevel 			return (EALREADY);
17943db86aabSstevel 		case FCAL_STATUS_DIAG_INVALID:
17953db86aabSstevel 			return (EINVAL);
17963db86aabSstevel 		default:
17973db86aabSstevel 			return (EIO);
17983db86aabSstevel 	}
17993db86aabSstevel 
18003db86aabSstevel }
18013db86aabSstevel 
18023db86aabSstevel /*
18033db86aabSstevel  * Function name : socal_disable()
18043db86aabSstevel  *
18053db86aabSstevel  * Return Values :  none
18063db86aabSstevel  *
18073db86aabSstevel  * Description	 : Reset the soc+
18083db86aabSstevel  *
18093db86aabSstevel  * Context	 : Can be called from different kernel process threads.
18103db86aabSstevel  *		   Can be called by interrupt thread.
18113db86aabSstevel  *
18123db86aabSstevel  * Note:  before calling this, the interface should be locked down
18133db86aabSstevel  * so that it is guaranteed that no other threads are accessing
18143db86aabSstevel  * the hardware.
18153db86aabSstevel  */
18163db86aabSstevel static	void
18173db86aabSstevel socal_disable(socal_state_t *socalp)
18183db86aabSstevel {
18193db86aabSstevel #if !defined(lint)
18203db86aabSstevel 	int i;
18213db86aabSstevel #endif
18223db86aabSstevel 	/* Don't touch the hardware if the registers aren't mapped */
18233db86aabSstevel 	if (!socalp->socal_rp)
18243db86aabSstevel 		return;
18253db86aabSstevel 
18263db86aabSstevel 	socalp->socal_rp->socal_imr = socalp->socal_k_imr = 0;
18273db86aabSstevel 	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOFT_RESET;
18283db86aabSstevel #if !defined(lint)
18293db86aabSstevel 	i = socalp->socal_rp->socal_csr.w;
18303db86aabSstevel #endif
18313db86aabSstevel 	DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
18323db86aabSstevel }
18333db86aabSstevel 
18343db86aabSstevel /*
18353db86aabSstevel  * Function name : socal_init_transport_interface()
18363db86aabSstevel  *
18373db86aabSstevel  * Return Values :  none
18383db86aabSstevel  *
18393db86aabSstevel  * Description	 : Fill up the fcal_tranpsort struct for ULPs
18403db86aabSstevel  *
18413db86aabSstevel  *
18423db86aabSstevel  * Note:  Only called during attach, so no protection
18433db86aabSstevel  */
18443db86aabSstevel static void
18453db86aabSstevel socal_init_transport_interface(socal_state_t *socalp)
18463db86aabSstevel {
18473db86aabSstevel 	int			i;
18483db86aabSstevel 	fcal_transport_t	*xport;
18493db86aabSstevel 
18503db86aabSstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
18513db86aabSstevel 		xport = socalp->port_state[i].sp_transport;
18523db86aabSstevel 		mutex_init(&xport->fcal_mtx, NULL, MUTEX_DRIVER,
18533db86aabSstevel 		    (void *)(socalp->iblkc));
18543db86aabSstevel 
18553db86aabSstevel 		cv_init(&xport->fcal_cv, NULL, CV_DRIVER, NULL);
18563db86aabSstevel 
18573db86aabSstevel 		xport->fcal_handle = (void *)socalp;
18583db86aabSstevel 		xport->fcal_dmalimp = socallim;
18593db86aabSstevel 		xport->fcal_iblock = socalp->iblkc;
18603db86aabSstevel 		xport->fcal_dmaattr = &socal_dma_attr;
18613db86aabSstevel 		xport->fcal_accattr = &socal_acc_attr;
18623db86aabSstevel 		xport->fcal_loginparms = socalp->socal_service_params;
18633db86aabSstevel 		bcopy((caddr_t)&socalp->socal_n_wwn,
18643db86aabSstevel 		    (caddr_t)&xport->fcal_n_wwn, sizeof (la_wwn_t));
18653db86aabSstevel 		bcopy((caddr_t)&socalp->port_state[i].sp_p_wwn,
18663db86aabSstevel 		    (caddr_t)&xport->fcal_p_wwn, sizeof (la_wwn_t));
18673db86aabSstevel 		xport->fcal_portno = i;
18683db86aabSstevel 		xport->fcal_cmdmax = SOCAL_MAX_XCHG;
18693db86aabSstevel 		xport->fcal_ops = &socal_transport_ops;
18703db86aabSstevel 	}
18713db86aabSstevel }
18723db86aabSstevel 
18733db86aabSstevel /*
18743db86aabSstevel  * static int
18753db86aabSstevel  * socal_cqalloc_init() - Inialize the circular queue tables.
18763db86aabSstevel  *	Also, init the locks that are associated with the tables.
18773db86aabSstevel  *
18783db86aabSstevel  *	Returns:	FCAL_SUCCESS, if able to init properly.
18793db86aabSstevel  *			FCAL_FAILURE, if unable to init properly.
18803db86aabSstevel  */
18813db86aabSstevel 
18823db86aabSstevel static int
18833db86aabSstevel socal_cqalloc_init(socal_state_t *socalp, uint32_t index)
18843db86aabSstevel {
18853db86aabSstevel 	uint32_t cq_size;
18863db86aabSstevel 	size_t real_len;
18873db86aabSstevel 	uint_t ccount;
18883db86aabSstevel 	socal_kcq_t *cqp;
18893db86aabSstevel 	int	req_bound = 0, rsp_bound = 0;
18903db86aabSstevel 
18913db86aabSstevel 	/*
18923db86aabSstevel 	 * Initialize the Request and Response Queue locks.
18933db86aabSstevel 	 */
18943db86aabSstevel 
18953db86aabSstevel 	mutex_init(&socalp->request[index].skc_mtx, NULL, MUTEX_DRIVER,
18963db86aabSstevel 	    (void *)socalp->iblkc);
18973db86aabSstevel 	mutex_init(&socalp->response[index].skc_mtx, NULL, MUTEX_DRIVER,
18983db86aabSstevel 	    (void *)socalp->iblkc);
18993db86aabSstevel 	cv_init(&socalp->request[index].skc_cv, NULL, CV_DRIVER, NULL);
19003db86aabSstevel 	cv_init(&socalp->response[index].skc_cv, NULL, CV_DRIVER, NULL);
19013db86aabSstevel 
19023db86aabSstevel 	/* Allocate DVMA resources for the Request Queue. */
19033db86aabSstevel 	cq_size = socal_req_entries[index] * sizeof (cqe_t);
19043db86aabSstevel 	if (cq_size) {
19053db86aabSstevel 		cqp = &socalp->request[index];
19063db86aabSstevel 
19073db86aabSstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
19083db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL,
19093db86aabSstevel 		    &cqp->skc_dhandle) != DDI_SUCCESS) {
19103db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4020",
19113db86aabSstevel 			    "!alloc of dma handle failed");
19123db86aabSstevel 			goto fail;
19133db86aabSstevel 		}
19143db86aabSstevel 
19153db86aabSstevel 		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
19163db86aabSstevel 		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
19173db86aabSstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
19183db86aabSstevel 		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
19193db86aabSstevel 		    &cqp->skc_acchandle) != DDI_SUCCESS) {
19203db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4030",
19213db86aabSstevel 			    "!alloc of dma space failed");
19223db86aabSstevel 				goto fail;
19233db86aabSstevel 		}
19243db86aabSstevel 
19253db86aabSstevel 		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
19263db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4035",
19273db86aabSstevel 			    "!alloc of dma space failed");
19283db86aabSstevel 			goto fail;
19293db86aabSstevel 		}
19303db86aabSstevel 		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
19313db86aabSstevel 		    (uintptr_t)SOCAL_CQ_ALIGN - 1) &
19323db86aabSstevel 		    ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
19333db86aabSstevel 
19343db86aabSstevel 		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
19353db86aabSstevel 		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
19363db86aabSstevel 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
19373db86aabSstevel 		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
19383db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4040",
19393db86aabSstevel 			    "!bind of dma handle failed");
19403db86aabSstevel 			goto fail;
19413db86aabSstevel 		}
19423db86aabSstevel 
19433db86aabSstevel 		req_bound = 1;
19443db86aabSstevel 		if (ccount != 1) {
19453db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4045",
19463db86aabSstevel 			    "!bind of dma handle failed");
19473db86aabSstevel 			goto fail;
19483db86aabSstevel 		}
19493db86aabSstevel 
19503db86aabSstevel 	} else {
19513db86aabSstevel 		socalp->request[index].skc_cq_raw = NULL;
19523db86aabSstevel 		socalp->request[index].skc_cq = (cqe_t *)NULL;
19533db86aabSstevel 		socalp->request[index].skc_dhandle = 0;
19543db86aabSstevel 	}
19553db86aabSstevel 
19563db86aabSstevel 	/* Allocate DVMA resources for the response Queue. */
19573db86aabSstevel 	cq_size = socal_rsp_entries[index] * sizeof (cqe_t);
19583db86aabSstevel 	if (cq_size) {
19593db86aabSstevel 		cqp = &socalp->response[index];
19603db86aabSstevel 
19613db86aabSstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
19623db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL,
19633db86aabSstevel 		    &cqp->skc_dhandle) != DDI_SUCCESS) {
19643db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4050",
19653db86aabSstevel 			    "!alloc of dma handle failed");
19663db86aabSstevel 			goto fail;
19673db86aabSstevel 		}
19683db86aabSstevel 
19693db86aabSstevel 		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
19703db86aabSstevel 		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
19713db86aabSstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
19723db86aabSstevel 		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
19733db86aabSstevel 		    &cqp->skc_acchandle) != DDI_SUCCESS) {
19743db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4060",
19753db86aabSstevel 			    "!alloc of dma space failed");
19763db86aabSstevel 				goto fail;
19773db86aabSstevel 		}
19783db86aabSstevel 
19793db86aabSstevel 		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
19803db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4065",
19813db86aabSstevel 			    "!alloc of dma space failed");
19823db86aabSstevel 			goto fail;
19833db86aabSstevel 		}
19843db86aabSstevel 
19853db86aabSstevel 		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
19863db86aabSstevel 		    (uintptr_t)SOCAL_CQ_ALIGN - 1) &
19873db86aabSstevel 		    ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
19883db86aabSstevel 
19893db86aabSstevel 		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
19903db86aabSstevel 		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
19913db86aabSstevel 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
19923db86aabSstevel 		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
19933db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4070",
19943db86aabSstevel 			    "!bind of dma handle failed");
19953db86aabSstevel 			goto fail;
19963db86aabSstevel 		}
19973db86aabSstevel 
19983db86aabSstevel 		rsp_bound = 1;
19993db86aabSstevel 		if (ccount != 1) {
20003db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4075",
20013db86aabSstevel 			    "!bind of dma handle failed");
20023db86aabSstevel 			goto fail;
20033db86aabSstevel 		}
20043db86aabSstevel 
20053db86aabSstevel 	} else {
20063db86aabSstevel 		socalp->response[index].skc_cq_raw = NULL;
20073db86aabSstevel 		socalp->response[index].skc_cq = (cqe_t *)NULL;
20083db86aabSstevel 		socalp->response[index].skc_dhandle = 0;
20093db86aabSstevel 	}
20103db86aabSstevel 
20113db86aabSstevel 	/*
20123db86aabSstevel 	 * Initialize the queue pointers
20133db86aabSstevel 	 */
20143db86aabSstevel 	socal_cqinit(socalp, index);
20153db86aabSstevel 
20163db86aabSstevel 	return (FCAL_SUCCESS);
20173db86aabSstevel fail:
20183db86aabSstevel 	if (socalp->request[index].skc_dhandle) {
20193db86aabSstevel 		if (req_bound)
20203db86aabSstevel 			(void) ddi_dma_unbind_handle(socalp->
20213db86aabSstevel 			    request[index].skc_dhandle);
20223db86aabSstevel 		ddi_dma_free_handle(&socalp->request[index].skc_dhandle);
20233db86aabSstevel 	}
20243db86aabSstevel 	if (socalp->request[index].skc_cq_raw)
20253db86aabSstevel 		ddi_dma_mem_free(&socalp->request[index].skc_acchandle);
20263db86aabSstevel 
20273db86aabSstevel 	if (socalp->response[index].skc_dhandle) {
20283db86aabSstevel 		if (rsp_bound)
20293db86aabSstevel 			(void) ddi_dma_unbind_handle(socalp->
20303db86aabSstevel 			    response[index].skc_dhandle);
20313db86aabSstevel 		ddi_dma_free_handle(&socalp->response[index].skc_dhandle);
20323db86aabSstevel 	}
20333db86aabSstevel 	if (socalp->response[index].skc_cq_raw)
20343db86aabSstevel 		ddi_dma_mem_free(&socalp->response[index].skc_acchandle);
20353db86aabSstevel 
20363db86aabSstevel 	socalp->request[index].skc_dhandle = NULL;
20373db86aabSstevel 	socalp->response[index].skc_dhandle = NULL;
20383db86aabSstevel 	socalp->request[index].skc_cq_raw = NULL;
20393db86aabSstevel 	socalp->request[index].skc_cq = NULL;
20403db86aabSstevel 	socalp->response[index].skc_cq_raw = NULL;
20413db86aabSstevel 	socalp->response[index].skc_cq = NULL;
20423db86aabSstevel 	mutex_destroy(&socalp->request[index].skc_mtx);
20433db86aabSstevel 	mutex_destroy(&socalp->response[index].skc_mtx);
20443db86aabSstevel 	cv_destroy(&socalp->request[index].skc_cv);
20453db86aabSstevel 	cv_destroy(&socalp->response[index].skc_cv);
20463db86aabSstevel 	return (FCAL_FAILURE);
20473db86aabSstevel 
20483db86aabSstevel }
20493db86aabSstevel 
20503db86aabSstevel /*
20513db86aabSstevel  * socal_cqinit() - initializes the driver's circular queue pointers, etc.
20523db86aabSstevel  */
20533db86aabSstevel 
20543db86aabSstevel static void
20553db86aabSstevel socal_cqinit(socal_state_t *socalp, uint32_t index)
20563db86aabSstevel {
20573db86aabSstevel 	socal_kcq_t *kcq_req = &socalp->request[index];
20583db86aabSstevel 	socal_kcq_t *kcq_rsp = &socalp->response[index];
20593db86aabSstevel 
20603db86aabSstevel 	/*
20613db86aabSstevel 	 * Initialize the Request and Response Queue pointers
20623db86aabSstevel 	 */
20633db86aabSstevel 	kcq_req->skc_seqno = 1;
20643db86aabSstevel 	kcq_rsp->skc_seqno = 1;
20653db86aabSstevel 	kcq_req->skc_in = 0;
20663db86aabSstevel 	kcq_rsp->skc_in = 0;
20673db86aabSstevel 	kcq_req->skc_out = 0;
20683db86aabSstevel 	kcq_rsp->skc_out = 0;
20693db86aabSstevel 	kcq_req->skc_last_index = socal_req_entries[index] - 1;
20703db86aabSstevel 	kcq_rsp->skc_last_index = socal_rsp_entries[index] - 1;
20713db86aabSstevel 	kcq_req->skc_full = 0;
20723db86aabSstevel 	kcq_rsp->deferred_intr_timeoutid = 0;
20733db86aabSstevel 	kcq_req->skc_socalp = socalp;
20743db86aabSstevel 	kcq_rsp->skc_socalp = socalp;
20753db86aabSstevel 
20763db86aabSstevel 	kcq_req->skc_xram_cqdesc =
20773db86aabSstevel 	    (socalp->xram_reqp + (index * sizeof (struct cq))/8);
20783db86aabSstevel 	kcq_rsp->skc_xram_cqdesc =
20793db86aabSstevel 	    (socalp->xram_rspp + (index * sizeof (struct cq))/8);
20803db86aabSstevel 
20813db86aabSstevel 	/*  Clear out memory we have allocated */
20823db86aabSstevel 	if (kcq_req->skc_cq != NULL)
20833db86aabSstevel 		bzero((caddr_t)kcq_req->skc_cq,
20843db86aabSstevel 		    socal_req_entries[index] * sizeof (cqe_t));
20853db86aabSstevel 	if (kcq_rsp->skc_cq != NULL)
20863db86aabSstevel 		bzero((caddr_t)kcq_rsp->skc_cq,
20873db86aabSstevel 		    socal_rsp_entries[index] * sizeof (cqe_t));
20883db86aabSstevel }
20893db86aabSstevel 
20903db86aabSstevel 
20913db86aabSstevel static int
20923db86aabSstevel socal_start(socal_state_t *socalp)
20933db86aabSstevel {
20943db86aabSstevel 	uint_t r;
20953db86aabSstevel 
20963db86aabSstevel 	if (!socalp)
20973db86aabSstevel 		return (FCAL_FAILURE);
20983db86aabSstevel 
20993db86aabSstevel 	socal_download_ucode(socalp);
21003db86aabSstevel 	socal_init_cq_desc(socalp);
21013db86aabSstevel 	socal_init_wwn(socalp);
21023db86aabSstevel 
21033db86aabSstevel 	mutex_enter(&socalp->port_state[0].sp_mtx);
21043db86aabSstevel 	socalp->port_state[0].sp_status
21053db86aabSstevel 	    &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
21063db86aabSstevel 	socalp->port_state[0].sp_status |= PORT_OFFLINE;
21073db86aabSstevel 	mutex_exit(&socalp->port_state[0].sp_mtx);
21083db86aabSstevel 
21093db86aabSstevel 	mutex_enter(&socalp->port_state[1].sp_mtx);
21103db86aabSstevel 	socalp->port_state[1].sp_status
21113db86aabSstevel 	    &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
21123db86aabSstevel 	socalp->port_state[1].sp_status |= PORT_OFFLINE;
21133db86aabSstevel 	mutex_exit(&socalp->port_state[1].sp_mtx);
21143db86aabSstevel 
21153db86aabSstevel 	socal_enable(socalp);
21163db86aabSstevel 	/* Make sure disabled ports stay disabled. */
21173db86aabSstevel 	if (socalp->port_state[0].sp_status & PORT_DISABLED)
21183db86aabSstevel 		(void) socal_diag_request((void *)socalp, 0, &r,
21193db86aabSstevel 		    SOC_DIAG_INT_LOOP);
21203db86aabSstevel 	if (socalp->port_state[1].sp_status & PORT_DISABLED)
21213db86aabSstevel 		(void) socal_diag_request((void *)socalp, 1, &r,
21223db86aabSstevel 		    SOC_DIAG_INT_LOOP);
21233db86aabSstevel 
21243db86aabSstevel 	mutex_enter(&socalp->k_imr_mtx);
21253db86aabSstevel 	socalp->socal_shutdown = 0;
21263db86aabSstevel 	mutex_exit(&socalp->k_imr_mtx);
21273db86aabSstevel 
21283db86aabSstevel 	mutex_enter(&socalp->board_mtx);
21293db86aabSstevel 	if (socal_establish_pool(socalp, 1) != FCAL_SUCCESS) {
21303db86aabSstevel 		mutex_exit(&socalp->board_mtx);
21313db86aabSstevel 		return (FCAL_FAILURE);
21323db86aabSstevel 	}
21333db86aabSstevel 	if (socal_add_pool_buffer(socalp, 1) != FCAL_SUCCESS) {
21343db86aabSstevel 		mutex_exit(&socalp->board_mtx);
21353db86aabSstevel 		return (FCAL_FAILURE);
21363db86aabSstevel 	}
21373db86aabSstevel 
21383db86aabSstevel 	mutex_exit(&socalp->board_mtx);
21393db86aabSstevel 	return (FCAL_SUCCESS);
21403db86aabSstevel }
21413db86aabSstevel 
21423db86aabSstevel static void
21433db86aabSstevel socal_doreset(socal_state_t *socalp)
21443db86aabSstevel {
21453db86aabSstevel 	int		i;
21463db86aabSstevel 	socal_port_t	*port_statep;
21473db86aabSstevel 	socal_unsol_cb_t *scbp;
21483db86aabSstevel 
21493db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
21503db86aabSstevel 		mutex_enter(&socalp->request[i].skc_mtx);
21513db86aabSstevel 		mutex_enter(&socalp->response[i].skc_mtx);
21523db86aabSstevel 	}
21533db86aabSstevel 
21543db86aabSstevel 	mutex_enter(&socalp->k_imr_mtx);
21553db86aabSstevel 	socal_disable(socalp);
21563db86aabSstevel 
21573db86aabSstevel 	if (socalp->pool_dhandle) {
21583db86aabSstevel 		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
21593db86aabSstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
21603db86aabSstevel 	}
21613db86aabSstevel 
21623db86aabSstevel 	if (socalp->pool)
21633db86aabSstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
21643db86aabSstevel 
21653db86aabSstevel 	socalp->pool_dhandle = NULL;
21663db86aabSstevel 	socalp->pool = NULL;
21673db86aabSstevel 
21683db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++)
21693db86aabSstevel 		socal_cqinit(socalp, i);
21703db86aabSstevel 
21713db86aabSstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
21723db86aabSstevel 		port_statep = &socalp->port_state[i];
21733db86aabSstevel 
21743db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
21753db86aabSstevel 		port_statep->sp_status &= ~ (PORT_STATUS_MASK |
21763db86aabSstevel 		    PORT_LILP_PENDING | PORT_LIP_PENDING |
21773db86aabSstevel 		    PORT_ABORT_PENDING | PORT_BYPASS_PENDING |
21783db86aabSstevel 		    PORT_ELS_PENDING);
21793db86aabSstevel 		mutex_exit(&port_statep->sp_mtx);
21803db86aabSstevel 	}
21813db86aabSstevel 
21823db86aabSstevel 	mutex_exit(&socalp->k_imr_mtx);
21833db86aabSstevel 
21843db86aabSstevel 	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
21853db86aabSstevel 		mutex_exit(&socalp->request[i].skc_mtx);
21863db86aabSstevel 		mutex_exit(&socalp->response[i].skc_mtx);
21873db86aabSstevel 	}
21883db86aabSstevel 
21893db86aabSstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
21903db86aabSstevel 		for (scbp = socalp->port_state[i].sp_unsol_cb; scbp;
21913db86aabSstevel 		    scbp = scbp->next)
21923db86aabSstevel 			(scbp->statec_cb)(scbp->arg, FCAL_STATE_RESET);
21933db86aabSstevel 	}
21943db86aabSstevel 
21953db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
21963db86aabSstevel 		mutex_enter(&socalp->request[i].skc_mtx);
21973db86aabSstevel 		mutex_enter(&socalp->response[i].skc_mtx);
21983db86aabSstevel 	}
21993db86aabSstevel 
22003db86aabSstevel 
22013db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
22023db86aabSstevel 		socalp->request[i].skc_overflowh = NULL;
22033db86aabSstevel 		if (socalp->request[i].skc_full & SOCAL_SKC_SLEEP)
22043db86aabSstevel 			cv_broadcast(&socalp->request[i].skc_cv);
22053db86aabSstevel 	}
22063db86aabSstevel 
22073db86aabSstevel 	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
22083db86aabSstevel 		mutex_exit(&socalp->request[i].skc_mtx);
22093db86aabSstevel 		mutex_exit(&socalp->response[i].skc_mtx);
22103db86aabSstevel 	}
22113db86aabSstevel 
22123db86aabSstevel }
22133db86aabSstevel 
22143db86aabSstevel 
22153db86aabSstevel /*
22163db86aabSstevel  * Function name : socal_download_ucode ()
22173db86aabSstevel  *
22183db86aabSstevel  * Return Values :
22193db86aabSstevel  *
22203db86aabSstevel  * Description	 : Copies firmware from code that has been linked into
22213db86aabSstevel  *		   the socal module into the soc+'s XRAM.  Prints the date
22223db86aabSstevel  *		   string
22233db86aabSstevel  *
22243db86aabSstevel  */
22253db86aabSstevel static void
22263db86aabSstevel socal_download_ucode(socal_state_t *socalp)
22273db86aabSstevel {
22283db86aabSstevel 	uint_t	fw_len = 0;
22293db86aabSstevel 	uint_t	date_str[16];
22303db86aabSstevel 	auto	char buf[256];
22313db86aabSstevel 
22323db86aabSstevel 	fw_len = (uint_t)socal_ucode_size;
22333db86aabSstevel 
22343db86aabSstevel 	/* Copy the firmware image */
22353db86aabSstevel 	socal_wcopy((uint_t *)&socal_ucode,
22363db86aabSstevel 	    (uint_t *)socalp->socal_xrp, fw_len);
22373db86aabSstevel 
22383db86aabSstevel 	socal_fix_harda(socalp, 0);
22393db86aabSstevel 	socal_fix_harda(socalp, 1);
22403db86aabSstevel 
22413db86aabSstevel 	/* Get the date string from the firmware image */
22423db86aabSstevel 	socal_wcopy((uint_t *)(socalp->socal_xrp+SOCAL_XRAM_FW_DATE_STR),
22433db86aabSstevel 	    date_str, sizeof (date_str));
22443db86aabSstevel 	date_str[sizeof (date_str) / sizeof (uint_t) - 1] = 0;
22453db86aabSstevel 
22463db86aabSstevel 	if (*(caddr_t)date_str != '\0') {
224719397407SSherry Moore 		(void) sprintf(buf,
224819397407SSherry Moore 		    "!Downloading host adapter, fw date code: %s\n",
22493db86aabSstevel 		    (caddr_t)date_str);
22503db86aabSstevel 		socal_disp_err(socalp, CE_CONT, "driver.1010", buf);
225119397407SSherry Moore 		(void) strcpy(socalp->socal_stats.fw_revision,
225219397407SSherry Moore 		    (char *)date_str);
22533db86aabSstevel 	} else {
22543db86aabSstevel 		(void) sprintf(buf,
225519397407SSherry Moore 		    "!Downloading host adapter fw, "
225619397407SSherry Moore 		    "date code: <not available>\n");
22573db86aabSstevel 		socal_disp_err(socalp, CE_CONT, "driver.3010", buf);
22583db86aabSstevel 		(void) strcpy(socalp->socal_stats.fw_revision,
22593db86aabSstevel 		    "<Not Available>");
22603db86aabSstevel 	}
22613db86aabSstevel }
22623db86aabSstevel 
22633db86aabSstevel /*
22643db86aabSstevel  * Function name : socal_disp_err()
22653db86aabSstevel  *
22663db86aabSstevel  * Return Values : none
22673db86aabSstevel  *
22683db86aabSstevel  * Description   : displays an error message on the system console
22693db86aabSstevel  *		   with the full device pathname displayed
22703db86aabSstevel  */
22713db86aabSstevel static void
22723db86aabSstevel socal_disp_err(
22733db86aabSstevel 	socal_state_t	*socalp,
22743db86aabSstevel 	uint_t		level,
22753db86aabSstevel 	char		*mid,
22763db86aabSstevel 	char		*msg)
22773db86aabSstevel {
22783db86aabSstevel 	char c;
22793db86aabSstevel 	int instance;
22803db86aabSstevel 
22813db86aabSstevel 	instance = ddi_get_instance(socalp->dip);
22823db86aabSstevel 
22833db86aabSstevel 	c = *msg;
22843db86aabSstevel 
22853db86aabSstevel 	if (c == '!')		/* log only */
22863db86aabSstevel 		cmn_err(level,
22873db86aabSstevel 		"!ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
22883db86aabSstevel 	else if (c == '?')	/* boot message - log && maybe console */
22893db86aabSstevel 		cmn_err(level,
22903db86aabSstevel 		"?ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
22913db86aabSstevel 	else if (c == '^')	/* console only */
22923db86aabSstevel 		cmn_err(level, "^socal%d: %s", instance, msg+1);
22933db86aabSstevel 	else	{		/* log and console */
22943db86aabSstevel 		cmn_err(level, "^socal%d: %s", instance, msg);
22953db86aabSstevel 		cmn_err(level, "!ID[SUNWssa.socal.%s] socal%d: %s", mid,
22963db86aabSstevel 		    instance, msg);
22973db86aabSstevel 	}
22983db86aabSstevel }
22993db86aabSstevel 
23003db86aabSstevel /*
23013db86aabSstevel  * Function name : socal_init_cq_desc()
23023db86aabSstevel  *
23033db86aabSstevel  * Return Values : none
23043db86aabSstevel  *
23053db86aabSstevel  * Description	 : Initializes the request and response queue
23063db86aabSstevel  *		   descriptors in the SOC+'s XRAM
23073db86aabSstevel  *
23083db86aabSstevel  * Context	 : Should only be called during initialiation when
23093db86aabSstevel  *		   the SOC+ is reset.
23103db86aabSstevel  */
23113db86aabSstevel static void
23123db86aabSstevel socal_init_cq_desc(socal_state_t *socalp)
23133db86aabSstevel {
23143db86aabSstevel 	soc_cq_t	que_desc[SOCAL_N_CQS];
23153db86aabSstevel 	uint32_t	i;
23163db86aabSstevel 
23173db86aabSstevel 	/*
23183db86aabSstevel 	 * Finish CQ table initialization and give the descriptor
23193db86aabSstevel 	 * table to the soc+.  Note that we don't use all of the queues
23203db86aabSstevel 	 * provided by the hardware, but we make sure we initialize the
23213db86aabSstevel 	 * quantities in the unused fields in the hardware to zeroes.
23223db86aabSstevel 	 */
23233db86aabSstevel 
23243db86aabSstevel 	/*
23253db86aabSstevel 	 * Do request queues
23263db86aabSstevel 	 */
23273db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
23283db86aabSstevel 		if (socal_req_entries[i]) {
23293db86aabSstevel 			que_desc[i].cq_address =
233019397407SSherry Moore 			    (uint32_t)socalp->request[i].
233119397407SSherry Moore 			    skc_dcookie.dmac_address;
23323db86aabSstevel 			que_desc[i].cq_last_index = socal_req_entries[i] - 1;
23333db86aabSstevel 		} else {
23343db86aabSstevel 			que_desc[i].cq_address = (uint32_t)0;
23353db86aabSstevel 			que_desc[i].cq_last_index = 0;
23363db86aabSstevel 		}
23373db86aabSstevel 		que_desc[i].cq_in = 0;
23383db86aabSstevel 		que_desc[i].cq_out = 0;
23393db86aabSstevel 		que_desc[i].cq_seqno = 1; /* required by SOC+ microcode */
23403db86aabSstevel 	}
23413db86aabSstevel 
23423db86aabSstevel 	/* copy to XRAM */
23433db86aabSstevel 	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
23443db86aabSstevel 	    (uint_t *)socalp->xram_reqp,	/* pointer to xram location */
23453db86aabSstevel 	    SOCAL_N_CQS * sizeof (soc_cq_t));
23463db86aabSstevel 
23473db86aabSstevel 	/*
23483db86aabSstevel 	 * Do response queues
23493db86aabSstevel 	 */
23503db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
23513db86aabSstevel 		if (socal_rsp_entries[i]) {
23523db86aabSstevel 			que_desc[i].cq_last_index = socal_rsp_entries[i] - 1;
23533db86aabSstevel 			que_desc[i].cq_address =
235419397407SSherry Moore 			    (uint32_t)socalp->response[i].
235519397407SSherry Moore 			    skc_dcookie.dmac_address;
23563db86aabSstevel 
23573db86aabSstevel 		} else {
23583db86aabSstevel 			que_desc[i].cq_address = 0;
23593db86aabSstevel 			que_desc[i].cq_last_index = 0;
23603db86aabSstevel 		}
23613db86aabSstevel 	}
23623db86aabSstevel 
23633db86aabSstevel 	/* copy to XRAM */
23643db86aabSstevel 	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
23653db86aabSstevel 	    (uint_t *)socalp->xram_rspp,	/* pointer to xram location */
23663db86aabSstevel 	    SOCAL_N_CQS * sizeof (soc_cq_t));
23673db86aabSstevel }
23683db86aabSstevel 
23693db86aabSstevel static void
23703db86aabSstevel socal_init_wwn(socal_state_t *socalp)
23713db86aabSstevel {
23723db86aabSstevel 	/* copy the node wwn to xram */
23733db86aabSstevel 	socal_wcopy((uint_t *)&socalp->socal_n_wwn,
23743db86aabSstevel 	    (uint_t *)(socalp->socal_xrp +
23753db86aabSstevel 	    SOCAL_XRAM_NODE_WWN), sizeof (la_wwn_t));
23763db86aabSstevel 
23773db86aabSstevel 	/* copy port a's wwn to xram */
23783db86aabSstevel 	socal_wcopy((uint_t *)&socalp->port_state[0].sp_p_wwn,
23793db86aabSstevel 	    (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTA_WWN),
23803db86aabSstevel 	    sizeof (la_wwn_t));
23813db86aabSstevel 
23823db86aabSstevel 	/* copy port b's wwn to xram */
23833db86aabSstevel 	socal_wcopy((uint_t *)&socalp->port_state[1].sp_p_wwn,
23843db86aabSstevel 	    (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTB_WWN),
23853db86aabSstevel 	    sizeof (la_wwn_t));
23863db86aabSstevel 
23873db86aabSstevel 	/*
23883db86aabSstevel 	 * need to avoid deadlock by assuring no other thread grabs both of
23893db86aabSstevel 	 * these at once
23903db86aabSstevel 	 */
23913db86aabSstevel 	mutex_enter(&socalp->port_state[0].sp_transport->fcal_mtx);
23923db86aabSstevel 	mutex_enter(&socalp->port_state[1].sp_transport->fcal_mtx);
23933db86aabSstevel 
23943db86aabSstevel 	socal_wcopy((uint_t *)(socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS),
23953db86aabSstevel 	    (uint_t *)&socalp->socal_service_params, SOCAL_SVC_LENGTH);
23963db86aabSstevel 	mutex_exit(&socalp->port_state[1].sp_transport->fcal_mtx);
23973db86aabSstevel 	mutex_exit(&socalp->port_state[0].sp_transport->fcal_mtx);
23983db86aabSstevel }
23993db86aabSstevel 
24003db86aabSstevel static void
24013db86aabSstevel socal_enable(socal_state_t *socalp)
24023db86aabSstevel {
24033db86aabSstevel 	DEBUGF(2, (CE_CONT, "socal%d: enable:\n",
24043db86aabSstevel 	    ddi_get_instance(socalp->dip)));
24053db86aabSstevel 
24063db86aabSstevel 	socalp->socal_rp->socal_cr.w = socalp->socal_cfg;
24073db86aabSstevel 	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOCAL_TO_HOST;
24083db86aabSstevel 
24093db86aabSstevel 	socalp->socal_k_imr = (uint32_t)SOCAL_CSR_SOCAL_TO_HOST |
24103db86aabSstevel 	    SOCAL_CSR_SLV_ACC_ERR;
24113db86aabSstevel 	socalp->socal_rp->socal_imr = (uint32_t)socalp->socal_k_imr;
24123db86aabSstevel }
24133db86aabSstevel 
24143db86aabSstevel /*
24153db86aabSstevel  * static int
24163db86aabSstevel  * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
24173db86aabSstevel  *	to place LINK ctl application data as it arrives.
24183db86aabSstevel  *
24193db86aabSstevel  *	Returns:
24203db86aabSstevel  *		FCAL_SUCCESS, upon establishing the pool.
24213db86aabSstevel  *		FCAL_FAILURE, if unable to establish the pool.
24223db86aabSstevel  */
24233db86aabSstevel 
24243db86aabSstevel static int
24253db86aabSstevel socal_establish_pool(socal_state_t *socalp, uint32_t poolid)
24263db86aabSstevel {
24273db86aabSstevel 	soc_pool_request_t	*prq;
24283db86aabSstevel 	int			result;
24293db86aabSstevel 
24303db86aabSstevel 	if ((prq =
24313db86aabSstevel 	    (soc_pool_request_t *)kmem_zalloc(sizeof (soc_pool_request_t),
24323db86aabSstevel 	    KM_NOSLEEP)) == NULL)
24333db86aabSstevel 			return (FCAL_FAILURE);
24343db86aabSstevel 	/*
24353db86aabSstevel 	 * Fill in the request structure.
24363db86aabSstevel 	 */
24373db86aabSstevel 	prq->spr_soc_hdr.sh_request_token = 1;
24383db86aabSstevel 	prq->spr_soc_hdr.sh_flags = SOC_FC_HEADER | SOC_UNSOLICITED |
24393db86aabSstevel 	    SOC_NO_RESPONSE;
24403db86aabSstevel 	prq->spr_soc_hdr.sh_class = 0;
24413db86aabSstevel 	prq->spr_soc_hdr.sh_seg_cnt = 1;
24423db86aabSstevel 	prq->spr_soc_hdr.sh_byte_cnt = 0;
24433db86aabSstevel 
24443db86aabSstevel 	prq->spr_pool_id = poolid;
24453db86aabSstevel 	prq->spr_header_mask = SOCPR_MASK_RCTL;
24463db86aabSstevel 	prq->spr_buf_size = SOCAL_POOL_SIZE;
24473db86aabSstevel 	prq->spr_n_entries = 0;
24483db86aabSstevel 
24493db86aabSstevel 	prq->spr_fc_frame_hdr.r_ctl = R_CTL_ELS_REQ;
24503db86aabSstevel 	prq->spr_fc_frame_hdr.d_id = 0;
24513db86aabSstevel 	prq->spr_fc_frame_hdr.s_id = 0;
24523db86aabSstevel 	prq->spr_fc_frame_hdr.type = 0;
24533db86aabSstevel 	prq->spr_fc_frame_hdr.f_ctl = 0;
24543db86aabSstevel 	prq->spr_fc_frame_hdr.seq_id = 0;
24553db86aabSstevel 	prq->spr_fc_frame_hdr.df_ctl = 0;
24563db86aabSstevel 	prq->spr_fc_frame_hdr.seq_cnt = 0;
24573db86aabSstevel 	prq->spr_fc_frame_hdr.ox_id = 0;
24583db86aabSstevel 	prq->spr_fc_frame_hdr.rx_id = 0;
24593db86aabSstevel 	prq->spr_fc_frame_hdr.ro = 0;
24603db86aabSstevel 
24613db86aabSstevel 	prq->spr_cqhdr.cq_hdr_count = 1;
24623db86aabSstevel 	prq->spr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_POOL;
24633db86aabSstevel 	prq->spr_cqhdr.cq_hdr_flags = 0;
24643db86aabSstevel 	prq->spr_cqhdr.cq_hdr_seqno = 0;
24653db86aabSstevel 
24663db86aabSstevel 	/* Enque the request. */
24673db86aabSstevel 	result = socal_cq_enque(socalp, NULL, (cqe_t *)prq, CQ_REQUEST_1,
24683db86aabSstevel 	    FCAL_NOSLEEP, NULL, 0);
24693db86aabSstevel 	kmem_free((void *)prq, sizeof (soc_pool_request_t));
24703db86aabSstevel 	return (result);
24713db86aabSstevel 
24723db86aabSstevel }
24733db86aabSstevel 
24743db86aabSstevel 
24753db86aabSstevel /*
24763db86aabSstevel  * static int
24773db86aabSstevel  * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
24783db86aabSstevel  *	to an established pool of buffers
24793db86aabSstevel  *
24803db86aabSstevel  *	Returns:
24813db86aabSstevel  *		DDI_SUCCESS, upon establishing the pool.
24823db86aabSstevel  *		DDI_FAILURE, if unable to establish the pool.
24833db86aabSstevel  */
24843db86aabSstevel 
24853db86aabSstevel static int
24863db86aabSstevel socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid)
24873db86aabSstevel {
24883db86aabSstevel 	soc_data_request_t	*drq;
24893db86aabSstevel 	int			result;
24903db86aabSstevel 	size_t			real_len;
24913db86aabSstevel 	int			bound = 0;
24923db86aabSstevel 	uint_t			ccount;
24933db86aabSstevel 
24943db86aabSstevel 	if ((drq =
24953db86aabSstevel 	    (soc_data_request_t *)kmem_zalloc(sizeof (soc_data_request_t),
24963db86aabSstevel 	    KM_NOSLEEP)) == NULL)
24973db86aabSstevel 			return (FCAL_FAILURE);
24983db86aabSstevel 
24993db86aabSstevel 	/* Allocate DVMA resources for the buffer pool */
25003db86aabSstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
25013db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &socalp->pool_dhandle) != DDI_SUCCESS)
25023db86aabSstevel 		goto fail;
25033db86aabSstevel 
25043db86aabSstevel 	if (ddi_dma_mem_alloc(socalp->pool_dhandle, SOCAL_POOL_SIZE,
25053db86aabSstevel 	    &socal_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
25063db86aabSstevel 	    (caddr_t *)&socalp->pool, &real_len, &socalp->pool_acchandle)
25073db86aabSstevel 	    != DDI_SUCCESS)
25083db86aabSstevel 		goto fail;
25093db86aabSstevel 
25103db86aabSstevel 	if (real_len < SOCAL_POOL_SIZE)
25113db86aabSstevel 		goto fail;
25123db86aabSstevel 
25133db86aabSstevel 	if (ddi_dma_addr_bind_handle(socalp->pool_dhandle, (struct as *)NULL,
25143db86aabSstevel 	    (caddr_t)socalp->pool, SOCAL_POOL_SIZE,
25153db86aabSstevel 	    DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
25163db86aabSstevel 	    NULL, &socalp->pool_dcookie, &ccount) != DDI_DMA_MAPPED)
25173db86aabSstevel 		goto fail;
25183db86aabSstevel 
25193db86aabSstevel 	bound = 1;
25203db86aabSstevel 	if (ccount != 1)
25213db86aabSstevel 		goto fail;
25223db86aabSstevel 
25233db86aabSstevel 	/*
25243db86aabSstevel 	 * Fill in the request structure.
25253db86aabSstevel 	 */
25263db86aabSstevel 	drq->sdr_soc_hdr.sh_request_token = poolid;
25273db86aabSstevel 	drq->sdr_soc_hdr.sh_flags = SOC_UNSOLICITED | SOC_NO_RESPONSE;
25283db86aabSstevel 	drq->sdr_soc_hdr.sh_class = 0;
25293db86aabSstevel 	drq->sdr_soc_hdr.sh_seg_cnt = 1;
25303db86aabSstevel 	drq->sdr_soc_hdr.sh_byte_cnt = 0;
25313db86aabSstevel 
25323db86aabSstevel 	drq->sdr_dataseg[0].fc_base =
25333db86aabSstevel 	    (uint32_t)socalp->pool_dcookie.dmac_address;
25343db86aabSstevel 	drq->sdr_dataseg[0].fc_count = SOCAL_POOL_SIZE;
25353db86aabSstevel 	drq->sdr_dataseg[1].fc_base = 0;
25363db86aabSstevel 	drq->sdr_dataseg[1].fc_count = 0;
25373db86aabSstevel 	drq->sdr_dataseg[2].fc_base = 0;
25383db86aabSstevel 	drq->sdr_dataseg[2].fc_count = 0;
25393db86aabSstevel 	drq->sdr_dataseg[3].fc_base = 0;
25403db86aabSstevel 	drq->sdr_dataseg[3].fc_count = 0;
25413db86aabSstevel 	drq->sdr_dataseg[4].fc_base = 0;
25423db86aabSstevel 	drq->sdr_dataseg[4].fc_count = 0;
25433db86aabSstevel 	drq->sdr_dataseg[5].fc_base = 0;
25443db86aabSstevel 	drq->sdr_dataseg[5].fc_count = 0;
25453db86aabSstevel 
25463db86aabSstevel 	drq->sdr_cqhdr.cq_hdr_count = 1;
25473db86aabSstevel 	drq->sdr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_BUFFER;
25483db86aabSstevel 	drq->sdr_cqhdr.cq_hdr_flags = 0;
25493db86aabSstevel 	drq->sdr_cqhdr.cq_hdr_seqno = 0;
25503db86aabSstevel 
25513db86aabSstevel 	/* Transport the request. */
25523db86aabSstevel 	result = socal_cq_enque(socalp, NULL, (cqe_t *)drq, CQ_REQUEST_1,
25533db86aabSstevel 	    FCAL_NOSLEEP, NULL, 0);
25543db86aabSstevel 	kmem_free((void *)drq, sizeof (soc_data_request_t));
25553db86aabSstevel 	return (result);
25563db86aabSstevel 
25573db86aabSstevel fail:
25583db86aabSstevel 	socal_disp_err(socalp, CE_WARN, "driver.4110",
25593db86aabSstevel 	    "!Buffer pool DVMA alloc failed");
25603db86aabSstevel 	if (socalp->pool_dhandle) {
25613db86aabSstevel 		if (bound)
25623db86aabSstevel 			(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
25633db86aabSstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
25643db86aabSstevel 	}
25653db86aabSstevel 	if (socalp->pool)
25663db86aabSstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
25673db86aabSstevel 	socalp->pool_dhandle = NULL;
25683db86aabSstevel 	return (FCAL_FAILURE);
25693db86aabSstevel }
25703db86aabSstevel 
25713db86aabSstevel static uint_t
25723db86aabSstevel socal_transport(fcal_packet_t *fcalpkt, fcal_sleep_t sleep, int req_q_no)
25733db86aabSstevel {
25743db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
25753db86aabSstevel 	socal_port_t	*port_statep;
25763db86aabSstevel #if defined(DEBUG) && !defined(lint)
25773db86aabSstevel 	int		instance = ddi_get_instance(socalp->dip);
25783db86aabSstevel #endif
25793db86aabSstevel 	int		port;
25803db86aabSstevel 	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
25813db86aabSstevel 
25823db86aabSstevel 	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
25833db86aabSstevel 		port = 1;
25843db86aabSstevel 	else
25853db86aabSstevel 		port = 0;
25863db86aabSstevel 	port_statep = &socalp->port_state[port];
25873db86aabSstevel 
25883db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d: transport: packet, sleep = %p, %d\n",
25893db86aabSstevel 	    instance, fcalpkt, sleep));
25903db86aabSstevel 
25913db86aabSstevel 	fcalpkt->fcal_cmd_state = 0;
25923db86aabSstevel 	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
25933db86aabSstevel 
25943db86aabSstevel 	return (socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
25953db86aabSstevel 	    req_q_no, sleep, fcalpkt, 0));
25963db86aabSstevel }
25973db86aabSstevel 
25983db86aabSstevel /*
25993db86aabSstevel  * Function name : socal_cq_enque()
26003db86aabSstevel  *
26013db86aabSstevel  * Return Values :
26023db86aabSstevel  *		FCAL_TRANSPORT_SUCCESS, if able to que the entry.
26033db86aabSstevel  *		FCAL_TRANSPORT_QFULL, if queue full & sleep not set
26043db86aabSstevel  *		FCAL_TRANSPORT_UNAVAIL if this port down
26053db86aabSstevel  *
26063db86aabSstevel  * Description	 : Enqueues an entry into the solicited request
26073db86aabSstevel  *		   queue
26083db86aabSstevel  *
26093db86aabSstevel  * Context	:
26103db86aabSstevel  */
26113db86aabSstevel 
26123db86aabSstevel /*ARGSUSED*/
26133db86aabSstevel static int
26143db86aabSstevel socal_cq_enque(socal_state_t *socalp, socal_port_t *port_statep, cqe_t *cqe,
26153db86aabSstevel 		int rqix, fcal_sleep_t sleep, fcal_packet_t *to_queue,
26163db86aabSstevel 		int mtxheld)
26173db86aabSstevel {
26183db86aabSstevel #if defined(DEBUG) && !defined(lint)
26193db86aabSstevel 	int 		instance = ddi_get_instance(socalp->dip);
26203db86aabSstevel #endif
26213db86aabSstevel 	socal_kcq_t	*kcq;
26223db86aabSstevel 	cqe_t		*sp;
26233db86aabSstevel 	uint_t		bitmask, wmask;
26243db86aabSstevel 	uchar_t		out;
26253db86aabSstevel 	uchar_t		s_out;
26263db86aabSstevel 	longlong_t	*p, *q;
26273db86aabSstevel 
26283db86aabSstevel 	kcq = &socalp->request[rqix];
26293db86aabSstevel 
26303db86aabSstevel 	bitmask = SOCAL_CSR_1ST_H_TO_S << rqix;
26313db86aabSstevel 	wmask = SOCAL_CSR_SOCAL_TO_HOST | bitmask;
26323db86aabSstevel 	p = (longlong_t *)cqe;
26333db86aabSstevel 
26343db86aabSstevel 	/*
26353db86aabSstevel 	 * Since we're only reading we don't need a mutex.
26363db86aabSstevel 	 */
26373db86aabSstevel 	if (socalp->socal_shutdown) {
26383db86aabSstevel 		return (FCAL_TRANSPORT_UNAVAIL);
26393db86aabSstevel 	}
26403db86aabSstevel 	/*
26413db86aabSstevel 	 * Get a token early.  That way we won't sleep
26423db86aabSstevel 	 * in id32_alloc() with a mutex held.
26433db86aabSstevel 	 */
26443db86aabSstevel 	if (to_queue) {
26453db86aabSstevel 		if ((to_queue->fcal_socal_request.sr_soc_hdr.sh_request_token =
26463db86aabSstevel 		    SOCAL_ID_GET(to_queue, mtxheld ? FCAL_NOSLEEP :
26473db86aabSstevel 		    sleep)) == NULL) {
26483db86aabSstevel 			return (FCAL_TRANSPORT_QFULL);
26493db86aabSstevel 		}
26503db86aabSstevel 	}
26513db86aabSstevel 	/*
26523db86aabSstevel 	 * Grab lock for request queue.
26533db86aabSstevel 	 */
26543db86aabSstevel 
26553db86aabSstevel 	if (!mtxheld)
26563db86aabSstevel 		mutex_enter(&kcq->skc_mtx);
26573db86aabSstevel 
26583db86aabSstevel 	/*
26593db86aabSstevel 	 * Determine if the queue is full
26603db86aabSstevel 	 */
26613db86aabSstevel 
26623db86aabSstevel 	do {
26633db86aabSstevel 
26643db86aabSstevel 		if (kcq->skc_full) {
26653db86aabSstevel 		/*
26663db86aabSstevel 		 * If soc's queue full, then we wait for an interrupt
26673db86aabSstevel 		 * telling us we are not full.
26683db86aabSstevel 		 */
26693db86aabSstevel 
26703db86aabSstevel 			if (to_queue) {
26713db86aabSstevel 			to_queue->fcal_pkt_next = NULL;
26723db86aabSstevel 			if (!kcq->skc_overflowh) {
26733db86aabSstevel 				DEBUGF(2, (CE_CONT,
267419397407SSherry Moore 				    "socal%d: cq_enque: request "
267519397407SSherry Moore 				    "que %d is full\n",
26763db86aabSstevel 				    instance, rqix));
26773db86aabSstevel 				kcq->skc_overflowh = to_queue;
26783db86aabSstevel 				socalp->socal_stats.qfulls++;
26793db86aabSstevel 			} else
26803db86aabSstevel 				kcq->skc_overflowt->fcal_pkt_next = to_queue;
26813db86aabSstevel 			kcq->skc_overflowt = to_queue;
26823db86aabSstevel 
26833db86aabSstevel 			mutex_enter(&socalp->k_imr_mtx);
26843db86aabSstevel 			socalp->socal_rp->socal_imr =
26853db86aabSstevel 			    (socalp->socal_k_imr |= bitmask);
26863db86aabSstevel 			mutex_exit(&socalp->k_imr_mtx);
26873db86aabSstevel 			to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
26883db86aabSstevel 			if (!mtxheld)
26893db86aabSstevel 				mutex_exit(&kcq->skc_mtx);
26903db86aabSstevel 			return (FCAL_TRANSPORT_SUCCESS);
26913db86aabSstevel 			}
26923db86aabSstevel 
26933db86aabSstevel 			if (!mtxheld)
26943db86aabSstevel 			mutex_exit(&kcq->skc_mtx);
26953db86aabSstevel 			return (FCAL_TRANSPORT_QFULL);
26963db86aabSstevel 		}
26973db86aabSstevel 
26983db86aabSstevel 		if (((kcq->skc_in + 1) & kcq->skc_last_index)
26993db86aabSstevel 		    == (out = kcq->skc_out)) {
27003db86aabSstevel 		/*
27013db86aabSstevel 		 * get SOC+'s copy of out to update our copy of out
27023db86aabSstevel 		 */
27033db86aabSstevel 		s_out =
27043db86aabSstevel 		    SOCAL_REQUESTQ_INDEX(rqix, socalp->socal_rp->socal_reqp.w);
27053db86aabSstevel 		DEBUGF(2, (CE_CONT,
27063db86aabSstevel 		    "socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
27073db86aabSstevel 		    instance, &kcq->skc_xram_cqdesc->cq_in, s_out));
27083db86aabSstevel 
27093db86aabSstevel 		kcq->skc_out = out = s_out;
27103db86aabSstevel 		/* if soc+'s que still full set flag */
27113db86aabSstevel 		kcq->skc_full = ((((kcq->skc_in + 1) &
27123db86aabSstevel 		    kcq->skc_last_index) == out)) ? SOCAL_SKC_FULL : 0;
27133db86aabSstevel 		}
27143db86aabSstevel 
27153db86aabSstevel 	} while (kcq->skc_full);
27163db86aabSstevel 
27173db86aabSstevel 	/* Now enque the entry. */
27183db86aabSstevel 	sp = &(kcq->skc_cq[kcq->skc_in]);
27193db86aabSstevel 	cqe->cqe_hdr.cq_hdr_seqno = kcq->skc_seqno;
27203db86aabSstevel 
27213db86aabSstevel 	/* Give the entry to the SOC. */
27223db86aabSstevel 	q = (longlong_t *)sp;
27233db86aabSstevel 	*q++ = *p++;
27243db86aabSstevel 	*q++ = *p++;
27253db86aabSstevel 	*q++ = *p++;
27263db86aabSstevel 	*q++ = *p++;
27273db86aabSstevel 	*q++ = *p++;
27283db86aabSstevel 	*q++ = *p++;
27293db86aabSstevel 	*q++ = *p++;
27303db86aabSstevel 	*q = *p;
27313db86aabSstevel 	(void) ddi_dma_sync(kcq->skc_dhandle, (int)((caddr_t)sp -
27323db86aabSstevel 	    (caddr_t)kcq->skc_cq), sizeof (cqe_t), DDI_DMA_SYNC_FORDEV);
27333db86aabSstevel 	if (to_queue)
27343db86aabSstevel 		to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
27353db86aabSstevel 
27363db86aabSstevel 	/*
27373db86aabSstevel 	 * Update circular queue and ring SOC's doorbell.
27383db86aabSstevel 	 */
27393db86aabSstevel 	kcq->skc_in++;
27403db86aabSstevel 	if ((kcq->skc_in & kcq->skc_last_index) == 0) {
27413db86aabSstevel 		kcq->skc_in = 0;
27423db86aabSstevel 		kcq->skc_seqno++;
27433db86aabSstevel 	}
27443db86aabSstevel 
27453db86aabSstevel 	socalp->socal_rp->socal_csr.w = wmask | (kcq->skc_in << 24);
27463db86aabSstevel 	/* Let lock go for request queue. */
27473db86aabSstevel 	if (!mtxheld)
27483db86aabSstevel 		mutex_exit(&kcq->skc_mtx);
27493db86aabSstevel 
27503db86aabSstevel 	return (FCAL_TRANSPORT_SUCCESS);
27513db86aabSstevel }
27523db86aabSstevel 
27533db86aabSstevel static uint_t
27543db86aabSstevel socal_transport_poll(fcal_packet_t *fcalpkt, uint_t timeout, int req_q_no)
27553db86aabSstevel {
27563db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
27573db86aabSstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
27583db86aabSstevel 	uint_t			csr;
27593db86aabSstevel 	socal_port_t	*port_statep;
27603db86aabSstevel 	int		port;
27613db86aabSstevel 	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
27623db86aabSstevel 	uint32_t	retval;
27633db86aabSstevel 	clock_t		ticker, t;
27643db86aabSstevel 
27653db86aabSstevel 	/* make the timeout meaningful */
27663db86aabSstevel 	timeout = drv_usectohz(timeout);
27673db86aabSstevel 	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
27683db86aabSstevel 		port = 1;
27693db86aabSstevel 	else
27703db86aabSstevel 		port = 0;
27713db86aabSstevel 	port_statep = &socalp->port_state[port];
27723db86aabSstevel 
27733db86aabSstevel 	fcalpkt->fcal_cmd_state = 0;
27743db86aabSstevel 	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
27753db86aabSstevel 
27763db86aabSstevel 	ticker = ddi_get_lbolt();
27773db86aabSstevel 
27783db86aabSstevel 	if ((retval = socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
27793db86aabSstevel 	    req_q_no, FCAL_NOSLEEP, fcalpkt, 0)) != FCAL_TRANSPORT_SUCCESS) {
27803db86aabSstevel 		return (retval);
27813db86aabSstevel 	} else {
27823db86aabSstevel 		while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
27833db86aabSstevel 			drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME);
27843db86aabSstevel 			t = ddi_get_lbolt();
27853db86aabSstevel 			if ((ticker + timeout) < t)
27863db86aabSstevel 				return (FCAL_TRANSPORT_TIMEOUT);
27873db86aabSstevel 			csr = socalreg->socal_csr.w;
27883db86aabSstevel 			if ((SOCAL_INTR_CAUSE(socalp, csr)) &
27893db86aabSstevel 			    SOCAL_CSR_RSP_QUE_0) {
27903db86aabSstevel 				socal_intr_solicited(socalp, 0);
27913db86aabSstevel 			}
27923db86aabSstevel 		}
27933db86aabSstevel 	}
27943db86aabSstevel 	return (FCAL_TRANSPORT_SUCCESS);
27953db86aabSstevel }
27963db86aabSstevel 
27973db86aabSstevel static uint_t
27983db86aabSstevel socal_doit(fcal_packet_t *fcalpkt, socal_port_t *port_statep, int polled,
27993db86aabSstevel     void (*func)(), int timo, int flag, uint_t *diagcode)
28003db86aabSstevel {
28013db86aabSstevel 	clock_t lb;
28023db86aabSstevel 	uint32_t retval, status;
28033db86aabSstevel 	socal_state_t   *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
28043db86aabSstevel 
28053db86aabSstevel 	if (polled) {
28063db86aabSstevel 		fcalpkt->fcal_pkt_comp = NULL;
28073db86aabSstevel 		status = socal_transport_poll(fcalpkt, timo, CQ_REQUEST_0);
28083db86aabSstevel 	} else {
28093db86aabSstevel 		fcalpkt->fcal_pkt_comp = func;
28103db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
28113db86aabSstevel 		port_statep->sp_status |= flag;
28123db86aabSstevel 		if ((status = socal_transport(fcalpkt, FCAL_NOSLEEP,
28133db86aabSstevel 		    CQ_REQUEST_0)) == FCAL_TRANSPORT_SUCCESS) {
28143db86aabSstevel 			lb = ddi_get_lbolt();
28153db86aabSstevel 			while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
28163db86aabSstevel 			if ((retval = cv_timedwait(&port_statep->sp_cv,
28173db86aabSstevel 			    &port_statep->sp_mtx,
28183db86aabSstevel 			    lb+drv_usectohz(timo))) == -1) {
28193db86aabSstevel 				status = FCAL_TRANSPORT_TIMEOUT;
28203db86aabSstevel 				break;
28213db86aabSstevel 			}
28223db86aabSstevel 			}
28233db86aabSstevel 		}
28243db86aabSstevel 		port_statep->sp_status &= ~flag;
28253db86aabSstevel 		mutex_exit(&port_statep->sp_mtx);
28263db86aabSstevel 	}
28273db86aabSstevel 
28283db86aabSstevel 	switch (status) {
28293db86aabSstevel 		case FCAL_TRANSPORT_SUCCESS:
28303db86aabSstevel 			status = fcalpkt->fcal_pkt_status;
28313db86aabSstevel 			if (diagcode)
28323db86aabSstevel 				*diagcode = fcalpkt->fcal_diag_status;
28333db86aabSstevel 			switch (status) {
28343db86aabSstevel 				case FCAL_STATUS_ABORT_FAILED:
28353db86aabSstevel 					if (flag == PORT_ABORT_PENDING)
28363db86aabSstevel 						retval = FCAL_ABORT_FAILED;
28373db86aabSstevel 					break;
28383db86aabSstevel 				case FCAL_STATUS_OK:
28393db86aabSstevel 					if (flag == PORT_ABORT_PENDING)
28403db86aabSstevel 						retval = FCAL_ABORT_FAILED;
28413db86aabSstevel 					else
28423db86aabSstevel 						retval = FCAL_SUCCESS;
28433db86aabSstevel 					break;
28443db86aabSstevel 				case FCAL_STATUS_OLD_PORT:
28453db86aabSstevel 					retval = FCAL_OLD_PORT;
28463db86aabSstevel 					break;
28473db86aabSstevel 				case FCAL_STATUS_ERR_OFFLINE:
28483db86aabSstevel 					retval = FCAL_OFFLINE;
28493db86aabSstevel 					break;
28503db86aabSstevel 				case FCAL_STATUS_ABORTED:
28513db86aabSstevel 					retval = FCAL_ABORTED;
28523db86aabSstevel 					port_statep->sp_board->
28533db86aabSstevel 					    socal_stats.pstats[port_statep
28543db86aabSstevel 					    ->sp_port].abts_ok++;
28553db86aabSstevel 					break;
28563db86aabSstevel 				case FCAL_STATUS_BAD_XID:
28573db86aabSstevel 					retval = FCAL_BAD_ABORT;
28583db86aabSstevel 					break;
28593db86aabSstevel 				case FCAL_STATUS_BAD_DID:
28603db86aabSstevel 					retval = FCAL_BAD_PARAMS;
28613db86aabSstevel 					break;
28623db86aabSstevel 				case FCAL_STATUS_DIAG_BUSY:
28633db86aabSstevel 				case FCAL_STATUS_DIAG_INVALID:
28643db86aabSstevel 					retval = status;
28653db86aabSstevel 					break;
28663db86aabSstevel 				default:
28673db86aabSstevel 					retval = FCAL_LINK_ERROR;
28683db86aabSstevel 			}
28693db86aabSstevel 			break;
28703db86aabSstevel 		case FCAL_TRANSPORT_TIMEOUT:
28713db86aabSstevel 			if (flag == PORT_LIP_PENDING ||
28723db86aabSstevel 			    flag == PORT_LILP_PENDING) {
28733db86aabSstevel 				if (socal_core &&
28743db86aabSstevel 				    (socal_core & SOCAL_FAILED_LIP)) {
28753db86aabSstevel 					socal_core = 0;
28763db86aabSstevel 					socal_take_core(socalp);
28773db86aabSstevel 				}
28783db86aabSstevel 				socal_disp_err(socalp, CE_WARN, "link.6040",
28793db86aabSstevel 				"SOCAL:Forcing SOC+ reset as LIP timed out\n");
28803db86aabSstevel 				/* restart socal after resetting */
28813db86aabSstevel 				(void) socal_force_reset(port_statep->sp_board,
28823db86aabSstevel 				    polled, RESET_PORT);
28833db86aabSstevel 			}
28843db86aabSstevel 			else
28853db86aabSstevel 				(void) socal_force_lip(port_statep->sp_board,
288619397407SSherry Moore 				    port_statep->sp_port, polled,
288719397407SSherry Moore 				    FCAL_FORCE_LIP);
28883db86aabSstevel 			retval = FCAL_TIMEOUT;
28893db86aabSstevel 			break;
28903db86aabSstevel 		case FCAL_TRANSPORT_FAILURE:
28913db86aabSstevel 		case FCAL_BAD_PACKET:
28923db86aabSstevel 		case FCAL_TRANSPORT_UNAVAIL:
28933db86aabSstevel 		case FCAL_TRANSPORT_QFULL:
28943db86aabSstevel 			retval = status;
28953db86aabSstevel 			break;
28963db86aabSstevel 		default:
28973db86aabSstevel 			retval = FCAL_LINK_ERROR;
28983db86aabSstevel 	}
28993db86aabSstevel 	socal_packet_free(fcalpkt);
29003db86aabSstevel 	return (retval);
29013db86aabSstevel }
29023db86aabSstevel 
29033db86aabSstevel static uint_t
29043db86aabSstevel socal_lilp_map(void *ssp, uint_t port, uint32_t bufid, uint_t polled)
29053db86aabSstevel {
29063db86aabSstevel 	fcal_packet_t		*fcalpkt;
29073db86aabSstevel 	soc_data_request_t	*sdr;
29083db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29093db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29103db86aabSstevel 
29113db86aabSstevel 	if ((fcalpkt =
29123db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
29133db86aabSstevel 	    == (fcal_packet_t *)NULL)
29143db86aabSstevel 		return (FCAL_ALLOC_FAILED);
29153db86aabSstevel 
29163db86aabSstevel 	sdr = (soc_data_request_t *)&fcalpkt->fcal_socal_request;
29173db86aabSstevel 	if (port)
29183db86aabSstevel 		sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
29193db86aabSstevel 	sdr->sdr_soc_hdr.sh_seg_cnt = 1;
29203db86aabSstevel 	sdr->sdr_soc_hdr.sh_byte_cnt = 132;
29213db86aabSstevel 	sdr->sdr_dataseg[0].fc_base = bufid;
29223db86aabSstevel 	sdr->sdr_dataseg[0].fc_count = 132;
29233db86aabSstevel 	sdr->sdr_cqhdr.cq_hdr_count = 1;
29243db86aabSstevel 	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_REPORT_MAP;
29253db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
29263db86aabSstevel 
29273db86aabSstevel 	return (socal_doit(fcalpkt, port_statep, polled, socal_lilp_map_done,
29283db86aabSstevel 	    SOCAL_LILP_TIMEOUT, PORT_LILP_PENDING, NULL));
29293db86aabSstevel }
29303db86aabSstevel 
29313db86aabSstevel static uint_t
29323db86aabSstevel socal_force_lip(void *ssp, uint_t port, uint_t polled, uint_t lip_req)
29333db86aabSstevel {
29343db86aabSstevel 	fcal_packet_t		*fcalpkt;
29353db86aabSstevel 	soc_cmdonly_request_t	*scr;
29363db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29373db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29383db86aabSstevel 
29393db86aabSstevel 
29403db86aabSstevel 	if (lip_req == FCAL_NO_LIP) {
29413db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
29423db86aabSstevel 		if ((port_statep->sp_status & PORT_ONLINE_LOOP) &&
29433db86aabSstevel 		    (port_statep->sp_unsol_cb->statec_cb != NULL)) {
29443db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
29453db86aabSstevel 				(*port_statep->sp_unsol_cb->statec_cb)
29463db86aabSstevel 				    (port_statep->sp_unsol_cb->arg,
29473db86aabSstevel 				    FCAL_STATUS_LOOP_ONLINE);
29483db86aabSstevel 			return (FCAL_SUCCESS);
29493db86aabSstevel 
29503db86aabSstevel 		} else
29513db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
29523db86aabSstevel 	}
29533db86aabSstevel 	socalp->socal_stats.pstats[port].lips++;
29543db86aabSstevel 	if ((fcalpkt =
29553db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
29563db86aabSstevel 	    == (fcal_packet_t *)NULL)
29573db86aabSstevel 		return (FCAL_ALLOC_FAILED);
29583db86aabSstevel 
29593db86aabSstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
29603db86aabSstevel 	if (port)
29613db86aabSstevel 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
29623db86aabSstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
29633db86aabSstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_LIP;
29643db86aabSstevel 
29653db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
29663db86aabSstevel 	return (socal_doit(fcalpkt, port_statep, polled, socal_force_lip_done,
29673db86aabSstevel 	    SOCAL_LIP_TIMEOUT, PORT_LIP_PENDING, NULL));
29683db86aabSstevel }
29693db86aabSstevel 
29703db86aabSstevel static uint_t
29713db86aabSstevel socal_abort_cmd(void *ssp, uint_t port, fcal_packet_t *fcalpkt, uint_t polled)
29723db86aabSstevel {
29733db86aabSstevel 	fcal_packet_t		*fcalpkt2, *fpkt;
29743db86aabSstevel 	soc_cmdonly_request_t	*scr, *tscr;
29753db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29763db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29773db86aabSstevel 	socal_kcq_t		*kcq;
29783db86aabSstevel 
29793db86aabSstevel 	socalp->socal_stats.pstats[port].abts++;
29803db86aabSstevel 	kcq = &socalp->request[CQ_REQUEST_1];
29813db86aabSstevel 	mutex_enter(&kcq->skc_mtx);
29823db86aabSstevel 	fcalpkt2 = kcq->skc_overflowh;
29833db86aabSstevel 	fpkt = NULL;
29843db86aabSstevel 	while (fcalpkt2 != NULL) {
29853db86aabSstevel 		if (fcalpkt2 == fcalpkt) {
29863db86aabSstevel 			if (fpkt == NULL)
29873db86aabSstevel 				kcq->skc_overflowh = fcalpkt->fcal_pkt_next;
29883db86aabSstevel 			else {
29893db86aabSstevel 				fpkt->fcal_pkt_next = fcalpkt->fcal_pkt_next;
29903db86aabSstevel 				if (kcq->skc_overflowt == fcalpkt)
29913db86aabSstevel 					kcq->skc_overflowt = fpkt;
29923db86aabSstevel 			}
29933db86aabSstevel 			mutex_exit(&kcq->skc_mtx);
29943db86aabSstevel 			socalp->socal_stats.pstats[port].abts_ok++;
29953db86aabSstevel 			SOCAL_ID_FREE(fcalpkt->fcal_socal_request.
29963db86aabSstevel 			    sr_soc_hdr.sh_request_token);
29973db86aabSstevel 			return (FCAL_ABORTED);
29983db86aabSstevel 		} else {
29993db86aabSstevel 			fpkt = fcalpkt2;
30003db86aabSstevel 			fcalpkt2 = fcalpkt2->fcal_pkt_next;
30013db86aabSstevel 		}
30023db86aabSstevel 	}
30033db86aabSstevel 	mutex_exit(&kcq->skc_mtx);
30043db86aabSstevel 	if ((fcalpkt2 =
30053db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
30063db86aabSstevel 	    == (fcal_packet_t *)NULL)
30073db86aabSstevel 		return (FCAL_ALLOC_FAILED);
30083db86aabSstevel 
30093db86aabSstevel 	mutex_enter(&socalp->abort_mtx);
30103db86aabSstevel 	/* Too late? */
30113db86aabSstevel 	if (fcalpkt->fcal_pkt_flags & FCFLAG_COMPLETE) {
30123db86aabSstevel 		socal_packet_free(fcalpkt2);
30133db86aabSstevel 		mutex_exit(&socalp->abort_mtx);
30143db86aabSstevel 		return (FCAL_ABORTED);
30153db86aabSstevel 		/* I lied.  So shoot me. */
30163db86aabSstevel 	}
30173db86aabSstevel 	/* Mark packet as being aborted and put it in the abort pending list. */
30183db86aabSstevel 	fcalpkt->fcal_pkt_flags |= FCFLAG_ABORTING;
30193db86aabSstevel 
30203db86aabSstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt2->fcal_socal_request;
30213db86aabSstevel 	tscr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
30223db86aabSstevel 	scr->scr_soc_hdr.sh_byte_cnt = tscr->scr_soc_hdr.sh_request_token;
30233db86aabSstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
30243db86aabSstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_ABORT;
30253db86aabSstevel 	if (port)
30263db86aabSstevel 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
30273db86aabSstevel 	fcalpkt2->fcal_pkt_cookie = (void *)socalp;
30283db86aabSstevel 	mutex_exit(&socalp->abort_mtx);
30293db86aabSstevel 
30303db86aabSstevel 	return (socal_doit(fcalpkt2, port_statep, polled, socal_abort_done,
30313db86aabSstevel 	    SOCAL_ABORT_TIMEOUT, PORT_ABORT_PENDING, NULL));
30323db86aabSstevel }
30333db86aabSstevel 
30343db86aabSstevel /*ARGSUSED*/
30353db86aabSstevel static uint_t
30363db86aabSstevel socal_els(void *ssp, uint_t port, uint_t elscode, uint_t dest,
30373db86aabSstevel 	void (*callback)(), void *arg, caddr_t reqpl, caddr_t *rsppl,
30383db86aabSstevel 	uint_t sleep)
30393db86aabSstevel {
30403db86aabSstevel 	return (FCAL_TRANSPORT_FAILURE);
30413db86aabSstevel }
30423db86aabSstevel 
30433db86aabSstevel static uint_t
30443db86aabSstevel socal_bypass_dev(void *ssp, uint_t port, uint_t dest)
30453db86aabSstevel {
30463db86aabSstevel 	fcal_packet_t		*fcalpkt;
30473db86aabSstevel 	soc_cmdonly_request_t	*scr;
30483db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
30493db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
30503db86aabSstevel 
30513db86aabSstevel 	if ((fcalpkt =
30523db86aabSstevel 	    socal_packet_alloc(socalp, FCAL_SLEEP))
30533db86aabSstevel 	    == (fcal_packet_t *)NULL)
30543db86aabSstevel 		return (FCAL_ALLOC_FAILED);
30553db86aabSstevel 
30563db86aabSstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
30573db86aabSstevel 	if (port)
30583db86aabSstevel 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
30593db86aabSstevel 	scr->scr_soc_hdr.sh_byte_cnt = dest;
30603db86aabSstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
30613db86aabSstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_BYPASS_DEV;
30623db86aabSstevel 	return (socal_doit(fcalpkt, port_statep, 0, socal_bypass_dev_done,
30633db86aabSstevel 	    SOCAL_BYPASS_TIMEOUT, PORT_BYPASS_PENDING, NULL));
30643db86aabSstevel }
30653db86aabSstevel 
30663db86aabSstevel 
30673db86aabSstevel /*ARGSUSED*/
30683db86aabSstevel static void
30693db86aabSstevel socal_force_reset(void *ssp, uint_t port, uint_t restart)
30703db86aabSstevel {
30713db86aabSstevel 	socal_state_t 	*socalp = (socal_state_t *)ssp;
30723db86aabSstevel 
30733db86aabSstevel 	mutex_enter(&socalp->k_imr_mtx);
30743db86aabSstevel 	if (socalp->socal_shutdown) {
30753db86aabSstevel 		mutex_exit(&socalp->k_imr_mtx);
30763db86aabSstevel 		return;
30773db86aabSstevel 	} else {
30783db86aabSstevel 		socalp->socal_shutdown = 1;
30793db86aabSstevel 		mutex_exit(&socalp->k_imr_mtx);
30803db86aabSstevel 	}
30813db86aabSstevel 	socalp->socal_stats.resets++;
30823db86aabSstevel 	socal_doreset(socalp);
30833db86aabSstevel 	if (restart) {
30843db86aabSstevel 		if (socal_start(socalp) != FCAL_SUCCESS) {
30853db86aabSstevel 			cmn_err(CE_WARN, "socal: start failed.\n");
30863db86aabSstevel 		}
30873db86aabSstevel 	}
30883db86aabSstevel }
30893db86aabSstevel 
30903db86aabSstevel 
30913db86aabSstevel static void
30923db86aabSstevel socal_add_ulp(void *ssp, uint_t port, uchar_t type,
30933db86aabSstevel 	void (*ulp_statec_callback)(), void (*ulp_els_callback)(),
30943db86aabSstevel 	void (*ulp_data_callback)(), void *arg)
30953db86aabSstevel {
30963db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)ssp;
30973db86aabSstevel 	socal_port_t	*port_statep = &socalp->port_state[port];
30983db86aabSstevel 	socal_unsol_cb_t *cbentry;
30993db86aabSstevel 
31003db86aabSstevel 	mutex_enter(&port_statep->sp_mtx);
31013db86aabSstevel 	for (cbentry = port_statep->sp_unsol_cb; cbentry;
31023db86aabSstevel 	    cbentry = cbentry->next) {
31033db86aabSstevel 		if (cbentry->type == type) {
31043db86aabSstevel 			cbentry->statec_cb = ulp_statec_callback;
31053db86aabSstevel 			cbentry->els_cb = ulp_els_callback;
31063db86aabSstevel 			cbentry->data_cb = ulp_data_callback;
31073db86aabSstevel 			cbentry->arg = arg;
31083db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
31093db86aabSstevel 			return;
31103db86aabSstevel 		}
31113db86aabSstevel 	}
31123db86aabSstevel 	mutex_exit(&port_statep->sp_mtx);
31133db86aabSstevel 	if ((cbentry =
31143db86aabSstevel 	    (socal_unsol_cb_t *)kmem_zalloc(sizeof (socal_unsol_cb_t),
31153db86aabSstevel 	    KM_SLEEP)) == (socal_unsol_cb_t *)NULL) {
31163db86aabSstevel 		return;
31173db86aabSstevel 	}
31183db86aabSstevel 	mutex_enter(&port_statep->sp_mtx);
31193db86aabSstevel 	cbentry->statec_cb = ulp_statec_callback;
31203db86aabSstevel 	cbentry->els_cb = ulp_els_callback;
31213db86aabSstevel 	cbentry->data_cb = ulp_data_callback;
31223db86aabSstevel 	cbentry->arg = arg;
31233db86aabSstevel 	cbentry->type = type;
31243db86aabSstevel 
31253db86aabSstevel 	cbentry->next = port_statep->sp_unsol_cb;
31263db86aabSstevel 	port_statep->sp_unsol_cb = cbentry;
31273db86aabSstevel 	mutex_exit(&port_statep->sp_mtx);
31283db86aabSstevel }
31293db86aabSstevel 
31303db86aabSstevel 
31313db86aabSstevel /*
31323db86aabSstevel  * remove a ULP with matching type and arg
31333db86aabSstevel  */
31343db86aabSstevel static void
31353db86aabSstevel socal_remove_ulp(void *ssp, uint_t port, uchar_t type, void *arg)
31363db86aabSstevel {
31373db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
31383db86aabSstevel 	socal_port_t		*port_statep;
31393db86aabSstevel 	socal_unsol_cb_t	*cbentry;
31403db86aabSstevel 	socal_unsol_cb_t	*p_cbentry;
31413db86aabSstevel 
31423db86aabSstevel 
31433db86aabSstevel 	ASSERT(ssp != NULL);
31443db86aabSstevel 	port_statep = &socalp->port_state[port];
31453db86aabSstevel 	ASSERT(port_statep != NULL);
31463db86aabSstevel 
31473db86aabSstevel 	/* scan the list of unsolicited callback entries */
31483db86aabSstevel 	mutex_enter(&port_statep->sp_mtx);
31493db86aabSstevel 	p_cbentry = NULL;
31503db86aabSstevel 	for (cbentry = port_statep->sp_unsol_cb;
31513db86aabSstevel 	    cbentry != NULL;
31523db86aabSstevel 	    p_cbentry = cbentry, cbentry = cbentry->next) {
31533db86aabSstevel 		if ((cbentry->type != type) || (cbentry->arg != arg)) {
31543db86aabSstevel 			continue;	/* this entry  doesn't match */
31553db86aabSstevel 		}
31563db86aabSstevel 		/* found entry to remove */
31573db86aabSstevel 		if (port_statep->sp_unsol_cb == cbentry) {
31583db86aabSstevel 			/* remove first entry in list */
31593db86aabSstevel 			port_statep->sp_unsol_cb = cbentry->next;
31603db86aabSstevel 		} else {
31613db86aabSstevel 			/* remove other entry in list */
31623db86aabSstevel 			if (p_cbentry)
31633db86aabSstevel 				p_cbentry->next = cbentry->next;
31643db86aabSstevel 		}
31653db86aabSstevel 		kmem_free((void *)cbentry, sizeof (socal_unsol_cb_t));
31663db86aabSstevel 		DEBUGF(2, (CE_CONT, "socal port %d ULP removed\n", port));
31673db86aabSstevel 		break;
31683db86aabSstevel 	}
31693db86aabSstevel 	mutex_exit(&port_statep->sp_mtx);
31703db86aabSstevel }
31713db86aabSstevel 
31723db86aabSstevel 
31733db86aabSstevel /*
31743db86aabSstevel  * static unsigned int
31753db86aabSstevel  * socal_intr() - this is the interrupt routine for the SOC. Process all
31763db86aabSstevel  *	possible incoming interrupts from the soc device.
31773db86aabSstevel  */
31783db86aabSstevel 
31793db86aabSstevel static unsigned int
31803db86aabSstevel socal_intr(caddr_t arg)
31813db86aabSstevel {
31823db86aabSstevel 	socal_state_t *socalp = (socal_state_t *)arg;
31833db86aabSstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
31843db86aabSstevel 	unsigned csr;
31853db86aabSstevel 	int cause = 0;
31863db86aabSstevel #if !defined(lint)
31873db86aabSstevel 	int instance = ddi_get_instance(socalp->dip);
31883db86aabSstevel #endif
31893db86aabSstevel 	int i, j, request;
31903db86aabSstevel 	char full;
31913db86aabSstevel 	struct fcal_packet *fpkt, *nfpkt;
31923db86aabSstevel 
31933db86aabSstevel 	csr = socalreg->socal_csr.w;
31943db86aabSstevel 	cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
31953db86aabSstevel 
31963db86aabSstevel 	DEBUGF(2, (CE_CONT,
31973db86aabSstevel 	    "socal%d: intr: csr: 0x%x cause: 0x%x\n",
31983db86aabSstevel 	    instance, csr, cause));
31993db86aabSstevel 
32003db86aabSstevel 	if (!cause) {
32013db86aabSstevel 		socalp->socal_on_intr = 0;
32023db86aabSstevel 		return (DDI_INTR_UNCLAIMED);
32033db86aabSstevel 	}
32043db86aabSstevel 
32053db86aabSstevel 	socalp->socal_on_intr = 1;
32063db86aabSstevel 
32073db86aabSstevel 	while (cause) {
32083db86aabSstevel 
32093db86aabSstevel 	/*
32103db86aabSstevel 	 * Process the unsolicited messages first in case there are some
32113db86aabSstevel 	 * high priority async events that we should act on.
32123db86aabSstevel 	 *
32133db86aabSstevel 	 */
32143db86aabSstevel 
32153db86aabSstevel 		if (cause & SOCAL_CSR_RSP_QUE_1) {
32163db86aabSstevel 			socal_intr_unsolicited(socalp, 1);
32173db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did unsolicited\n", instance));
32183db86aabSstevel 		}
32193db86aabSstevel 
32203db86aabSstevel 		if (cause & SOCAL_CSR_RSP_QUE_0) {
32213db86aabSstevel 			socal_intr_solicited(socalp, 0);
32223db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did solicited\n", instance));
32233db86aabSstevel 		}
32243db86aabSstevel 
32253db86aabSstevel 	/*
32263db86aabSstevel 	 * for use with token-only response queues in the future
32273db86aabSstevel 	 * if (cause & SOCAL_CSR_RSP_QUE_0) {
32283db86aabSstevel 	 *	socal_intr_solicited(socalp, 0);
32293db86aabSstevel 	 * }
32303db86aabSstevel 	 */
32313db86aabSstevel 
32323db86aabSstevel 
32333db86aabSstevel 	/*
32343db86aabSstevel 	 * Process any request interrupts
32353db86aabSstevel 	 * We only allow request interrupts when the request
32363db86aabSstevel 	 * queue is full and we are waiting so we can enque
32373db86aabSstevel 	 * another command.
32383db86aabSstevel 	 */
32393db86aabSstevel 		if ((request = (cause & SOCAL_CSR_HOST_TO_SOCAL)) != 0) {
32403db86aabSstevel 		socalp->socal_stats.reqq_intrs++;
32413db86aabSstevel 		for (i = SOCAL_CSR_1ST_H_TO_S, j = 0; j < SOCAL_N_CQS;
32423db86aabSstevel 		    j++, i <<= 1) {
32433db86aabSstevel 			if (request & i) {
32443db86aabSstevel 			socal_kcq_t *kcq = &socalp->request[j];
32453db86aabSstevel 
32463db86aabSstevel 			if (kcq->skc_full) {
32473db86aabSstevel 				mutex_enter(&kcq->skc_mtx);
32483db86aabSstevel 				full = kcq->skc_full;
32493db86aabSstevel 				kcq->skc_full = 0;
32503db86aabSstevel 				while ((fpkt = kcq->skc_overflowh) != NULL) {
32513db86aabSstevel 				nfpkt = fpkt->fcal_pkt_next;
32523db86aabSstevel 				fpkt->fcal_pkt_next = NULL;
32533db86aabSstevel 				kcq->skc_overflowh = nfpkt;
32543db86aabSstevel 				if (socal_cq_enque(socalp, (socal_port_t *)
32553db86aabSstevel 				    fpkt->fcal_pkt_cookie,
32563db86aabSstevel 				    (cqe_t *)&fpkt->fcal_socal_request,
32573db86aabSstevel 				    j, FCAL_NOSLEEP, NULL, 1) !=
32583db86aabSstevel 				    FCAL_TRANSPORT_SUCCESS) {
32593db86aabSstevel 					break;
32603db86aabSstevel 				}
32613db86aabSstevel 				}
32623db86aabSstevel 				if (!kcq->skc_overflowh) {
32633db86aabSstevel 				if (full & SOCAL_SKC_SLEEP)
32643db86aabSstevel 					cv_broadcast(&kcq->skc_cv);
32653db86aabSstevel 
32663db86aabSstevel 			    /* Disable this queue's intrs */
32673db86aabSstevel 				DEBUGF(2, (CE_CONT,
32683db86aabSstevel 				    "socal%d: req que %d overflow cleared\n",
32693db86aabSstevel 				    instance, j));
32703db86aabSstevel 				mutex_enter(&socalp->k_imr_mtx);
32713db86aabSstevel 				socalp->socal_rp->socal_imr =
32723db86aabSstevel 				    (socalp->socal_k_imr &= ~i);
32733db86aabSstevel 				mutex_exit(&socalp->k_imr_mtx);
32743db86aabSstevel 				}
32753db86aabSstevel 				mutex_exit(&kcq->skc_mtx);
32763db86aabSstevel 			}
32773db86aabSstevel 			}
32783db86aabSstevel 		}
32793db86aabSstevel 		}
32803db86aabSstevel 		csr = socalreg->socal_csr.w;
32813db86aabSstevel 		cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
32823db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did request queues\n", instance));
32833db86aabSstevel 
32843db86aabSstevel 	}
32853db86aabSstevel 
32863db86aabSstevel 	socalp->socal_on_intr = 0;
32873db86aabSstevel 	return (DDI_INTR_CLAIMED);
32883db86aabSstevel }
32893db86aabSstevel 
32903db86aabSstevel static void
32913db86aabSstevel socal_intr_solicited(socal_state_t *socalp, uint32_t srq)
32923db86aabSstevel {
32933db86aabSstevel 	socal_kcq_t		*kcq;
32943db86aabSstevel 	volatile socal_kcq_t	*kcqv;
32953db86aabSstevel 	soc_response_t		*srp;
32963db86aabSstevel 	cqe_t			*cqe;
32973db86aabSstevel 	uint_t			status, i;
32983db86aabSstevel 	fcal_packet_t		*fcalpkt = NULL;
32993db86aabSstevel 	soc_header_t		*shp;
33003db86aabSstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
33013db86aabSstevel 	caddr_t			src, dst;
33023db86aabSstevel 	uchar_t			index_in;
33033db86aabSstevel 	cq_hdr_t		*cq_hdr;
33043db86aabSstevel 	char			val;
33053db86aabSstevel 	int			port;
33063db86aabSstevel 
33073db86aabSstevel #if defined(DEBUG) && !defined(lint)
33083db86aabSstevel 	int instance = ddi_get_instance(socalp->dip);
33093db86aabSstevel #endif
33103db86aabSstevel 	auto char buf[80];
33113db86aabSstevel 
33123db86aabSstevel 	kcq = &socalp->response[srq];
33133db86aabSstevel 	kcqv = (volatile socal_kcq_t *)kcq;
33143db86aabSstevel 	DEBUGF(4, (CE_CONT, "socal%d intr_sol: entered \n", instance));
33153db86aabSstevel 
33163db86aabSstevel 	/*
33173db86aabSstevel 	 * Grab lock for request queue.
33183db86aabSstevel 	 */
33193db86aabSstevel 	mutex_enter(&kcq->skc_mtx);
33203db86aabSstevel 
33213db86aabSstevel 	/*
33223db86aabSstevel 	 * Process as many response queue entries as we can.
33233db86aabSstevel 	 */
33243db86aabSstevel 	cqe = &(kcq->skc_cq[kcqv->skc_out]);
33253db86aabSstevel 
33263db86aabSstevel 	index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
33273db86aabSstevel 
33283db86aabSstevel 	if (index_in == kcqv->skc_out) {
33293db86aabSstevel 		socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
33303db86aabSstevel 		    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
33313db86aabSstevel 
33323db86aabSstevel 		/* make sure the write completed */
33333db86aabSstevel 		i = socalreg->socal_csr.w;
33343db86aabSstevel 
33353db86aabSstevel 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
33363db86aabSstevel 	}
33373db86aabSstevel 
33383db86aabSstevel 	kcqv->skc_in = index_in;
33393db86aabSstevel 
33403db86aabSstevel 	while (kcqv->skc_out != index_in) {
33413db86aabSstevel 		/* Find out where the newest entry lives in the queue */
33423db86aabSstevel 		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
33433db86aabSstevel 		    DDI_DMA_SYNC_FORKERNEL);
33443db86aabSstevel 
33453db86aabSstevel 		srp = (soc_response_t *)cqe;
33463db86aabSstevel 		port = srp->sr_soc_hdr.sh_flags & SOC_PORT_B;
33473db86aabSstevel 		shp = &srp->sr_soc_hdr;
33483db86aabSstevel 		cq_hdr = &srp->sr_cqhdr;
33493db86aabSstevel 		/*
33503db86aabSstevel 		 * It turns out that on faster CPU's we have a problem where
33513db86aabSstevel 		 * the soc interrupts us before the response has been DMA'ed
33523db86aabSstevel 		 * in. This should not happen but does !!. So to workaround
33533db86aabSstevel 		 * the problem for now, check the sequence # of the response.
33543db86aabSstevel 		 * If it does not match with what we have, we must be
33553db86aabSstevel 		 * reading stale data
33563db86aabSstevel 		 */
33573db86aabSstevel 		if (cq_hdr->cq_hdr_seqno != kcqv->skc_seqno) {
33583db86aabSstevel #if defined(DEBUG) && !defined(lint)
33593db86aabSstevel 			socal_read_stale_data++;
33603db86aabSstevel #endif
33613db86aabSstevel 			if (kcq->deferred_intr_timeoutid) {
33623db86aabSstevel 				mutex_exit(&kcq->skc_mtx);
33633db86aabSstevel 				return;
33643db86aabSstevel 			} else {
33653db86aabSstevel 				kcq->skc_saved_out = kcqv->skc_out;
33663db86aabSstevel 				kcq->skc_saved_seqno = kcqv->skc_seqno;
33673db86aabSstevel 				kcq->deferred_intr_timeoutid = timeout(
33683db86aabSstevel 				    socal_deferred_intr, (caddr_t)kcq,
33693db86aabSstevel 				    drv_usectohz(10000));
33703db86aabSstevel 				mutex_exit(&kcq->skc_mtx);
33713db86aabSstevel 				return;
33723db86aabSstevel 			}
33733db86aabSstevel 		}
33743db86aabSstevel 
33753db86aabSstevel 		fcalpkt = (fcal_packet_t *)
33763db86aabSstevel 		    SOCAL_ID_LOOKUP(shp->sh_request_token);
33773db86aabSstevel 
33783db86aabSstevel 		if ((socal_core & SOCAL_TAKE_CORE) && ddi_peek8(socalp->dip,
33793db86aabSstevel 		    (char *)fcalpkt, &val) != DDI_SUCCESS) {
33803db86aabSstevel 			cmn_err(CE_WARN, "bad token = %p\n", (void *)fcalpkt);
33813db86aabSstevel 			mutex_exit(&kcq->skc_mtx);
33823db86aabSstevel 			socal_take_core(socalp);
33833db86aabSstevel 		}
33843db86aabSstevel 
33853db86aabSstevel 		if ((fcalpkt == (fcal_packet_t *)NULL) ||
33863db86aabSstevel 		    (fcalpkt->fcal_magic != FCALP_MAGIC)) {
33873db86aabSstevel 			(void) sprintf(buf, "!invalid FC packet; \n\
33883db86aabSstevel 			    in, out, seqno = 0x%x, 0x%x, 0x%x\n",
33893db86aabSstevel 			    kcqv->skc_in, kcqv->skc_out, kcqv->skc_seqno);
33903db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "link.4060", buf);
33913db86aabSstevel 			DEBUGF(4, (CE_CONT,
33923db86aabSstevel 			    "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
33933db86aabSstevel 			    socalreg->socal_cr.w,
33943db86aabSstevel 			    socalreg->socal_sae.w,
33953db86aabSstevel 			    socalreg->socal_csr.w,
33963db86aabSstevel 			    socalreg->socal_imr));
33973db86aabSstevel 		/*
33983db86aabSstevel 		 * Update response queue ptrs and soc registers.
33993db86aabSstevel 		 */
34003db86aabSstevel 			kcqv->skc_out++;
34013db86aabSstevel 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
34023db86aabSstevel 				kcqv->skc_out = 0;
34033db86aabSstevel 				kcqv->skc_seqno++;
34043db86aabSstevel 			}
34053db86aabSstevel 
34063db86aabSstevel 		} else {
34073db86aabSstevel 
34083db86aabSstevel 			DEBUGF(2, (CE_CONT, "packet 0x%p complete\n",
34093db86aabSstevel 			    fcalpkt));
34103db86aabSstevel 			status = srp->sr_soc_status;
34113db86aabSstevel 			fcalpkt->fcal_pkt_status = status;
34123db86aabSstevel 			DEBUGF(2, (CE_CONT, "SOC status: 0x%x\n", status));
34133db86aabSstevel 			/*
34143db86aabSstevel 			 * map soc status codes to
34153db86aabSstevel 			 * transport status codes
34163db86aabSstevel 			 */
34173db86aabSstevel 
34183db86aabSstevel 			ASSERT((fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)
34193db86aabSstevel 			    == 0);
34203db86aabSstevel 			mutex_enter(&socalp->abort_mtx);
34213db86aabSstevel 			fcalpkt->fcal_pkt_flags |= FCFLAG_COMPLETE;
34223db86aabSstevel 			mutex_exit(&socalp->abort_mtx);
34233db86aabSstevel 
34243db86aabSstevel 			/*
34253db86aabSstevel 			 * Copy the response frame header (if there is one)
34263db86aabSstevel 			 * so that the upper levels can use it.  Note that,
34273db86aabSstevel 			 * for now, we'll copy the header only if there was
34283db86aabSstevel 			 * some sort of non-OK status, to save the PIO reads
34293db86aabSstevel 			 * required to get the header from the host adapter's
34303db86aabSstevel 			 * xRAM.
34313db86aabSstevel 			 */
34323db86aabSstevel 			if (((status != FCAL_STATUS_OK) ||
34333db86aabSstevel 			    (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags
34343db86aabSstevel 			    & SOC_RESP_HEADER)) &&
34353db86aabSstevel 			    (srp->sr_soc_hdr.sh_flags & SOC_FC_HEADER)) {
34363db86aabSstevel 				src = (caddr_t)&srp->sr_fc_frame_hdr;
34373db86aabSstevel 				dst = (caddr_t)&fcalpkt->fcal_resp_hdr;
34383db86aabSstevel 				bcopy(src, dst, sizeof (fc_frame_header_t));
34393db86aabSstevel 				fcalpkt->fcal_pkt_flags |= FCFLAG_RESP_HEADER;
34403db86aabSstevel 				i = srp->sr_soc_hdr.sh_flags & SOC_PORT_B ?
34413db86aabSstevel 				    1 : 0;
34423db86aabSstevel 				if ((status != FCAL_STATUS_OK) &&
34433db86aabSstevel 				    (status <= FCAL_STATUS_MAX_STATUS)) {
34443db86aabSstevel 					socalp->socal_stats.pstats[i].
34453db86aabSstevel 					    resp_status[status]++;
34463db86aabSstevel 				} else {
34473db86aabSstevel 					socalp->socal_stats.pstats[i].
34483db86aabSstevel 					    resp_status[FCAL_STATUS_ERROR]++;
34493db86aabSstevel 				}
34503db86aabSstevel 			} else if (status == FCAL_STATUS_OK) {
345119397407SSherry Moore 				fcalpkt->fcal_socal_request.
345219397407SSherry Moore 				    sr_soc_hdr.sh_byte_cnt =
34533db86aabSstevel 				    shp->sh_byte_cnt;
34543db86aabSstevel 			}
34553db86aabSstevel 			fcalpkt->fcal_diag_status =
34563db86aabSstevel 			    (uint32_t)srp->sr_dataseg.fc_base;
34573db86aabSstevel 			fcalpkt->fcal_ncmds = srp->sr_ncmds;
34583db86aabSstevel 
34593db86aabSstevel 			/*
34603db86aabSstevel 			 * Update response queue ptrs and soc registers.
34613db86aabSstevel 			 */
34623db86aabSstevel 			kcqv->skc_out++;
34633db86aabSstevel 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
34643db86aabSstevel 				kcqv->skc_out = 0;
34653db86aabSstevel 				kcqv->skc_seqno++;
34663db86aabSstevel 			}
34673db86aabSstevel 
34683db86aabSstevel 			/* For incmplt DMA offline loop by loopback */
34693db86aabSstevel 			if (fcalpkt->fcal_pkt_status ==
34703db86aabSstevel 			    FCAL_STATUS_INCOMPLETE_DMA_ERR) {
34713db86aabSstevel 				socal_port_t	*port_statep;
34723db86aabSstevel 				uint_t		r;
34733db86aabSstevel 
34743db86aabSstevel 				/*
34753db86aabSstevel 				 * Give up the mutex to avoid a deadlock
34763db86aabSstevel 				 * with the loopback routine.
34773db86aabSstevel 				 */
34783db86aabSstevel 				mutex_exit(&kcq->skc_mtx);
34793db86aabSstevel 
34803db86aabSstevel 				port_statep = &socalp->port_state[port];
34813db86aabSstevel 				mutex_enter(&port_statep->sp_mtx);
34823db86aabSstevel 				if (port_statep->sp_status &
34833db86aabSstevel 				    PORT_DISABLED) {
34843db86aabSstevel 					/* Already disabled */
34853db86aabSstevel 					mutex_exit(&port_statep->sp_mtx);
34863db86aabSstevel 				} else {
34873db86aabSstevel 					port_statep->sp_status |=
34883db86aabSstevel 					    PORT_DISABLED;
34893db86aabSstevel 					mutex_exit(&port_statep->sp_mtx);
34903db86aabSstevel 					(void) socal_diag_request(
34913db86aabSstevel 					    (void *)socalp, port,
34923db86aabSstevel 					    &r, SOC_DIAG_INT_LOOP);
34933db86aabSstevel 				}
34943db86aabSstevel 				/* reacquire mutex */
34953db86aabSstevel 				mutex_enter(&kcq->skc_mtx);
34963db86aabSstevel 			}
34973db86aabSstevel 
34983db86aabSstevel 			/*
34993db86aabSstevel 			 * Complete the packet *ONLY* if it not being aborted
35003db86aabSstevel 			 * or the abort has already completed.  Otherwise it is
35013db86aabSstevel 			 * not safe to free the ID.
35023db86aabSstevel 			 */
35033db86aabSstevel 			mutex_enter(&socalp->abort_mtx);
35043db86aabSstevel 			if (!(fcalpkt->fcal_pkt_flags & FCFLAG_ABORTING)) {
35053db86aabSstevel 				/*
35063db86aabSstevel 				 * Call the completion routine
35073db86aabSstevel 				 */
35083db86aabSstevel 				SOCAL_ID_FREE(shp->sh_request_token);
35093db86aabSstevel 				if (fcalpkt->fcal_pkt_comp != NULL) {
35103db86aabSstevel 					fcalpkt->fcal_cmd_state |=
35113db86aabSstevel 					    FCAL_CMD_COMPLETE;
35123db86aabSstevel 
35133db86aabSstevel 					/*
35143db86aabSstevel 					 * Give up the mutex to avoid a
35153db86aabSstevel 					 * deadlock with the callback routine.
35163db86aabSstevel 					 */
35173db86aabSstevel 					mutex_exit(&socalp->abort_mtx);
35183db86aabSstevel 					mutex_exit(&kcq->skc_mtx);
35193db86aabSstevel 
35203db86aabSstevel 					/* callback */
35213db86aabSstevel 					(*fcalpkt->fcal_pkt_comp)(fcalpkt);
35223db86aabSstevel 
35233db86aabSstevel 					/* reacquire mutex */
35243db86aabSstevel 					mutex_enter(&kcq->skc_mtx);
35253db86aabSstevel 				} else {
35263db86aabSstevel 					fcalpkt->fcal_cmd_state |=
35273db86aabSstevel 					    FCAL_CMD_COMPLETE;
35283db86aabSstevel 					mutex_exit(&socalp->abort_mtx);
35293db86aabSstevel 				}
35303db86aabSstevel 			} else {
35313db86aabSstevel 				mutex_exit(&socalp->abort_mtx);
35323db86aabSstevel 			}
35333db86aabSstevel 		}
35343db86aabSstevel 
35353db86aabSstevel 
35363db86aabSstevel 		if (kcq->skc_cq == NULL)
35373db86aabSstevel 			/*
35383db86aabSstevel 			 * This action averts a potential PANIC scenario
35393db86aabSstevel 			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
35403db86aabSstevel 			 * when we let it go, to call our completion routine,
35413db86aabSstevel 			 * and "initialized" the response queue.  We exit our
35423db86aabSstevel 			 * processing loop here, thereby averting a PANIC due
35433db86aabSstevel 			 * to a NULL de-reference from the response queue.
35443db86aabSstevel 			 *
35453db86aabSstevel 			 * Note that this is an interim measure that needs
35463db86aabSstevel 			 * to be revisited when this driver is next revised
35473db86aabSstevel 			 * for enhanced performance.
35483db86aabSstevel 			 */
35493db86aabSstevel 			break;
35503db86aabSstevel 
35513db86aabSstevel 		/*
35523db86aabSstevel 		 * We need to re-read the input and output pointers in
35533db86aabSstevel 		 * case a polling routine should process some entries
35543db86aabSstevel 		 * from the response queue while we're doing a callback
35553db86aabSstevel 		 * routine with the response queue mutex dropped.
35563db86aabSstevel 		 */
35573db86aabSstevel 		cqe = &(kcq->skc_cq[kcqv->skc_out]);
35583db86aabSstevel 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
35593db86aabSstevel 
35603db86aabSstevel 		/*
35613db86aabSstevel 		 * Mess around with the hardware if we think we've run out
35623db86aabSstevel 		 * of entries in the queue, just to make sure we've read
35633db86aabSstevel 		 * all entries that are available.
35643db86aabSstevel 		 */
35653db86aabSstevel 
356619397407SSherry Moore 		socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
35673db86aabSstevel 		    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
35683db86aabSstevel 
35693db86aabSstevel 		/* Make sure the csr write has completed */
35703db86aabSstevel 		i = socalreg->socal_csr.w;
35713db86aabSstevel 		DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
35723db86aabSstevel 
35733db86aabSstevel 		/*
35743db86aabSstevel 		 * Update our idea of where the host adapter has placed
35753db86aabSstevel 		 * the most recent entry in the response queue and resync
35763db86aabSstevel 		 * the response queue
35773db86aabSstevel 		 */
357819397407SSherry Moore 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
35793db86aabSstevel 
35803db86aabSstevel 		kcqv->skc_in = index_in;
35813db86aabSstevel 	}
35823db86aabSstevel 
35833db86aabSstevel 	/* Drop lock for request queue. */
35843db86aabSstevel 	mutex_exit(&kcq->skc_mtx);
35853db86aabSstevel }
35863db86aabSstevel 
35873db86aabSstevel /*
35883db86aabSstevel  * Function name : socal_intr_unsolicited()
35893db86aabSstevel  *
35903db86aabSstevel  * Return Values : none
35913db86aabSstevel  *
35923db86aabSstevel  * Description	 : Processes entries in the unsolicited response
35933db86aabSstevel  *		   queue
35943db86aabSstevel  *
35953db86aabSstevel  *	The SOC+ will give us an unsolicited response
35963db86aabSstevel  *	whenever its status changes: OFFLINE, ONLINE,
35973db86aabSstevel  *	or in response to a packet arriving from an originator.
35983db86aabSstevel  *
35993db86aabSstevel  *	When message requests come in they will be placed in our
36003db86aabSstevel  *	buffer queue or in the next "inline" packet by the SOC hardware.
36013db86aabSstevel  *
36023db86aabSstevel  * Context	: Unsolicited interrupts must be masked
36033db86aabSstevel  */
36043db86aabSstevel 
36053db86aabSstevel static void
36063db86aabSstevel socal_intr_unsolicited(socal_state_t *socalp, uint32_t urq)
36073db86aabSstevel {
36083db86aabSstevel 	socal_kcq_t		*kcq;
36093db86aabSstevel 	volatile socal_kcq_t	*kcqv;
36103db86aabSstevel 	soc_response_t		*srp;
36113db86aabSstevel 	volatile cqe_t		*cqe;
36123db86aabSstevel 	int			port;
36133db86aabSstevel 	register uchar_t		t_index, t_seqno;
36143db86aabSstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
36153db86aabSstevel 	volatile cqe_t		*cqe_cont = NULL;
36163db86aabSstevel 	uint_t			i;
36173db86aabSstevel 	int			hdr_count;
36183db86aabSstevel 	int			status;
36193db86aabSstevel 	ushort_t		flags;
36203db86aabSstevel 	auto char		buf[256];
36213db86aabSstevel 	socal_port_t		*port_statep;
36223db86aabSstevel #if defined(DEBUG) && !defined(lint)
36233db86aabSstevel 	int			instance = ddi_get_instance(socalp->dip);
36243db86aabSstevel #endif
36253db86aabSstevel 	uchar_t			index_in;
36263db86aabSstevel 	socal_unsol_cb_t	*cblist;
36273db86aabSstevel 
36283db86aabSstevel 	kcq = &socalp->response[urq];
36293db86aabSstevel 	kcqv = (volatile socal_kcq_t *)kcq;
36303db86aabSstevel 
36313db86aabSstevel 	/*
36323db86aabSstevel 	 * Grab lock for response queue.
36333db86aabSstevel 	 */
36343db86aabSstevel 	mutex_enter(&kcq->skc_mtx);
36353db86aabSstevel 
36363db86aabSstevel 	cqe = (volatile cqe_t *)&(kcq->skc_cq[kcqv->skc_out]);
36373db86aabSstevel 
36383db86aabSstevel 	index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
36393db86aabSstevel 
36403db86aabSstevel 	kcqv->skc_in = index_in;
36413db86aabSstevel 
36423db86aabSstevel 	while (kcqv->skc_out != index_in) {
36433db86aabSstevel 		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
36443db86aabSstevel 		    DDI_DMA_SYNC_FORKERNEL);
36453db86aabSstevel 
36463db86aabSstevel 		/* Check for continuation entries */
36473db86aabSstevel 		if ((hdr_count = cqe->cqe_hdr.cq_hdr_count) != 1) {
36483db86aabSstevel 
36493db86aabSstevel 			t_seqno = kcqv->skc_seqno;
36503db86aabSstevel 			t_index = kcqv->skc_out + hdr_count;
36513db86aabSstevel 
36523db86aabSstevel 			i = index_in;
36533db86aabSstevel 			if (kcqv->skc_out > index_in)
36543db86aabSstevel 			i += kcq->skc_last_index + 1;
36553db86aabSstevel 
36563db86aabSstevel 		/*
36573db86aabSstevel 		 * If we think the continuation entries haven't yet
36583db86aabSstevel 		 * arrived, try once more before giving up
36593db86aabSstevel 		 */
36603db86aabSstevel 			if (i < t_index) {
36613db86aabSstevel 
36623db86aabSstevel 			socalreg->socal_csr.w =
36633db86aabSstevel 			    ((kcqv->skc_out << 24) |
36643db86aabSstevel 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
36653db86aabSstevel 
36663db86aabSstevel 			/* Make sure the csr write has completed */
36673db86aabSstevel 			i = socalreg->socal_csr.w;
36683db86aabSstevel 
36693db86aabSstevel 			/*
36703db86aabSstevel 			 * Update our idea of where the host adapter has placed
36713db86aabSstevel 			 * the most recent entry in the response queue
36723db86aabSstevel 			 */
36733db86aabSstevel 			i = index_in = SOCAL_RESPONSEQ_INDEX(urq,
36743db86aabSstevel 			    socalreg->socal_rspp.w);
36753db86aabSstevel 			if (kcqv->skc_out > index_in)
36763db86aabSstevel 				i += kcq->skc_last_index + 1;
36773db86aabSstevel 
36783db86aabSstevel 			/*
36793db86aabSstevel 			 * Exit if the continuation entries haven't yet
36803db86aabSstevel 			 * arrived
36813db86aabSstevel 			 */
36823db86aabSstevel 			if (i < t_index)
36833db86aabSstevel 				break;
36843db86aabSstevel 			}
36853db86aabSstevel 
36863db86aabSstevel 			if (t_index > kcq->skc_last_index) {
36873db86aabSstevel 			t_seqno++;
36883db86aabSstevel 			t_index &= kcq->skc_last_index;
36893db86aabSstevel 			}
36903db86aabSstevel 
36913db86aabSstevel 			cqe_cont = (volatile cqe_t *)
369219397407SSherry Moore 			    &(kcq->skc_cq[t_index ? t_index - 1 :
369319397407SSherry Moore 			    kcq->skc_last_index]);
36943db86aabSstevel 
36953db86aabSstevel 
36963db86aabSstevel 		    /* A cq_hdr_count > 2 is illegal; throw away the response */
36973db86aabSstevel 
36983db86aabSstevel 		/*
36993db86aabSstevel 		 * XXX - should probably throw out as many entries as the
37003db86aabSstevel 		 * hdr_cout tells us there are
37013db86aabSstevel 		 */
37023db86aabSstevel 			if (hdr_count != 2) {
37033db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "driver.4030",
37043db86aabSstevel 			    "!too many continuation entries");
37053db86aabSstevel 			DEBUGF(4, (CE_CONT,
37063db86aabSstevel 			    "socal%d: soc+ unsolicited entry count = %d\n",
37073db86aabSstevel 			    instance, cqe->cqe_hdr.cq_hdr_count));
37083db86aabSstevel 
37093db86aabSstevel 			if ((++t_index & kcq->skc_last_index) == 0) {
37103db86aabSstevel 				t_index = 0;
37113db86aabSstevel 				t_seqno++;
37123db86aabSstevel 			}
37133db86aabSstevel 			kcqv->skc_out = t_index;
37143db86aabSstevel 			kcqv->skc_seqno = t_seqno;
37153db86aabSstevel 
37163db86aabSstevel 			cqe = &(kcq->skc_cq[kcqv->skc_out]);
37173db86aabSstevel 			cqe_cont = NULL;
37183db86aabSstevel 			continue;
37193db86aabSstevel 			}
37203db86aabSstevel 		}
37213db86aabSstevel 
37223db86aabSstevel 		/*
37233db86aabSstevel 		 * Update unsolicited response queue ptrs
37243db86aabSstevel 		 */
37253db86aabSstevel 		kcqv->skc_out++;
37263db86aabSstevel 		if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
37273db86aabSstevel 			kcqv->skc_out = 0;
37283db86aabSstevel 			kcqv->skc_seqno++;
37293db86aabSstevel 		}
37303db86aabSstevel 
37313db86aabSstevel 		if (cqe_cont != NULL) {
37323db86aabSstevel 			kcqv->skc_out++;
37333db86aabSstevel 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
37343db86aabSstevel 				kcqv->skc_out = 0;
37353db86aabSstevel 				kcqv->skc_seqno++;
37363db86aabSstevel 			}
37373db86aabSstevel 		}
37383db86aabSstevel 
37393db86aabSstevel 		if (index_in == kcqv->skc_out) {
37403db86aabSstevel 			socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
37413db86aabSstevel 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
37423db86aabSstevel 
37433db86aabSstevel 		/* Make sure the csr write has completed */
37443db86aabSstevel 			i = socalreg->socal_csr.w;
37453db86aabSstevel 		}
37463db86aabSstevel 
37473db86aabSstevel 		srp = (soc_response_t *)cqe;
37483db86aabSstevel 		flags = srp->sr_soc_hdr.sh_flags;
37493db86aabSstevel 		port = flags & SOC_PORT_B;
37503db86aabSstevel 		port_statep = &socalp->port_state[port];
37513db86aabSstevel 
37523db86aabSstevel 		/*
37533db86aabSstevel 		 * XXX need to deal buffer pool entries here
37543db86aabSstevel 		 */
37553db86aabSstevel 		switch (flags & ~SOC_PORT_B) {
37563db86aabSstevel 		case SOC_UNSOLICITED | SOC_FC_HEADER:
37573db86aabSstevel 
37583db86aabSstevel 			srp = (soc_response_t *)cqe;
37593db86aabSstevel 
37603db86aabSstevel 			switch (srp->sr_fc_frame_hdr.r_ctl & R_CTL_ROUTING) {
37613db86aabSstevel 			case R_CTL_EXTENDED_SVC:
37623db86aabSstevel 			/*
37633db86aabSstevel 			 * Extended Link Services frame received
37643db86aabSstevel 			 */
37653db86aabSstevel 			socalp->socal_stats.pstats[port].els_rcvd++;
37663db86aabSstevel 			socal_us_els(socalp, (cqe_t *)cqe, (caddr_t)cqe_cont);
37673db86aabSstevel 
37683db86aabSstevel 			/* do callbacks to any interested ULPs */
37693db86aabSstevel 			mutex_enter(&port_statep->sp_mtx);
37703db86aabSstevel 			for (cblist = port_statep->sp_unsol_cb; cblist;
37713db86aabSstevel 			    cblist = cblist->next) {
37723db86aabSstevel 				if (cblist->els_cb) {
37733db86aabSstevel 					mutex_exit(&port_statep->sp_mtx);
37743db86aabSstevel 					mutex_exit(&kcq->skc_mtx);
377519397407SSherry Moore 					cblist->els_cb(cblist->arg,
377619397407SSherry Moore 					    (cqe_t *)cqe,
37773db86aabSstevel 					    (caddr_t)cqe_cont);
37783db86aabSstevel 					mutex_enter(&kcq->skc_mtx);
37793db86aabSstevel 					mutex_enter(&port_statep->sp_mtx);
37803db86aabSstevel 				}
37813db86aabSstevel 			}
37823db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
37833db86aabSstevel 			break;
37843db86aabSstevel 			case R_CTL_BASIC_SVC:
37853db86aabSstevel 			(void) sprintf(buf,
37863db86aabSstevel 			    "!unsupported Link Service command: 0x%x",
37873db86aabSstevel 			    srp->sr_fc_frame_hdr.type);
37883db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "link.4020", buf);
37893db86aabSstevel 			break;
37903db86aabSstevel 			case R_CTL_DEVICE_DATA:
37913db86aabSstevel 			switch (srp->sr_fc_frame_hdr.type) {
37923db86aabSstevel 			default:
37933db86aabSstevel 				mutex_enter(&port_statep->sp_mtx);
37943db86aabSstevel 				status = 1;
37953db86aabSstevel 				for (cblist = port_statep->sp_unsol_cb; cblist;
37963db86aabSstevel 				    cblist = cblist->next) {
37973db86aabSstevel 				if (cblist->data_cb &&
37983db86aabSstevel 				    (cblist->type ==
37993db86aabSstevel 				    srp->sr_fc_frame_hdr.type)) {
38003db86aabSstevel 					mutex_exit(&port_statep->sp_mtx);
38013db86aabSstevel 					mutex_exit(&kcq->skc_mtx);
38023db86aabSstevel 					cblist->data_cb(cblist->arg,
38033db86aabSstevel 					    (cqe_t *)cqe, (caddr_t)cqe_cont);
38043db86aabSstevel 					mutex_enter(&kcq->skc_mtx);
38053db86aabSstevel 					mutex_enter(&port_statep->sp_mtx);
38063db86aabSstevel 					status = 0;
38073db86aabSstevel 				}
38083db86aabSstevel 				}
38093db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
38103db86aabSstevel 
38113db86aabSstevel 				if (status == 0)
38123db86aabSstevel 				break;
38133db86aabSstevel 
381419397407SSherry Moore 				(void) sprintf(buf,
381519397407SSherry Moore 				    "!unknown FC-4 command: 0x%x",
38163db86aabSstevel 				    srp->sr_fc_frame_hdr.type);
381719397407SSherry Moore 				socal_disp_err(socalp, CE_WARN,
381819397407SSherry Moore 				    "link.4030", buf);
38193db86aabSstevel 				break;
38203db86aabSstevel 			}
38213db86aabSstevel 			break;
38223db86aabSstevel 			default:
38233db86aabSstevel 			(void) sprintf(buf, "!unsupported FC frame R_CTL: 0x%x",
38243db86aabSstevel 			    srp->sr_fc_frame_hdr.r_ctl);
38253db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "link.4040", buf);
38263db86aabSstevel 			break;
38273db86aabSstevel 			}
38283db86aabSstevel 			break;
38293db86aabSstevel 
38303db86aabSstevel 		case SOC_STATUS: {
38313db86aabSstevel 
38323db86aabSstevel 			/*
38333db86aabSstevel 			 * Note that only the lsbyte of the status has
38343db86aabSstevel 			 * interesting information...
38353db86aabSstevel 			 */
38363db86aabSstevel 			status = srp->sr_soc_status;
38373db86aabSstevel 
38383db86aabSstevel 			switch (status) {
38393db86aabSstevel 
38403db86aabSstevel 			case FCAL_STATUS_ONLINE:
38413db86aabSstevel 				(void) sprintf(buf,
38423db86aabSstevel 				"!port %d: Fibre Channel is ONLINE\n", port);
38433db86aabSstevel 				socal_disp_err(socalp, CE_CONT, "link.6010",
38443db86aabSstevel 				    buf);
38453db86aabSstevel 				mutex_enter(&port_statep->sp_mtx);
38463db86aabSstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38473db86aabSstevel 				port_statep->sp_status |= PORT_ONLINE;
38483db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
38493db86aabSstevel 				socalp->socal_stats.pstats[port].onlines++;
38503db86aabSstevel 				DEBUGF(4, (CE_CONT,
38513db86aabSstevel 				    "socal%d intr_unsol: ONLINE intr\n",
38523db86aabSstevel 				    instance));
38533db86aabSstevel 				break;
38543db86aabSstevel 
38553db86aabSstevel 			case FCAL_STATUS_LOOP_ONLINE:
38563db86aabSstevel 				(void) sprintf(buf,
38573db86aabSstevel 				"!port %d: Fibre Channel Loop is ONLINE\n",
38583db86aabSstevel 				    port);
38593db86aabSstevel 				socal_disp_err(socalp, CE_CONT, "link.6010",
38603db86aabSstevel 				    buf);
38613db86aabSstevel 				mutex_enter(&port_statep->sp_mtx);
38623db86aabSstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38633db86aabSstevel 				port_statep->sp_status |= PORT_ONLINE_LOOP;
38643db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
38653db86aabSstevel 				socalp->socal_stats.pstats[port].online_loops++;
38663db86aabSstevel 				DEBUGF(4, (CE_CONT,
38673db86aabSstevel 				    "socal%d intr_unsol: ONLINE-LOOP intr\n",
38683db86aabSstevel 				    instance));
38693db86aabSstevel 				break;
38703db86aabSstevel 
38713db86aabSstevel 			case FCAL_STATUS_ERR_OFFLINE:
38723db86aabSstevel 				/*
38733db86aabSstevel 				 * SOC and Responder will both flush
38743db86aabSstevel 				 * all active commands.
38753db86aabSstevel 				 * So I don't have to do anything
38763db86aabSstevel 				 * until it comes back online.
38773db86aabSstevel 				 */
38783db86aabSstevel 				(void) sprintf(buf,
38793db86aabSstevel 				"!port %d: Fibre Channel is OFFLINE\n", port);
38803db86aabSstevel 				socal_disp_err(socalp, CE_CONT, "link.5010",
38813db86aabSstevel 				    buf);
38823db86aabSstevel 
38833db86aabSstevel 				mutex_enter(&port_statep->sp_mtx);
38843db86aabSstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38853db86aabSstevel 				port_statep->sp_status |= PORT_OFFLINE;
38863db86aabSstevel 				port_statep->sp_lilpmap_valid = 0;
38873db86aabSstevel 				mutex_exit(&port_statep->sp_mtx);
38883db86aabSstevel 				socalp->socal_stats.pstats[port].offlines++;
38893db86aabSstevel 				DEBUGF(4, (CE_CONT,
38903db86aabSstevel 				    "socal%d intr_unsol: OFFLINE intr\n",
38913db86aabSstevel 				    instance));
38923db86aabSstevel 
38933db86aabSstevel 				break;
38943db86aabSstevel 			default:
38953db86aabSstevel 				(void) sprintf(buf, "!unknown status: 0x%x\n",
38963db86aabSstevel 				    status);
38973db86aabSstevel 				socal_disp_err(socalp, CE_WARN, "link.3020",
38983db86aabSstevel 				    buf);
38993db86aabSstevel 			}
39003db86aabSstevel 			mutex_exit(&kcq->skc_mtx);
39013db86aabSstevel 			mutex_enter(&port_statep->sp_mtx);
39023db86aabSstevel 			for (cblist = port_statep->sp_unsol_cb; cblist;
39033db86aabSstevel 			    cblist = cblist->next) {
39043db86aabSstevel 				if (cblist->statec_cb) {
39053db86aabSstevel 					mutex_exit(&port_statep->sp_mtx);
390619397407SSherry Moore 					(*cblist->statec_cb)(cblist->arg,
390719397407SSherry Moore 					    status);
39083db86aabSstevel 					mutex_enter(&port_statep->sp_mtx);
39093db86aabSstevel 				}
39103db86aabSstevel 			}
39113db86aabSstevel 			mutex_exit(&port_statep->sp_mtx);
39123db86aabSstevel 			if (status == FCAL_STATUS_ERR_OFFLINE) {
39133db86aabSstevel 				socal_flush_overflowq(socalp, port,
39143db86aabSstevel 				    CQ_REQUEST_0);
39153db86aabSstevel 				socal_flush_overflowq(socalp, port,
39163db86aabSstevel 				    CQ_REQUEST_1);
39173db86aabSstevel 			}
39183db86aabSstevel 			mutex_enter(&kcq->skc_mtx);
39193db86aabSstevel 			break;
39203db86aabSstevel 		}
39213db86aabSstevel 		default:
39223db86aabSstevel 			(void) sprintf(buf, "!unexpected state: flags: 0x%x\n",
39233db86aabSstevel 			    flags);
39243db86aabSstevel 			socal_disp_err(socalp, CE_WARN, "link.4050", buf);
39253db86aabSstevel 			DEBUGF(4, (CE_CONT,
39263db86aabSstevel 			    "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
39273db86aabSstevel 			    socalp->socal_rp->socal_cr.w,
39283db86aabSstevel 			    socalp->socal_rp->socal_sae.w,
39293db86aabSstevel 			    socalp->socal_rp->socal_csr.w,
39303db86aabSstevel 			    socalp->socal_rp->socal_imr));
39313db86aabSstevel 		}
39323db86aabSstevel 
39333db86aabSstevel 
39343db86aabSstevel 		if (kcq->skc_cq == NULL)
39353db86aabSstevel 			/*
39363db86aabSstevel 			 * This action averts a potential PANIC scenario
39373db86aabSstevel 			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
39383db86aabSstevel 			 * when we let it go, to call our completion routine,
39393db86aabSstevel 			 * and "initialized" the response queue.  We exit our
39403db86aabSstevel 			 * processing loop here, thereby averting a PANIC due
39413db86aabSstevel 			 * to a NULL de-reference from the response queue.
39423db86aabSstevel 			 *
39433db86aabSstevel 			 * Note that this is an interim measure that needs
39443db86aabSstevel 			 * to be revisited when this driver is next revised
39453db86aabSstevel 			 * for enhanced performance.
39463db86aabSstevel 			 */
39473db86aabSstevel 			break;
39483db86aabSstevel 
39493db86aabSstevel 		/*
39503db86aabSstevel 		 * We need to re-read the input and output pointers in
39513db86aabSstevel 		 * case a polling routine should process some entries
39523db86aabSstevel 		 * from the response queue while we're doing a callback
39533db86aabSstevel 		 * routine with the response queue mutex dropped.
39543db86aabSstevel 		 */
39553db86aabSstevel 		cqe = &(kcq->skc_cq[kcqv->skc_out]);
39563db86aabSstevel 		index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
39573db86aabSstevel 		cqe_cont = NULL;
39583db86aabSstevel 
39593db86aabSstevel 		/*
39603db86aabSstevel 		 * Mess around with the hardware if we think we've run out
39613db86aabSstevel 		 * of entries in the queue, just to make sure we've read
39623db86aabSstevel 		 * all entries that are available.
39633db86aabSstevel 		 */
39643db86aabSstevel 		if (index_in == kcqv->skc_out) {
39653db86aabSstevel 
39663db86aabSstevel 			socalreg->socal_csr.w =
39673db86aabSstevel 			    ((kcqv->skc_out << 24) |
39683db86aabSstevel 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
39693db86aabSstevel 
39703db86aabSstevel 		/* Make sure the csr write has completed */
39713db86aabSstevel 			i = socalreg->socal_csr.w;
39723db86aabSstevel 
39733db86aabSstevel 		/*
39743db86aabSstevel 		 * Update our idea of where the host adapter has placed
39753db86aabSstevel 		 * the most recent entry in the response queue
39763db86aabSstevel 		 */
39773db86aabSstevel 			index_in =
39783db86aabSstevel 			    SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
39793db86aabSstevel 		}
39803db86aabSstevel 
39813db86aabSstevel 		socalp->socal_stats.pstats[port].unsol_resps++;
39823db86aabSstevel 
39833db86aabSstevel 		kcqv->skc_in = index_in;
39843db86aabSstevel 
39853db86aabSstevel 	}
39863db86aabSstevel 
39873db86aabSstevel 	/* Release lock for response queue. */
39883db86aabSstevel 	mutex_exit(&kcq->skc_mtx);
39893db86aabSstevel }
39903db86aabSstevel 
39913db86aabSstevel /*
39923db86aabSstevel  * socal_us_els() - This function handles unsolicited extended link
39933db86aabSstevel  *	service responses received from the soc.
39943db86aabSstevel  */
39953db86aabSstevel static void
39963db86aabSstevel socal_us_els(socal_state_t *socalp, cqe_t *cqe, caddr_t payload)
39973db86aabSstevel {
39983db86aabSstevel 	soc_response_t	*srp = (soc_response_t *)cqe;
39993db86aabSstevel 	els_payload_t	*els = (els_payload_t *)payload;
40003db86aabSstevel 	int	i;
40013db86aabSstevel 	char   *bp;
40023db86aabSstevel 	auto	char buf[256];
40033db86aabSstevel 
40043db86aabSstevel 	/*
40053db86aabSstevel 	 * There should be a CQE continuation entry for all
40063db86aabSstevel 	 * extended link services
40073db86aabSstevel 	 */
40083db86aabSstevel 	if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
40093db86aabSstevel 		socal_disp_err(socalp, CE_WARN, "link.4010",
40103db86aabSstevel 		"!incomplete continuation entry");
40113db86aabSstevel 		return;
40123db86aabSstevel 	}
40133db86aabSstevel 
40143db86aabSstevel 	/* Quietly impose a maximum byte count */
40153db86aabSstevel 	if (i > SOC_CQE_PAYLOAD)
40163db86aabSstevel 		i = SOC_CQE_PAYLOAD;
40173db86aabSstevel 	i -= sizeof (union els_cmd_u);
40183db86aabSstevel 
40193db86aabSstevel 	/*
40203db86aabSstevel 	 * Decode the LS_Command code
40213db86aabSstevel 	 */
40223db86aabSstevel 	switch (els->els_cmd.c.ls_command) {
40233db86aabSstevel 		case LA_ELS_DISPLAY:
40243db86aabSstevel 		els->els_data[i] = '\0';	/* terminate the string */
40253db86aabSstevel 		for (bp = (char *)&(els->els_data[0]); *bp; bp++) {
40263db86aabSstevel 			/* squash newlines */
40273db86aabSstevel 			if (*bp == '\n') *bp = ' ';
40283db86aabSstevel 		}
40293db86aabSstevel 		(void) sprintf(buf, "!message: %s\n", els->els_data);
40303db86aabSstevel 		socal_disp_err(socalp, CE_CONT, "link.1010", buf);
40313db86aabSstevel 		break;
40323db86aabSstevel 
40333db86aabSstevel 		default:
40343db86aabSstevel 		DEBUGF(3, (CE_CONT, "!unknown LS_Command, %x\n",
40353db86aabSstevel 		    els->els_cmd.i));
40363db86aabSstevel 		break;
40373db86aabSstevel 	}
40383db86aabSstevel 
40393db86aabSstevel }
40403db86aabSstevel 
40413db86aabSstevel /*ARGSUSED*/
40423db86aabSstevel static fcal_packet_t *
40433db86aabSstevel socal_packet_alloc(socal_state_t *socalp, fcal_sleep_t sleep)
40443db86aabSstevel {
40453db86aabSstevel 	int flag;
40463db86aabSstevel 	fcal_packet_t *pkt;
40473db86aabSstevel 
40483db86aabSstevel 	if (sleep == FCAL_SLEEP)
40493db86aabSstevel 		flag = KM_SLEEP;
40503db86aabSstevel 	else
40513db86aabSstevel 		flag = KM_NOSLEEP;
40523db86aabSstevel 
40533db86aabSstevel 	pkt = (fcal_packet_t *)kmem_zalloc(sizeof (fcal_packet_t), flag);
40543db86aabSstevel 
40553db86aabSstevel 	if (pkt != (fcal_packet_t *)NULL)
40563db86aabSstevel 		pkt->fcal_magic = FCALP_MAGIC;
40573db86aabSstevel 
40583db86aabSstevel 	return (pkt);
40593db86aabSstevel }
40603db86aabSstevel 
40613db86aabSstevel static void
40623db86aabSstevel socal_packet_free(fcal_packet_t *fcalpkt)
40633db86aabSstevel {
40643db86aabSstevel 	kmem_free((void *)fcalpkt, sizeof (fcal_packet_t));
40653db86aabSstevel }
40663db86aabSstevel 
40673db86aabSstevel static void
40683db86aabSstevel socal_lilp_map_done(fcal_packet_t *fcalpkt)
40693db86aabSstevel {
40703db86aabSstevel 	uint32_t	port;
40713db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
40723db86aabSstevel 
40733db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
40743db86aabSstevel 		port = 1;
40753db86aabSstevel 	else
40763db86aabSstevel 		port = 0;
40773db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
40783db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_LILP_PENDING;
40793db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
40803db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
40813db86aabSstevel }
40823db86aabSstevel 
40833db86aabSstevel static void
40843db86aabSstevel socal_force_lip_done(fcal_packet_t *fcalpkt)
40853db86aabSstevel {
40863db86aabSstevel 	uint32_t	port;
40873db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
40883db86aabSstevel 
40893db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
40903db86aabSstevel 		port = 1;
40913db86aabSstevel 	else
40923db86aabSstevel 		port = 0;
40933db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
40943db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_LIP_PENDING;
40953db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
40963db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
40973db86aabSstevel }
40983db86aabSstevel 
40993db86aabSstevel static void
41003db86aabSstevel socal_adisc_done(fcal_packet_t *fcalpkt)
41013db86aabSstevel {
41023db86aabSstevel 	uint32_t	port;
41033db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41043db86aabSstevel 
41053db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41063db86aabSstevel 		port = 1;
41073db86aabSstevel 	else
41083db86aabSstevel 		port = 0;
41093db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41103db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_ADISC_PENDING;
41113db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41123db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41133db86aabSstevel }
41143db86aabSstevel 
41153db86aabSstevel static void
41163db86aabSstevel socal_lbf_done(fcal_packet_t *fcalpkt)
41173db86aabSstevel {
41183db86aabSstevel 	uint32_t	port;
41193db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41203db86aabSstevel 
41213db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41223db86aabSstevel 		port = 1;
41233db86aabSstevel 	else
41243db86aabSstevel 		port = 0;
41253db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41263db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_LBF_PENDING;
41273db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41283db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41293db86aabSstevel }
41303db86aabSstevel 
41313db86aabSstevel static void
41323db86aabSstevel socal_rls_done(fcal_packet_t *fcalpkt)
41333db86aabSstevel {
41343db86aabSstevel 	uint32_t	port;
41353db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41363db86aabSstevel 
41373db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41383db86aabSstevel 		port = 1;
41393db86aabSstevel 	else
41403db86aabSstevel 		port = 0;
41413db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41423db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_RLS_PENDING;
41433db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41443db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41453db86aabSstevel }
41463db86aabSstevel 
41473db86aabSstevel static void
41483db86aabSstevel socal_force_offline_done(fcal_packet_t *fcalpkt)
41493db86aabSstevel {
41503db86aabSstevel 	uint32_t	port;
41513db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41523db86aabSstevel 
41533db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41543db86aabSstevel 		port = 1;
41553db86aabSstevel 	else
41563db86aabSstevel 		port = 0;
41573db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41583db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_OFFLINE_PENDING;
41593db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41603db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41613db86aabSstevel }
41623db86aabSstevel 
41633db86aabSstevel static void
41643db86aabSstevel socal_abort_done(fcal_packet_t *fcalpkt)
41653db86aabSstevel {
41663db86aabSstevel 	uint32_t	port;
41673db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41683db86aabSstevel 	soc_header_t	*shp =
41693db86aabSstevel 	    (soc_header_t *)&fcalpkt->fcal_socal_request.sr_soc_hdr;
41703db86aabSstevel 	fcal_packet_t	*target = (fcal_packet_t *)
41713db86aabSstevel 	    SOCAL_ID_LOOKUP(shp->sh_request_token);
41723db86aabSstevel 
41733db86aabSstevel 	mutex_enter(&socalp->abort_mtx);
41743db86aabSstevel 	ASSERT(target->fcal_pkt_flags & FCFLAG_ABORTING);
41753db86aabSstevel 	if (!(target->fcal_pkt_flags & FCFLAG_COMPLETE)) {
41763db86aabSstevel 		SOCAL_ID_FREE(shp->sh_request_token);
41773db86aabSstevel 	}
41783db86aabSstevel 	mutex_exit(&socalp->abort_mtx);
41793db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41803db86aabSstevel 		port = 1;
41813db86aabSstevel 	else
41823db86aabSstevel 		port = 0;
41833db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41843db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_ABORT_PENDING;
41853db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41863db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41873db86aabSstevel }
41883db86aabSstevel 
41893db86aabSstevel static void
41903db86aabSstevel socal_bypass_dev_done(fcal_packet_t *fcalpkt)
41913db86aabSstevel {
41923db86aabSstevel 	uint32_t	port;
41933db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41943db86aabSstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41953db86aabSstevel 		port = 1;
41963db86aabSstevel 	else
41973db86aabSstevel 		port = 0;
41983db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41993db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_BYPASS_PENDING;
42003db86aabSstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
42013db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
42023db86aabSstevel }
42033db86aabSstevel 
42043db86aabSstevel /*ARGSUSED*/
42053db86aabSstevel static unsigned int
42063db86aabSstevel socal_dummy_intr(caddr_t arg)
42073db86aabSstevel {
42083db86aabSstevel 	return (DDI_INTR_UNCLAIMED);
42093db86aabSstevel }
42103db86aabSstevel 
42113db86aabSstevel static int
42123db86aabSstevel socal_diag_request(socal_state_t *socalp, uint32_t port, uint_t *diagcode,
42133db86aabSstevel     uint32_t cmd)
42143db86aabSstevel {
42153db86aabSstevel 	fcal_packet_t		*fcalpkt;
42163db86aabSstevel 	soc_diag_request_t	*sdr;
42173db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
42183db86aabSstevel 	struct fcal_lilp_map	map;
42193db86aabSstevel 
42203db86aabSstevel 	/* Grabbing the state mutex is totally unnecessary.... */
42213db86aabSstevel 	if (!(port_statep->sp_status & PORT_DISABLED)) {
42223db86aabSstevel 		if (socal_getmap(socalp, port, (caddr_t)&map, 0, FKIOCTL)
42233db86aabSstevel 		    != -1) {
42243db86aabSstevel 			if (map.lilp_length != 1 && ((port_statep->sp_status &
42253db86aabSstevel 			    PORT_ONLINE_LOOP) && cmd != SOC_DIAG_REM_LOOP))
42263db86aabSstevel 				return (FCAL_TRANSPORT_UNAVAIL);
42273db86aabSstevel 		}
42283db86aabSstevel 	}
42293db86aabSstevel 	if ((fcalpkt = socal_packet_alloc(socalp, FCAL_SLEEP))
42303db86aabSstevel 	    == (fcal_packet_t *)NULL)
42313db86aabSstevel 		return (FCAL_ALLOC_FAILED);
42323db86aabSstevel 	sdr = (soc_diag_request_t *)&fcalpkt->fcal_socal_request;
42333db86aabSstevel 	if (port)
42343db86aabSstevel 		sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
42353db86aabSstevel 	sdr->sdr_diag_cmd = cmd;
42363db86aabSstevel 	sdr->sdr_cqhdr.cq_hdr_count = 1;
42373db86aabSstevel 	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_DIAGNOSTIC;
42383db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
42393db86aabSstevel 	return (socal_doit(fcalpkt, port_statep, 1, NULL,
42403db86aabSstevel 	    SOCAL_DIAG_TIMEOUT, 0, diagcode));
42413db86aabSstevel }
42423db86aabSstevel 
42433db86aabSstevel static uint_t
42443db86aabSstevel socal_force_offline(void *ssp, uint_t port, uint_t polled)
42453db86aabSstevel {
42463db86aabSstevel 	fcal_packet_t		*fcalpkt;
42473db86aabSstevel 	soc_cmdonly_request_t	*scr;
42483db86aabSstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
42493db86aabSstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
42503db86aabSstevel 
42513db86aabSstevel 	if ((fcalpkt =
42523db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
42533db86aabSstevel 	    == (fcal_packet_t *)NULL)
42543db86aabSstevel 		return (FCAL_ALLOC_FAILED);
42553db86aabSstevel 
42563db86aabSstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
42573db86aabSstevel 	if (port)
42583db86aabSstevel 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
42593db86aabSstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
42603db86aabSstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_OFFLINE;
42613db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
42623db86aabSstevel 	return (socal_doit(fcalpkt, port_statep, 0, socal_force_offline_done,
42633db86aabSstevel 	    SOCAL_OFFLINE_TIMEOUT, PORT_OFFLINE_PENDING, NULL));
42643db86aabSstevel }
42653db86aabSstevel 
42663db86aabSstevel static int
42673db86aabSstevel socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t dest,
42683db86aabSstevel 	la_els_adisc_t *payload, uint32_t polled)
42693db86aabSstevel {
42703db86aabSstevel 	int			retval;
42713db86aabSstevel 	la_els_adisc_t		*buf;
42723db86aabSstevel 	fcal_packet_t		*fcalpkt;
42733db86aabSstevel 	socal_port_t		*port_statep;
42743db86aabSstevel 	socal_priv_cmd_t 	*privp;
42753db86aabSstevel 
42763db86aabSstevel 	port_statep = &socalp->port_state[port];
42773db86aabSstevel 
42783db86aabSstevel 	if ((fcalpkt =
42793db86aabSstevel 	    socal_els_alloc(socalp, port, dest, sizeof (la_els_adisc_t),
42803db86aabSstevel 	    sizeof (la_els_adisc_t), (caddr_t *)&privp, polled))
42813db86aabSstevel 	    == (fcal_packet_t *)NULL)
42823db86aabSstevel 		return (FCAL_ALLOC_FAILED);
42833db86aabSstevel 
42843db86aabSstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
42853db86aabSstevel 	buf = (la_els_adisc_t *)privp->cmd;
42863db86aabSstevel 	buf->ls_code = LA_ELS_ADISC;
42873db86aabSstevel 	buf->mbz[0] = 0;
42883db86aabSstevel 	buf->mbz[1] = 0;
42893db86aabSstevel 	buf->mbz[2] = 0;
42903db86aabSstevel 	buf->hard_address = 0;
42913db86aabSstevel 	bcopy((caddr_t)&port_statep->sp_p_wwn,
42923db86aabSstevel 	    (caddr_t)&buf->port_wwn, sizeof (buf->port_wwn));
42933db86aabSstevel 	bcopy((caddr_t)&socalp->socal_n_wwn,
42943db86aabSstevel 	    (caddr_t)&buf->node_wwn, sizeof (buf->node_wwn));
42953db86aabSstevel 	buf->nport_id = fcalpkt->fcal_socal_request.sr_fc_frame_hdr.s_id;
42963db86aabSstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
42973db86aabSstevel 
42983db86aabSstevel 	retval = socal_doit(fcalpkt, port_statep, 0, socal_adisc_done,
42993db86aabSstevel 	    SOCAL_ADISC_TIMEOUT, PORT_ADISC_PENDING, NULL);
43003db86aabSstevel 	if (retval == FCAL_SUCCESS) {
43013db86aabSstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
43023db86aabSstevel 		    DDI_DMA_SYNC_FORKERNEL);
43033db86aabSstevel 		bcopy(privp->rsp, (caddr_t)payload, sizeof (la_els_adisc_t));
43043db86aabSstevel 	}
43053db86aabSstevel 	privp->fapktp = NULL;
43063db86aabSstevel 	socal_els_free(privp);
43073db86aabSstevel 	return (retval);
43083db86aabSstevel }
43093db86aabSstevel 
43103db86aabSstevel static int
43113db86aabSstevel socal_issue_lbf(socal_state_t *socalp, uint32_t port,
43123db86aabSstevel     uchar_t *payload, size_t length, uint32_t polled)
43133db86aabSstevel {
43143db86aabSstevel 	int			retval;
43153db86aabSstevel 	fcal_packet_t		*fcalpkt;
43163db86aabSstevel 	socal_port_t		*port_statep;
43173db86aabSstevel 	socal_priv_cmd_t 	*privp;
43183db86aabSstevel 
43193db86aabSstevel 	port_statep = &socalp->port_state[port];
43203db86aabSstevel 
43213db86aabSstevel 	if ((fcalpkt = socal_lbf_alloc(socalp, port, length, length,
43223db86aabSstevel 	    (caddr_t *)&privp, polled)) == (fcal_packet_t *)NULL)
43233db86aabSstevel 		return (FCAL_ALLOC_FAILED);
43243db86aabSstevel 
43253db86aabSstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
43263db86aabSstevel 	bcopy((caddr_t)payload, privp->cmd, length);
43273db86aabSstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
43283db86aabSstevel 
43293db86aabSstevel 	retval = socal_doit(fcalpkt, port_statep, polled, socal_lbf_done,
43303db86aabSstevel 	    SOCAL_LBF_TIMEOUT, PORT_LBF_PENDING, NULL);
43313db86aabSstevel 
43323db86aabSstevel 	if (retval == FCAL_SUCCESS) {
43333db86aabSstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
43343db86aabSstevel 		    DDI_DMA_SYNC_FORKERNEL);
43353db86aabSstevel 		bcopy(privp->rsp, (caddr_t)payload, length);
43363db86aabSstevel 	}
43373db86aabSstevel 	privp->fapktp = NULL;
43383db86aabSstevel 	socal_lbf_free(privp);
43393db86aabSstevel 	return (retval);
43403db86aabSstevel }
43413db86aabSstevel 
43423db86aabSstevel static int
43433db86aabSstevel socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t dest,
43443db86aabSstevel 	la_els_rls_reply_t *payload, uint32_t polled)
43453db86aabSstevel {
43463db86aabSstevel 	int	retval;
43473db86aabSstevel 	la_els_rls_t		*buf;
43483db86aabSstevel 	fcal_packet_t		*fcalpkt;
43493db86aabSstevel 	socal_port_t		*port_statep;
43503db86aabSstevel 	socal_priv_cmd_t 	*privp;
43513db86aabSstevel 	uint32_t		arg;
43523db86aabSstevel 
43533db86aabSstevel 	port_statep = &socalp->port_state[port];
43543db86aabSstevel 
43553db86aabSstevel 	if (dest == socal_getmap(socalp, port, NULL, 0, 0)) {
43563db86aabSstevel 		/* load up the the struct with the local lesb */
43573db86aabSstevel 		struct la_els_rjt *rsp = (struct la_els_rjt *)payload;
43583db86aabSstevel 
43593db86aabSstevel 		rsp->ls_code = LA_ELS_RJT;
43603db86aabSstevel 		rsp->mbz[0] = 0;
43613db86aabSstevel 		rsp->mbz[1] = 0;
43623db86aabSstevel 		rsp->mbz[2] = 0;
43633db86aabSstevel 		rsp->reason_code = RJT_UNSUPPORTED;
43643db86aabSstevel 		rsp->reserved = 0;
43653db86aabSstevel 		rsp->explanation = 0;
43663db86aabSstevel 		rsp->vendor = 0;
43673db86aabSstevel 		return (FCAL_SUCCESS);
43683db86aabSstevel 	}
43693db86aabSstevel 
43703db86aabSstevel 	if ((fcalpkt =
43713db86aabSstevel 	    socal_els_alloc(socalp, port, dest, sizeof (la_els_rls_t),
43723db86aabSstevel 	    sizeof (la_els_rls_reply_t), (caddr_t *)&privp, polled))
43733db86aabSstevel 	    == (fcal_packet_t *)NULL)
43743db86aabSstevel 		return (FCAL_ALLOC_FAILED);
43753db86aabSstevel 
43763db86aabSstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
43773db86aabSstevel 
43783db86aabSstevel 	if (payload->link_failure & 0xff000000)
43793db86aabSstevel 		arg = payload->link_failure;
43803db86aabSstevel 	else
43813db86aabSstevel 		arg = dest;
43823db86aabSstevel 
43833db86aabSstevel 	buf = (la_els_rls_t *)privp->cmd;
43843db86aabSstevel 	buf->ls_code = LA_ELS_RLS;
43853db86aabSstevel 	buf->mbz[0] = 0;
43863db86aabSstevel 	buf->mbz[1] = 0;
43873db86aabSstevel 	buf->mbz[2] = 0;
43883db86aabSstevel 	buf->reserved = 0;
43893db86aabSstevel 	buf->nport_id[0] = (arg >> 16) & 0xff;
43903db86aabSstevel 	buf->nport_id[1] = (arg >> 8) & 0xff;
43913db86aabSstevel 	buf->nport_id[2] = arg & 0xff;
43923db86aabSstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
43933db86aabSstevel 
43943db86aabSstevel 	retval = socal_doit(fcalpkt, port_statep, 0, socal_rls_done,
43953db86aabSstevel 	    SOCAL_RLS_TIMEOUT, PORT_RLS_PENDING, NULL);
43963db86aabSstevel 	if (retval == FCAL_SUCCESS) {
43973db86aabSstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
43983db86aabSstevel 		    DDI_DMA_SYNC_FORKERNEL);
43993db86aabSstevel 		bcopy(privp->rsp, (caddr_t)payload,
44003db86aabSstevel 		    sizeof (la_els_rls_reply_t));
44013db86aabSstevel 	}
44023db86aabSstevel 	privp->fapktp = NULL;
44033db86aabSstevel 	socal_els_free(privp);
44043db86aabSstevel 	return (retval);
44053db86aabSstevel }
44063db86aabSstevel 
44073db86aabSstevel fcal_packet_t *
44083db86aabSstevel socal_els_alloc(socal_state_t *socalp, uint32_t port, uint32_t dest,
44093db86aabSstevel 	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp, uint32_t polled)
44103db86aabSstevel {
44113db86aabSstevel 	struct fcal_packet	*fcalpkt;
44123db86aabSstevel 	ddi_dma_cookie_t	ccookie;
44133db86aabSstevel 	ddi_dma_cookie_t	rcookie;
44143db86aabSstevel 	socal_priv_cmd_t	*privp;
44153db86aabSstevel 	ddi_dma_handle_t	chandle = NULL;
44163db86aabSstevel 	ddi_dma_handle_t	rhandle = NULL;
44173db86aabSstevel 	ddi_acc_handle_t	cacchandle;
44183db86aabSstevel 	ddi_acc_handle_t	racchandle;
44193db86aabSstevel 	soc_request_t		*srp;
44203db86aabSstevel 	fc_frame_header_t	*fhp;
44213db86aabSstevel 	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
44223db86aabSstevel 	size_t			real_len;
44233db86aabSstevel 	caddr_t			cmd;
44243db86aabSstevel 	caddr_t			rsp;
44253db86aabSstevel 	uint32_t		ouralpa;
44263db86aabSstevel 
44273db86aabSstevel 	if ((fcalpkt =
44283db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
44293db86aabSstevel 	    == (fcal_packet_t *)NULL)
44303db86aabSstevel 		return (NULL);
44313db86aabSstevel 
44323db86aabSstevel 	if ((privp =
44333db86aabSstevel 	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
44343db86aabSstevel 	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
44353db86aabSstevel 		goto fail;
44363db86aabSstevel 	}
44373db86aabSstevel 
44383db86aabSstevel 	rprivp = (caddr_t *)&privp;
44393db86aabSstevel 
44403db86aabSstevel 	fcalpkt->fcal_pkt_private = (caddr_t)privp;
44413db86aabSstevel 	privp->fapktp = (void *)fcalpkt;
44423db86aabSstevel 
44433db86aabSstevel 	if ((ouralpa = socal_getmap(socalp, port, NULL, 0, 0)) == -1)
44443db86aabSstevel 		goto fail;
44453db86aabSstevel 
44463db86aabSstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
44473db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
44483db86aabSstevel 		goto fail;
44493db86aabSstevel 	privp->cmd_handle = chandle;
44503db86aabSstevel 
44513db86aabSstevel 	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
44523db86aabSstevel 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
44533db86aabSstevel 	    (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
44543db86aabSstevel 		goto fail;
44553db86aabSstevel 	privp->cmd = cmd;
44563db86aabSstevel 	privp->cmd_acchandle = cacchandle;
44573db86aabSstevel 
44583db86aabSstevel 	if (real_len < cmd_size)
44593db86aabSstevel 		goto fail;
44603db86aabSstevel 
44613db86aabSstevel 	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
44623db86aabSstevel 	    (caddr_t)cmd, cmd_size,
44633db86aabSstevel 	    DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
44643db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
44653db86aabSstevel 	    != DDI_DMA_MAPPED)
44663db86aabSstevel 		goto fail;
44673db86aabSstevel 	cmd_bound = 1;
44683db86aabSstevel 	if (ccount != 1)
44693db86aabSstevel 		goto fail;
44703db86aabSstevel 
44713db86aabSstevel 	if (rsp_size) {
44723db86aabSstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
44733db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
44743db86aabSstevel 		goto fail;
44753db86aabSstevel 
44763db86aabSstevel 		privp->rsp_handle = rhandle;
44773db86aabSstevel 		if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
44783db86aabSstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
44793db86aabSstevel 		    &rsp, &real_len, &racchandle) != DDI_SUCCESS)
44803db86aabSstevel 			goto fail;
44813db86aabSstevel 		privp->rsp = rsp;
44823db86aabSstevel 		privp->rsp_acchandle = racchandle;
44833db86aabSstevel 		if (real_len < rsp_size)
44843db86aabSstevel 		goto fail;
44853db86aabSstevel 
44863db86aabSstevel 		if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
44873db86aabSstevel 		    rsp, rsp_size,
44883db86aabSstevel 		    DDI_DMA_READ | DDI_DMA_CONSISTENT,
44893db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
44903db86aabSstevel 		    != DDI_DMA_MAPPED)
44913db86aabSstevel 		goto fail;
44923db86aabSstevel 
44933db86aabSstevel 		rsp_bound = 1;
44943db86aabSstevel 		if (ccount != 1)
44953db86aabSstevel 		goto fail;
44963db86aabSstevel 	}
44973db86aabSstevel 
44983db86aabSstevel 	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
44993db86aabSstevel 	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
45003db86aabSstevel 	if (port)
45013db86aabSstevel 		srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
45023db86aabSstevel 	srp->sr_soc_hdr.sh_class = 3;
45033db86aabSstevel 	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
45043db86aabSstevel 	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
45053db86aabSstevel 	srp->sr_dataseg[0].fc_count = cmd_size;
45063db86aabSstevel 	if (rsp_size == 0) {
45073db86aabSstevel 		srp->sr_soc_hdr.sh_seg_cnt = 1;
45083db86aabSstevel 	} else {
45093db86aabSstevel 		srp->sr_soc_hdr.sh_seg_cnt = 2;
45103db86aabSstevel 		srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
45113db86aabSstevel 		srp->sr_dataseg[1].fc_count = rsp_size;
45123db86aabSstevel 	}
45133db86aabSstevel 	srp->sr_cqhdr.cq_hdr_count = 1;
45143db86aabSstevel 	/* this will potentially be overwritten by the calling function */
45153db86aabSstevel 	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
45163db86aabSstevel 
45173db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
45183db86aabSstevel 
45193db86aabSstevel 	/* Fill in the Fabric Channel Header */
45203db86aabSstevel 	fhp = &srp->sr_fc_frame_hdr;
45213db86aabSstevel 	fhp->r_ctl = R_CTL_ELS_REQ;
45223db86aabSstevel 	fhp->d_id = dest;
45233db86aabSstevel 	fhp->s_id = ouralpa;
45243db86aabSstevel 	fhp->type = TYPE_EXTENDED_LS;
45253db86aabSstevel 	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
45263db86aabSstevel 	fhp->seq_id = 0;
45273db86aabSstevel 	fhp->df_ctl  = 0;
45283db86aabSstevel 	fhp->seq_cnt = 0;
45293db86aabSstevel 	fhp->ox_id = 0xffff;
45303db86aabSstevel 	fhp->rx_id = 0xffff;
45313db86aabSstevel 	fhp->ro = 0;
45323db86aabSstevel 	return (fcalpkt);
45333db86aabSstevel fail:
45343db86aabSstevel 	socal_packet_free(fcalpkt);
45353db86aabSstevel 	if (privp) {
45363db86aabSstevel 		if (privp->cmd_handle) {
45373db86aabSstevel 			if (cmd_bound)
45383db86aabSstevel 				(void) ddi_dma_unbind_handle(privp->cmd_handle);
45393db86aabSstevel 			ddi_dma_free_handle(&privp->cmd_handle);
45403db86aabSstevel 		}
45413db86aabSstevel 		if (privp->cmd)
45423db86aabSstevel 			ddi_dma_mem_free(&privp->cmd_acchandle);
45433db86aabSstevel 		if (privp->rsp_handle) {
45443db86aabSstevel 			if (rsp_bound)
45453db86aabSstevel 				(void) ddi_dma_unbind_handle(privp->rsp_handle);
45463db86aabSstevel 			ddi_dma_free_handle(&privp->rsp_handle);
45473db86aabSstevel 		}
45483db86aabSstevel 		if (privp->rsp)
45493db86aabSstevel 			ddi_dma_mem_free(&privp->rsp_acchandle);
45503db86aabSstevel 
45513db86aabSstevel 		kmem_free(privp, sizeof (*privp));
45523db86aabSstevel 	}
45533db86aabSstevel 	return (NULL);
45543db86aabSstevel }
45553db86aabSstevel 
45563db86aabSstevel fcal_packet_t *
45573db86aabSstevel socal_lbf_alloc(socal_state_t *socalp, uint32_t port,
45583db86aabSstevel 	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp,
45593db86aabSstevel 	uint32_t polled)
45603db86aabSstevel {
45613db86aabSstevel 	struct fcal_packet	*fcalpkt;
45623db86aabSstevel 	ddi_dma_cookie_t	ccookie;
45633db86aabSstevel 	ddi_dma_cookie_t	rcookie;
45643db86aabSstevel 	socal_priv_cmd_t	*privp;
45653db86aabSstevel 	ddi_dma_handle_t	chandle = NULL;
45663db86aabSstevel 	ddi_dma_handle_t	rhandle = NULL;
45673db86aabSstevel 	ddi_acc_handle_t	cacchandle;
45683db86aabSstevel 	ddi_acc_handle_t	racchandle;
45693db86aabSstevel 	soc_request_t		*srp;
45703db86aabSstevel 	fc_frame_header_t	*fhp;
45713db86aabSstevel 	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
45723db86aabSstevel 	size_t			real_len;
45733db86aabSstevel 	caddr_t			cmd;
45743db86aabSstevel 	caddr_t			rsp;
45753db86aabSstevel 
45763db86aabSstevel 	if ((fcalpkt =
45773db86aabSstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
45783db86aabSstevel 	    == (fcal_packet_t *)NULL)
45793db86aabSstevel 		return (NULL);
45803db86aabSstevel 
45813db86aabSstevel 	if ((privp =
45823db86aabSstevel 	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
45833db86aabSstevel 	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
45843db86aabSstevel 		goto fail;
45853db86aabSstevel 	}
45863db86aabSstevel 
45873db86aabSstevel 	rprivp = (caddr_t *)&privp;
45883db86aabSstevel 
45893db86aabSstevel 	fcalpkt->fcal_pkt_private = (caddr_t)privp;
45903db86aabSstevel 	privp->fapktp = (void *)fcalpkt;
45913db86aabSstevel 
45923db86aabSstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
45933db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
45943db86aabSstevel 		goto fail;
45953db86aabSstevel 	privp->cmd_handle = chandle;
45963db86aabSstevel 
45973db86aabSstevel 	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
45983db86aabSstevel 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
45993db86aabSstevel 	    (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
46003db86aabSstevel 		goto fail;
46013db86aabSstevel 	privp->cmd = cmd;
46023db86aabSstevel 	privp->cmd_acchandle = cacchandle;
46033db86aabSstevel 
46043db86aabSstevel 	if (real_len < cmd_size)
46053db86aabSstevel 		goto fail;
46063db86aabSstevel 
46073db86aabSstevel 	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
46083db86aabSstevel 	    (caddr_t)cmd, cmd_size,
46093db86aabSstevel 	    DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
46103db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
46113db86aabSstevel 	    != DDI_DMA_MAPPED)
46123db86aabSstevel 		goto fail;
46133db86aabSstevel 	cmd_bound = 1;
46143db86aabSstevel 	if (ccount != 1)
46153db86aabSstevel 		goto fail;
46163db86aabSstevel 
46173db86aabSstevel 	if (rsp_size) {
46183db86aabSstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
46193db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
46203db86aabSstevel 		goto fail;
46213db86aabSstevel 
46223db86aabSstevel 		privp->rsp_handle = rhandle;
46233db86aabSstevel 		if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
46243db86aabSstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
46253db86aabSstevel 		    &rsp, &real_len, &racchandle) != DDI_SUCCESS)
46263db86aabSstevel 			goto fail;
46273db86aabSstevel 
46283db86aabSstevel 		privp->rsp = rsp;
46293db86aabSstevel 		privp->rsp_acchandle = racchandle;
46303db86aabSstevel 		if (real_len < rsp_size)
46313db86aabSstevel 		goto fail;
46323db86aabSstevel 
46333db86aabSstevel 		if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
46343db86aabSstevel 		    rsp, rsp_size,
46353db86aabSstevel 		    DDI_DMA_READ | DDI_DMA_CONSISTENT,
46363db86aabSstevel 		    DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
46373db86aabSstevel 		    != DDI_DMA_MAPPED)
46383db86aabSstevel 			goto fail;
46393db86aabSstevel 
46403db86aabSstevel 		rsp_bound = 1;
46413db86aabSstevel 		if (ccount != 1)
46423db86aabSstevel 		goto fail;
46433db86aabSstevel 	}
46443db86aabSstevel 
46453db86aabSstevel 	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
46463db86aabSstevel 	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
46473db86aabSstevel 	if (port)
46483db86aabSstevel 		srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
46493db86aabSstevel 	srp->sr_soc_hdr.sh_class = 3;
46503db86aabSstevel 	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
46513db86aabSstevel 	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
46523db86aabSstevel 	srp->sr_dataseg[0].fc_count = cmd_size;
46533db86aabSstevel 	if (rsp_size == 0) {
46543db86aabSstevel 		srp->sr_soc_hdr.sh_seg_cnt = 1;
46553db86aabSstevel 	} else {
46563db86aabSstevel 		srp->sr_soc_hdr.sh_seg_cnt = 2;
46573db86aabSstevel 		srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
46583db86aabSstevel 		srp->sr_dataseg[1].fc_count = rsp_size;
46593db86aabSstevel 	}
46603db86aabSstevel 	srp->sr_cqhdr.cq_hdr_count = 1;
46613db86aabSstevel 	/* this will potentially be overwritten by the calling function */
46623db86aabSstevel 	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
46633db86aabSstevel 
46643db86aabSstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
46653db86aabSstevel 
46663db86aabSstevel 	/* Fill in the Fabric Channel Header */
46673db86aabSstevel 	fhp = &srp->sr_fc_frame_hdr;
46683db86aabSstevel 	fhp->r_ctl = R_CTL_SOLICITED_DATA;
46693db86aabSstevel 	fhp->d_id = socalp->port_state[port].sp_src_id;
46703db86aabSstevel 	fhp->s_id = socalp->port_state[port].sp_src_id;
46713db86aabSstevel 	fhp->type = TYPE_SCSI_FCP;
46723db86aabSstevel 	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ;
46733db86aabSstevel 	fhp->seq_id = 0;
46743db86aabSstevel 	fhp->df_ctl  = 0;
46753db86aabSstevel 	fhp->seq_cnt = 0;
46763db86aabSstevel 	fhp->ox_id = 0xffff;
46773db86aabSstevel 	fhp->rx_id = 0xffff;
46783db86aabSstevel 	fhp->ro = 0;
46793db86aabSstevel 	return (fcalpkt);
46803db86aabSstevel fail:
46813db86aabSstevel 	socal_packet_free(fcalpkt);
46823db86aabSstevel 	if (privp) {
46833db86aabSstevel 		if (privp->cmd_handle) {
46843db86aabSstevel 			if (cmd_bound)
46853db86aabSstevel 				(void) ddi_dma_unbind_handle(privp->cmd_handle);
46863db86aabSstevel 			ddi_dma_free_handle(&privp->cmd_handle);
46873db86aabSstevel 		}
46883db86aabSstevel 		if (privp->cmd)
46893db86aabSstevel 			ddi_dma_mem_free(&privp->cmd_acchandle);
46903db86aabSstevel 		if (privp->rsp_handle) {
46913db86aabSstevel 			if (rsp_bound)
46923db86aabSstevel 				(void) ddi_dma_unbind_handle(privp->rsp_handle);
46933db86aabSstevel 			ddi_dma_free_handle(&privp->rsp_handle);
46943db86aabSstevel 		}
46953db86aabSstevel 		if (privp->rsp)
46963db86aabSstevel 			ddi_dma_mem_free(&privp->rsp_acchandle);
46973db86aabSstevel 
46983db86aabSstevel 		kmem_free(privp, sizeof (*privp));
46993db86aabSstevel 	}
47003db86aabSstevel 	return (NULL);
47013db86aabSstevel }
47023db86aabSstevel 
47033db86aabSstevel void
47043db86aabSstevel socal_els_free(socal_priv_cmd_t *privp)
47053db86aabSstevel {
47063db86aabSstevel 	fcal_packet_t		*fcalpkt;
47073db86aabSstevel 
47083db86aabSstevel 	if (privp)
47093db86aabSstevel 		fcalpkt = (fcal_packet_t *)privp->fapktp;
47103db86aabSstevel 	else
47113db86aabSstevel 		return;
47123db86aabSstevel 
47133db86aabSstevel 	(void) ddi_dma_unbind_handle(privp->cmd_handle);
47143db86aabSstevel 	ddi_dma_free_handle(&privp->cmd_handle);
47153db86aabSstevel 	ddi_dma_mem_free(&privp->cmd_acchandle);
47163db86aabSstevel 
47173db86aabSstevel 	if (privp->rsp_handle) {
47183db86aabSstevel 		(void) ddi_dma_unbind_handle(privp->rsp_handle);
47193db86aabSstevel 		ddi_dma_free_handle(&privp->rsp_handle);
47203db86aabSstevel 	}
47213db86aabSstevel 	if (privp->rsp)
47223db86aabSstevel 		ddi_dma_mem_free(&privp->rsp_acchandle);
47233db86aabSstevel 
47243db86aabSstevel 	kmem_free(privp, sizeof (*privp));
47253db86aabSstevel 	if (fcalpkt != NULL)
47263db86aabSstevel 		socal_packet_free(fcalpkt);
47273db86aabSstevel }
47283db86aabSstevel 
47293db86aabSstevel void
47303db86aabSstevel socal_lbf_free(socal_priv_cmd_t *privp)
47313db86aabSstevel {
47323db86aabSstevel 	fcal_packet_t		*fcalpkt;
47333db86aabSstevel 
47343db86aabSstevel 	if (privp)
47353db86aabSstevel 		fcalpkt = (fcal_packet_t *)privp->fapktp;
47363db86aabSstevel 	else
47373db86aabSstevel 		return;
47383db86aabSstevel 
47393db86aabSstevel 	(void) ddi_dma_unbind_handle(privp->cmd_handle);
47403db86aabSstevel 	ddi_dma_free_handle(&privp->cmd_handle);
47413db86aabSstevel 	ddi_dma_mem_free(&privp->cmd_acchandle);
47423db86aabSstevel 
47433db86aabSstevel 	if (privp->rsp_handle) {
47443db86aabSstevel 		(void) ddi_dma_unbind_handle(privp->rsp_handle);
47453db86aabSstevel 		ddi_dma_free_handle(&privp->rsp_handle);
47463db86aabSstevel 	}
47473db86aabSstevel 
47483db86aabSstevel 	if (privp->rsp)
47493db86aabSstevel 		ddi_dma_mem_free(&privp->rsp_acchandle);
47503db86aabSstevel 
47513db86aabSstevel 	kmem_free(privp, sizeof (*privp));
47523db86aabSstevel 	if (fcalpkt != NULL)
47533db86aabSstevel 		socal_packet_free(fcalpkt);
47543db86aabSstevel }
47553db86aabSstevel 
47563db86aabSstevel static int
47573db86aabSstevel socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
47583db86aabSstevel 	uint32_t polled, int flags)
47593db86aabSstevel {
47603db86aabSstevel 	ddi_dma_cookie_t	dcookie;
47613db86aabSstevel 	ddi_dma_handle_t	dhandle = NULL;
47623db86aabSstevel 	ddi_acc_handle_t	acchandle;
47633db86aabSstevel 	size_t			real_len, i;
47643db86aabSstevel 	uint_t			ccount;
47653db86aabSstevel 	fcal_lilp_map_t		*buf = NULL;
47663db86aabSstevel 	int			retval, bound = 0;
47673db86aabSstevel 	socal_port_t		*port_statep;
47683db86aabSstevel 
47693db86aabSstevel 	port_statep = &socalp->port_state[port];
47703db86aabSstevel 
47713db86aabSstevel 	if (port_statep->sp_lilpmap_valid) {
47723db86aabSstevel 
47733db86aabSstevel 		buf = &port_statep->sp_lilpmap; /* give from cache */
47743db86aabSstevel 
47753db86aabSstevel 		if (arg) {
47763db86aabSstevel 		if (ddi_copyout(buf, (caddr_t)arg,
47773db86aabSstevel 		    sizeof (struct lilpmap), flags) == -1)
47783db86aabSstevel 			return (-1);
47793db86aabSstevel 		}
47803db86aabSstevel 
47813db86aabSstevel 		return (buf->lilp_myalpa);
47823db86aabSstevel 	}
47833db86aabSstevel 
47843db86aabSstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
47853db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &dhandle) != DDI_SUCCESS)
47863db86aabSstevel 		goto getmap_fail;
47873db86aabSstevel 
47883db86aabSstevel 	i = sizeof (struct fcal_lilp_map);
47893db86aabSstevel 
47903db86aabSstevel 	if (ddi_dma_mem_alloc(dhandle, i, &socal_acc_attr,
47913db86aabSstevel 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
47923db86aabSstevel 	    (caddr_t *)&buf, &real_len, &acchandle) != DDI_SUCCESS)
47933db86aabSstevel 		goto getmap_fail;
47943db86aabSstevel 
47953db86aabSstevel 	if (real_len < i)
47963db86aabSstevel 		goto getmap_fail;
47973db86aabSstevel 
47983db86aabSstevel 	if (ddi_dma_addr_bind_handle(dhandle, (struct as *)NULL,
47993db86aabSstevel 	    (caddr_t)buf, i, DDI_DMA_READ | DDI_DMA_CONSISTENT,
48003db86aabSstevel 	    DDI_DMA_DONTWAIT, NULL, &dcookie, &ccount) != DDI_DMA_MAPPED)
48013db86aabSstevel 		goto getmap_fail;
48023db86aabSstevel 
48033db86aabSstevel 	bound = 1;
48043db86aabSstevel 	if (ccount != 1)
48053db86aabSstevel 		goto getmap_fail;
48063db86aabSstevel 
48073db86aabSstevel 	retval = socal_lilp_map((void *)socalp, port,
48083db86aabSstevel 	    (uint32_t)dcookie.dmac_address, polled);
48093db86aabSstevel 
48103db86aabSstevel 	(void) ddi_dma_sync(dhandle, 0, 0, DDI_DMA_SYNC_FORKERNEL);
48113db86aabSstevel 
48123db86aabSstevel 	if (retval == FCAL_SUCCESS) {
48133db86aabSstevel 		bcopy(buf, &port_statep->sp_lilpmap, sizeof (fcal_lilp_map_t));
48143db86aabSstevel 
48153db86aabSstevel 		mutex_enter(&port_statep->sp_mtx);
48163db86aabSstevel 		port_statep->sp_src_id = buf->lilp_myalpa;
48173db86aabSstevel 		port_statep->sp_lilpmap_valid = 1; /* cached */
48183db86aabSstevel 		mutex_exit(&port_statep->sp_mtx);
48193db86aabSstevel 
48203db86aabSstevel 		if (arg) {
48213db86aabSstevel 		if (ddi_copyout(buf, (caddr_t)arg,
48223db86aabSstevel 		    sizeof (struct lilpmap), flags) == -1)
48233db86aabSstevel 			goto getmap_fail;
48243db86aabSstevel 		}
48253db86aabSstevel 
48263db86aabSstevel 		retval = buf->lilp_myalpa;
48273db86aabSstevel 	}
48283db86aabSstevel 	else
48293db86aabSstevel 		retval = -1;
48303db86aabSstevel 
48313db86aabSstevel 	(void) ddi_dma_unbind_handle(dhandle);
48323db86aabSstevel 	ddi_dma_mem_free(&acchandle);
48333db86aabSstevel 	ddi_dma_free_handle(&dhandle);
48343db86aabSstevel 	return (retval);
48353db86aabSstevel 
48363db86aabSstevel getmap_fail:
48373db86aabSstevel 	if (dhandle) {
48383db86aabSstevel 		if (bound)
48393db86aabSstevel 			(void) ddi_dma_unbind_handle(dhandle);
48403db86aabSstevel 		ddi_dma_free_handle(&dhandle);
48413db86aabSstevel 	}
48423db86aabSstevel 	if (buf)
48433db86aabSstevel 		ddi_dma_mem_free(&acchandle);
48443db86aabSstevel 	return (-1);
48453db86aabSstevel }
48463db86aabSstevel 
48473db86aabSstevel static	void
48483db86aabSstevel socal_wcopy(uint_t *h_src, uint_t *h_dest, int len)
48493db86aabSstevel {
48503db86aabSstevel 	int	i;
48513db86aabSstevel 	for (i = 0; i < len/4; i++) {
48523db86aabSstevel 		*h_dest++ = *h_src++;
48533db86aabSstevel 	}
48543db86aabSstevel }
48553db86aabSstevel 
48563db86aabSstevel static void
48573db86aabSstevel socal_flush_overflowq(socal_state_t *socalp, int port, int q_no)
48583db86aabSstevel {
48593db86aabSstevel 	socal_kcq_t	*kcq;
48603db86aabSstevel 	fcal_packet_t	*fpkt1, *fpkt2, *head = NULL, *tmp;
48613db86aabSstevel 
48623db86aabSstevel 	kcq = &socalp->request[q_no];
48633db86aabSstevel 	mutex_enter(&kcq->skc_mtx);
48643db86aabSstevel 	fpkt2 = kcq->skc_overflowh;
48653db86aabSstevel 	fpkt1 = NULL;
48663db86aabSstevel 	while (fpkt2 != NULL) {
48673db86aabSstevel 		if ((((soc_request_t *)&fpkt2->fcal_socal_request)
48683db86aabSstevel 		    ->sr_soc_hdr.sh_flags & SOC_PORT_B) == port) {
48693db86aabSstevel 			if (fpkt1 == NULL)
48703db86aabSstevel 				kcq->skc_overflowh = fpkt2->fcal_pkt_next;
48713db86aabSstevel 			else {
48723db86aabSstevel 				fpkt1->fcal_pkt_next = fpkt2->fcal_pkt_next;
48733db86aabSstevel 				if (kcq->skc_overflowt == fpkt2)
48743db86aabSstevel 					kcq->skc_overflowt = fpkt1;
48753db86aabSstevel 			}
48763db86aabSstevel 			tmp = fpkt2->fcal_pkt_next;
48773db86aabSstevel 			fpkt2->fcal_pkt_next = head;
48783db86aabSstevel 			head = fpkt2;
48793db86aabSstevel 			fpkt2 = tmp;
48803db86aabSstevel 			SOCAL_ID_FREE(head->fcal_socal_request.
48813db86aabSstevel 			    sr_soc_hdr.sh_request_token);
48823db86aabSstevel 		} else {
48833db86aabSstevel 			fpkt1 = fpkt2;
48843db86aabSstevel 			fpkt2 = fpkt2->fcal_pkt_next;
48853db86aabSstevel 		}
48863db86aabSstevel 	}
48873db86aabSstevel 	mutex_exit(&kcq->skc_mtx);
48883db86aabSstevel 	fpkt2 = head;
48893db86aabSstevel 	while (fpkt2 != NULL) {
48903db86aabSstevel 		fpkt2->fcal_pkt_status = FCAL_STATUS_ERR_OFFLINE;
48913db86aabSstevel 		fpkt2->fcal_cmd_state |= FCAL_CMD_COMPLETE;
48923db86aabSstevel 		fpkt2->fcal_pkt_flags |= FCFLAG_COMPLETE;
48933db86aabSstevel 		tmp = fpkt2->fcal_pkt_next;
48943db86aabSstevel 		if (fpkt2->fcal_pkt_comp != NULL)
48953db86aabSstevel 			(*fpkt2->fcal_pkt_comp)(fpkt2);
48963db86aabSstevel 		fpkt2 = tmp;
48973db86aabSstevel 	}
48983db86aabSstevel }
48993db86aabSstevel 
49003db86aabSstevel static void
49013db86aabSstevel socal_deferred_intr(void *arg)
49023db86aabSstevel {
49033db86aabSstevel 	socal_kcq_t	*kcq = (socal_kcq_t *)arg;
49043db86aabSstevel 	socal_state_t	*socalp = kcq->skc_socalp;
49053db86aabSstevel 
49063db86aabSstevel 	ASSERT((socalp != NULL));
49073db86aabSstevel 
49083db86aabSstevel 	mutex_enter(&kcq->skc_mtx);
49093db86aabSstevel 
49103db86aabSstevel 	if ((kcq->skc_out != kcq->skc_saved_out) ||
49113db86aabSstevel 	    (kcq->skc_seqno != kcq->skc_saved_seqno)) {
49123db86aabSstevel 		kcq->deferred_intr_timeoutid = 0;
49133db86aabSstevel 		mutex_exit(&kcq->skc_mtx);
49143db86aabSstevel 		return;
49153db86aabSstevel 	}
49163db86aabSstevel 
49173db86aabSstevel 	if (socalp->socal_on_intr) {
49183db86aabSstevel 		mutex_exit(&kcq->skc_mtx);
49193db86aabSstevel 		kcq->deferred_intr_timeoutid = timeout(socal_deferred_intr,
49203db86aabSstevel 		    (caddr_t)kcq, drv_usectohz(10000));
49213db86aabSstevel 		return;
49223db86aabSstevel 	}
49233db86aabSstevel 
49243db86aabSstevel 	kcq->deferred_intr_timeoutid = 0;
49253db86aabSstevel 	mutex_exit(&kcq->skc_mtx);
49263db86aabSstevel 	socal_intr_solicited(socalp, 0);
49273db86aabSstevel }
49283db86aabSstevel 
49293db86aabSstevel static void
49303db86aabSstevel socal_take_core(void *arg)
49313db86aabSstevel {
49323db86aabSstevel 	socal_state_t	*socalp = (socal_state_t *)arg;
49333db86aabSstevel 	int i, instance;
49343db86aabSstevel 
49353db86aabSstevel 	socal_disable(socalp);
49363db86aabSstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
49373db86aabSstevel 		mutex_enter(&socalp->request[i].skc_mtx);
49383db86aabSstevel 		mutex_enter(&socalp->response[i].skc_mtx);
49393db86aabSstevel 	}
49403db86aabSstevel 	for (i = 0; i < 4; i++) {
49413db86aabSstevel 		socalp->socal_rp->socal_cr.w &=
49423db86aabSstevel 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
49433db86aabSstevel 		socalp->socal_rp->socal_cr.w |= i<<24;
49443db86aabSstevel 		(void) bcopy((caddr_t)socalp->socal_xrp,
49453db86aabSstevel 		    (caddr_t)&socal_xrambuf[i*0x10000], 0x10000);
49463db86aabSstevel 	}
49473db86aabSstevel 	for (i = 3; i >= 0; i--) {
49483db86aabSstevel 		mutex_exit(&socalp->request[i].skc_mtx);
49493db86aabSstevel 		mutex_exit(&socalp->response[i].skc_mtx);
49503db86aabSstevel 	}
49513db86aabSstevel 	instance = ddi_get_instance(socalp->dip);
49523db86aabSstevel 	cmn_err(CE_PANIC,
49533db86aabSstevel 	    "socal take core (socal instance %d)", instance);
49543db86aabSstevel }
49553db86aabSstevel 
49563db86aabSstevel /*
49573db86aabSstevel  * Preset AL_PA in hardware, if is told.
49583db86aabSstevel  */
49593db86aabSstevel static void
49603db86aabSstevel socal_fix_harda(socal_state_t *socalp, int port)
49613db86aabSstevel {
49623db86aabSstevel 	socal_port_t	*portp = &socalp->port_state[port];
49633db86aabSstevel 	uint_t		*xrp = (uint_t *)socalp->socal_xrp;
49643db86aabSstevel 	uint_t		accum, harda;
49653db86aabSstevel 
49663db86aabSstevel 	harda = portp->sp_hard_alpa;
49673db86aabSstevel 	accum = xrp[SOCAL_XRAM_PORTA_HRDA/4];
49683db86aabSstevel 	if (port == 0) {
49693db86aabSstevel 		accum &= 0x00FFFFFF;
49703db86aabSstevel 		accum |= ((harda & 0xFF) << 24);
49713db86aabSstevel 	} else {
49723db86aabSstevel 		accum &= 0xFF00FFFF;
49733db86aabSstevel 		accum |= ((harda & 0xFF) << 16);
49743db86aabSstevel 	}
49753db86aabSstevel 	xrp[SOCAL_XRAM_PORTA_HRDA/4] = accum;
49763db86aabSstevel }
49773db86aabSstevel 
49783db86aabSstevel /*
49793db86aabSstevel  * Target-Mode attach function
49803db86aabSstevel  */
49813db86aabSstevel fcal_transport_t *
49823db86aabSstevel socal_sftm_attach(dev_t dev, int loop_id)
49833db86aabSstevel {
49843db86aabSstevel 	int 		instance = getminor(dev) / 2;
49853db86aabSstevel 	int		port = getminor(dev) % 2;
49863db86aabSstevel 	int		hard_alpa;
49873db86aabSstevel 	char		*name;
49883db86aabSstevel 	socal_state_t	*socalp;
49893db86aabSstevel 
49903db86aabSstevel 	/*
49913db86aabSstevel 	 * If the device is not a "socal" device, return
49923db86aabSstevel 	 */
49933db86aabSstevel 	if ((name = ddi_major_to_name(getmajor(dev))) == NULL ||
49943db86aabSstevel 	    strcmp(name, "socal") != 0)
49953db86aabSstevel 		return (NULL);
49963db86aabSstevel 
49973db86aabSstevel 	/*
49983db86aabSstevel 	 * If no soft state structure, return
49993db86aabSstevel 	 */
50003db86aabSstevel 	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
50013db86aabSstevel 	if (socalp == NULL)
50023db86aabSstevel 		return (NULL);
50033db86aabSstevel 
50043db86aabSstevel 	/*
50053db86aabSstevel 	 * If the port is already attached, return
50063db86aabSstevel 	 */
50073db86aabSstevel 	if (socalp->port_state[port].sp_status & PORT_CHILD_INIT)
50083db86aabSstevel 		return (NULL);
50093db86aabSstevel 
50103db86aabSstevel 	if (loop_id < 0 || loop_id > 126)
50113db86aabSstevel 		return (NULL);
50123db86aabSstevel 
50133db86aabSstevel 	/* if this instance is detaching, don't attach */
50143db86aabSstevel 	mutex_enter(&socalp->board_mtx);
50153db86aabSstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
50163db86aabSstevel 	if (socalp->socal_busy < 0) {
50173db86aabSstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
50183db86aabSstevel 		mutex_exit(&socalp->board_mtx);
50193db86aabSstevel 		return (NULL);
50203db86aabSstevel 	}
50213db86aabSstevel 	socalp->socal_busy++;
50223db86aabSstevel 	socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
50233db86aabSstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
50243db86aabSstevel 	mutex_exit(&socalp->board_mtx);
50253db86aabSstevel 
50263db86aabSstevel 	/*
50273db86aabSstevel 	 * Since we keep the Hard Loop-id in two config files, warn the
50283db86aabSstevel 	 * user if they don't match.
50293db86aabSstevel 	 */
50303db86aabSstevel 	hard_alpa = socal_switch_to_alpa[loop_id];
50313db86aabSstevel 	if (hard_alpa != socalp->port_state[port].sp_hard_alpa) {
50323db86aabSstevel 		socalp->port_state[port].sp_hard_alpa = hard_alpa;
50333db86aabSstevel 		cmn_err(CE_WARN, "socal%d: Hard Loop-id mismatch - "
50343db86aabSstevel 		    "using Loop-id %d",
50353db86aabSstevel 		    instance, loop_id);
50363db86aabSstevel 	}
50373db86aabSstevel 
50383db86aabSstevel 	return (socalp->port_state[port].sp_transport);
50393db86aabSstevel }
50403db86aabSstevel 
50413db86aabSstevel 
50423db86aabSstevel /*
50433db86aabSstevel  * Target-Mode detach function
50443db86aabSstevel  */
50453db86aabSstevel int
50463db86aabSstevel socal_sftm_detach(socal_state_t *socalp, int port)
50473db86aabSstevel {
50483db86aabSstevel 	mutex_enter(&socalp->board_mtx);
50493db86aabSstevel 	socalp->socal_busy--;
50503db86aabSstevel 	socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
50513db86aabSstevel 	mutex_exit(&socalp->board_mtx);
50523db86aabSstevel 
50533db86aabSstevel 	return (0);
50543db86aabSstevel }
5055