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