xref: /onnv-gate/usr/src/uts/sun/io/socal.c (revision 7656:2621e50fdf4a)
12305Sstevel /*
22305Sstevel  * CDDL HEADER START
32305Sstevel  *
42305Sstevel  * The contents of this file are subject to the terms of the
52305Sstevel  * Common Development and Distribution License (the "License").
62305Sstevel  * You may not use this file except in compliance with the License.
72305Sstevel  *
82305Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel  * or http://www.opensolaris.org/os/licensing.
102305Sstevel  * See the License for the specific language governing permissions
112305Sstevel  * and limitations under the License.
122305Sstevel  *
132305Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel  * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel  *
192305Sstevel  * CDDL HEADER END
202305Sstevel  */
212305Sstevel 
222305Sstevel /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242305Sstevel  * Use is subject to license terms.
252305Sstevel  */
262305Sstevel 
272305Sstevel 
282305Sstevel /*
292305Sstevel  * socal - Serial Optical Channel Arbitrated Loop host adapter driver.
302305Sstevel  */
312305Sstevel 
322305Sstevel #include <sys/types.h>
332305Sstevel #include <sys/note.h>
342305Sstevel #include <sys/devops.h>
352305Sstevel #include <sys/param.h>
362305Sstevel #include <sys/systm.h>
372305Sstevel #include <sys/user.h>
382305Sstevel #include <sys/buf.h>
392305Sstevel #include <sys/ioctl.h>
402305Sstevel #include <sys/uio.h>
412305Sstevel #include <sys/fcntl.h>
422305Sstevel 
432305Sstevel #include <sys/cmn_err.h>
442305Sstevel #include <sys/stropts.h>
452305Sstevel #include <sys/kmem.h>
462305Sstevel 
472305Sstevel #include <sys/errno.h>
482305Sstevel #include <sys/open.h>
492305Sstevel #include <sys/varargs.h>
502305Sstevel #include <sys/var.h>
512305Sstevel #include <sys/thread.h>
522305Sstevel #include <sys/debug.h>
532305Sstevel #include <sys/cpu.h>
542305Sstevel #include <sys/autoconf.h>
552305Sstevel #include <sys/conf.h>
562305Sstevel #include <sys/stat.h>
572305Sstevel 
582305Sstevel #include <sys/file.h>
592305Sstevel #include <sys/syslog.h>
602305Sstevel 
612305Sstevel #include <sys/ddi.h>
622305Sstevel #include <sys/sunddi.h>
632305Sstevel #include <sys/ddi_impldefs.h>
642305Sstevel #include <sys/ksynch.h>
652305Sstevel #include <sys/ddidmareq.h>
662305Sstevel #include <sys/dditypes.h>
672305Sstevel #include <sys/ethernet.h>
682305Sstevel #include <sys/socalreg.h>
692305Sstevel #include <sys/socalmap.h>
702305Sstevel #include <sys/fc4/fcal.h>
712305Sstevel #include <sys/socal_cq_defs.h>
722305Sstevel #include <sys/fc4/fcal_linkapp.h>
732305Sstevel #include <sys/fc4/fcal_transport.h>
742305Sstevel #include <sys/socalio.h>
752305Sstevel #include <sys/socalvar.h>
762305Sstevel 
772305Sstevel /*
782305Sstevel  * Local Macros
792305Sstevel  */
802305Sstevel 
812305Sstevel #ifdef DEBUG
822305Sstevel #define	SOCAL_DEBUG 1
832305Sstevel #else
842305Sstevel #define	SOCAL_DEBUG 0
852305Sstevel #endif
862305Sstevel static uchar_t	socal_xrambuf[0x40000];
872305Sstevel static int 	socal_core = SOCAL_TAKE_CORE;
882305Sstevel #if SOCAL_DEBUG > 0 && !defined(lint)
892305Sstevel static	int soc_debug = SOCAL_DEBUG;
902305Sstevel static  int socal_read_stale_data = 0;
912305Sstevel #define	DEBUGF(level, args) \
922305Sstevel 	if (soc_debug >= (level)) cmn_err args;
932305Sstevel #define	SOCALDEBUG(level, args) \
942305Sstevel 	if (soc_debug >= level) args;
952305Sstevel #else
962305Sstevel #define	DEBUGF(level, args)	/* Nothing */
972305Sstevel #define	SOCALDEBUG(level, args)	/* Nothing */
982305Sstevel #endif
992305Sstevel 
1002305Sstevel 
1012305Sstevel /* defines for properties */
1022305Sstevel #define	SOCAL_PORT_NO_PROP		"socal_port"
1032305Sstevel #define	SOCAL_ALT_PORT_NO_PROP		"port#"
1042305Sstevel 
1052305Sstevel /* for socal_force_reset() */
1062305Sstevel #define	RESET_PORT			1
1072305Sstevel #define	DONT_RESET_PORT			0
1082305Sstevel 
1092305Sstevel /*
1102305Sstevel  * Driver Entry points.
1112305Sstevel  */
1122305Sstevel static int socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1132305Sstevel static int socal_bus_ctl(dev_info_t *dip, dev_info_t *rip,
1142305Sstevel 	ddi_ctl_enum_t op, void *a, void *v);
1152305Sstevel static int socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1162305Sstevel static int socal_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
1172305Sstevel 	void *arg, void **result);
1182305Sstevel static unsigned int socal_intr(caddr_t arg);
1192305Sstevel static unsigned int socal_dummy_intr(caddr_t arg);
1202305Sstevel static int socal_open(dev_t *devp, int flag, int otyp,
1212305Sstevel 	cred_t *cred_p);
1222305Sstevel static int socal_close(dev_t dev, int flag, int otyp,
1232305Sstevel 	cred_t *cred_p);
1242305Sstevel static int socal_ioctl(dev_t dev, int cmd, intptr_t arg,
1252305Sstevel 	int mode, cred_t *cred_p, int *rval_p);
1262305Sstevel 
1272305Sstevel /*
1282305Sstevel  * FC_AL transport functions.
1292305Sstevel  */
1302305Sstevel static uint_t socal_transport(fcal_packet_t *, fcal_sleep_t, int);
1312305Sstevel static uint_t socal_transport_poll(fcal_packet_t *, uint_t, int);
1322305Sstevel static uint_t socal_lilp_map(void *, uint_t, uint32_t, uint_t);
1332305Sstevel static uint_t socal_force_lip(void *, uint_t, uint_t, uint_t);
1342305Sstevel static uint_t socal_force_offline(void *, uint_t, uint_t);
1352305Sstevel static uint_t socal_abort_cmd(void *, uint_t, fcal_packet_t *, uint_t);
1362305Sstevel static uint_t socal_doit(fcal_packet_t *, socal_port_t *, int,
1372305Sstevel     void (*)(), int, int, uint_t *);
1382305Sstevel static uint_t socal_els(void *, uint_t, uint_t, uint_t,
1392305Sstevel 	void (*callback)(), void *, caddr_t, caddr_t *, uint_t);
1402305Sstevel static uint_t socal_bypass_dev(void *, uint_t, uint_t);
1412305Sstevel static void socal_force_reset(void *, uint_t, uint_t);
1422305Sstevel static void socal_add_ulp(void *, uint_t, uchar_t, void (*)(),
1432305Sstevel 	void (*)(), void (*)(), void *);
1442305Sstevel static void socal_remove_ulp(void *, uint_t, uchar_t, void *);
1452305Sstevel static void socal_take_core(void *);
1462305Sstevel 
1472305Sstevel /*
1482305Sstevel  * Driver internal functions.
1492305Sstevel  */
1502305Sstevel static void socal_intr_solicited(socal_state_t *, uint32_t srq);
1512305Sstevel static void socal_intr_unsolicited(socal_state_t *, uint32_t urq);
1522305Sstevel static void socal_lilp_map_done(fcal_packet_t *);
1532305Sstevel static void socal_force_lip_done(fcal_packet_t *);
1542305Sstevel static void socal_force_offline_done(fcal_packet_t *);
1552305Sstevel static void socal_abort_done(fcal_packet_t *);
1562305Sstevel static void socal_bypass_dev_done(fcal_packet_t *);
1572305Sstevel static fcal_packet_t *socal_packet_alloc(socal_state_t *, fcal_sleep_t);
1582305Sstevel static void socal_packet_free(fcal_packet_t *);
1592305Sstevel static void socal_disable(socal_state_t *socalp);
1602305Sstevel static void socal_init_transport_interface(socal_state_t *socalp);
1612305Sstevel static int socal_cqalloc_init(socal_state_t *socalp, uint32_t index);
1622305Sstevel static void socal_cqinit(socal_state_t *socalp, uint32_t index);
1632305Sstevel static int socal_start(socal_state_t *socalp);
1642305Sstevel static void socal_doreset(socal_state_t *socalp);
1652305Sstevel static int socal_dodetach(dev_info_t *dip);
1662305Sstevel static int socal_diag_request(socal_state_t *socalp, uint32_t port,
1672305Sstevel 	uint_t *diagcode, uint32_t cmd);
1682305Sstevel static void socal_download_ucode(socal_state_t *socalp);
1692305Sstevel static void socal_init_cq_desc(socal_state_t *socalp);
1702305Sstevel static void socal_init_wwn(socal_state_t *socalp);
1712305Sstevel static void socal_enable(socal_state_t *socalp);
1722305Sstevel static int socal_establish_pool(socal_state_t *socalp, uint32_t poolid);
1732305Sstevel static int socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid);
1742305Sstevel static int socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t
1752305Sstevel 	dest, la_els_adisc_t *adisc_pl, uint32_t polled);
1762305Sstevel static int socal_issue_lbf(socal_state_t *socalp, uint32_t port,
1772305Sstevel 	uchar_t *flb_pl, size_t length, uint32_t polled);
1782305Sstevel static int socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t
1792305Sstevel 	dest, la_els_rls_reply_t *rls_pl, uint32_t polled);
1802305Sstevel static void socal_us_els(socal_state_t *, cqe_t *, caddr_t);
1812305Sstevel static fcal_packet_t *socal_els_alloc(socal_state_t *, uint32_t, uint32_t,
1822305Sstevel 	uint32_t, uint32_t, caddr_t *, uint32_t);
1832305Sstevel static fcal_packet_t *socal_lbf_alloc(socal_state_t *, uint32_t,
1842305Sstevel 	uint32_t, uint32_t, caddr_t *, uint32_t);
1852305Sstevel static void socal_els_free(socal_priv_cmd_t *);
1862305Sstevel static void socal_lbf_free(socal_priv_cmd_t *);
1872305Sstevel static int socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
1882305Sstevel 	uint32_t polled, int);
1892305Sstevel static void socal_flush_overflowq(socal_state_t *, int, int);
1902305Sstevel static void socal_deferred_intr(void *);
1912305Sstevel static void socal_fix_harda(socal_state_t *socalp, int port);
1922305Sstevel 
1932305Sstevel /*
1942305Sstevel  * SOC+ Circular Queue Management routines.
1952305Sstevel  */
1962305Sstevel static int socal_cq_enque(socal_state_t *, socal_port_t *, cqe_t *, int,
1972305Sstevel 	fcal_sleep_t, fcal_packet_t *, int);
1982305Sstevel 
1992305Sstevel /*
2002305Sstevel  * Utility functions
2012305Sstevel  */
2022305Sstevel static void socal_disp_err(socal_state_t *, uint_t level, char *mid, char *msg);
2032305Sstevel static void socal_wcopy(uint_t *, uint_t *, int);
2042305Sstevel 
2052305Sstevel /*
2062305Sstevel  *  Set this bit to enable 64-bit sus mode
2072305Sstevel  */
2082305Sstevel static	int socal_64bitsbus = 1;
2092305Sstevel 
2102305Sstevel /*
2112305Sstevel  * Default soc dma limits
2122305Sstevel  */
2132305Sstevel 
2142305Sstevel static ddi_dma_lim_t default_socallim = {
2152305Sstevel 	(ulong_t)0, (ulong_t)0xffffffff, (uint_t)0xffffffff,
2162305Sstevel 	DEFAULT_BURSTSIZE | BURST32 | BURST64, 1, (25*1024)
2172305Sstevel };
2182305Sstevel 
2192305Sstevel static struct ddi_dma_attr socal_dma_attr = {
2202305Sstevel 	DMA_ATTR_V0,			/* version */
2212305Sstevel 	(unsigned long long)0,		/* addr_lo */
2222305Sstevel 	(unsigned long long)0xffffffff,	/* addr_hi */
2232305Sstevel 	(unsigned long long)0xffffffff,	/* count max */
2242305Sstevel 	(unsigned long long)4,		/* align */
2252305Sstevel 	DEFAULT_BURSTSIZE | BURST32 | BURST64, 	/* burst size */
2262305Sstevel 	1,				/* minxfer */
2272305Sstevel 	(unsigned long long)0xffffffff,	/* maxxfer */
2282305Sstevel 	(unsigned long long)0xffffffff,	/* seg */
2292305Sstevel 	1,				/* sgllen */
2302305Sstevel 	4,				/* granularity */
2312305Sstevel 	0				/* flags */
2322305Sstevel };
2332305Sstevel 
2342305Sstevel static struct ddi_device_acc_attr socal_acc_attr = {
2352305Sstevel 	(ushort_t)DDI_DEVICE_ATTR_V0,	/* version */
2362305Sstevel 	(uchar_t)DDI_STRUCTURE_BE_ACC,	/* endian flags */
2372305Sstevel 	(uchar_t)DDI_STRICTORDER_ACC	/* data order */
2382305Sstevel };
2392305Sstevel 
2402305Sstevel static struct fcal_transport_ops socal_transport_ops = {
2412305Sstevel 	socal_transport,
2422305Sstevel 	socal_transport_poll,
2432305Sstevel 	socal_lilp_map,
2442305Sstevel 	socal_force_lip,
2452305Sstevel 	socal_abort_cmd,
2462305Sstevel 	socal_els,
2472305Sstevel 	socal_bypass_dev,
2482305Sstevel 	socal_force_reset,
2492305Sstevel 	socal_add_ulp,
2502305Sstevel 	socal_remove_ulp,
2512305Sstevel 	socal_take_core
2522305Sstevel };
2532305Sstevel 
2542305Sstevel /*
2552305Sstevel  * Table used for setting the burst size in the soc+ config register
2562305Sstevel  */
2572305Sstevel static int socal_burst32_table[] = {
2582305Sstevel 	SOCAL_CR_BURST_4,
2592305Sstevel 	SOCAL_CR_BURST_4,
2602305Sstevel 	SOCAL_CR_BURST_4,
2612305Sstevel 	SOCAL_CR_BURST_4,
2622305Sstevel 	SOCAL_CR_BURST_16,
2632305Sstevel 	SOCAL_CR_BURST_32,
2642305Sstevel 	SOCAL_CR_BURST_64
2652305Sstevel };
2662305Sstevel 
2672305Sstevel /*
2682305Sstevel  * Table for setting the burst size for 64-bit sbus mode in soc+'s CR
2692305Sstevel  */
2702305Sstevel static int socal_burst64_table[] = {
2712305Sstevel 	(SOCAL_CR_BURST_8 << 8),
2722305Sstevel 	(SOCAL_CR_BURST_8 << 8),
2732305Sstevel 	(SOCAL_CR_BURST_8 << 8),
2742305Sstevel 	(SOCAL_CR_BURST_8 << 8),
2752305Sstevel 	(SOCAL_CR_BURST_8 << 8),
2762305Sstevel 	(SOCAL_CR_BURST_32 << 8),
2772305Sstevel 	(SOCAL_CR_BURST_64 << 8),
2782305Sstevel 	(SOCAL_CR_BURST_128 << 8)
2792305Sstevel };
2802305Sstevel 
2812305Sstevel /*
2822305Sstevel  * Tables used to define the sizes of the Circular Queues
2832305Sstevel  *
2842305Sstevel  * To conserve DVMA/IOPB space, we make some of these queues small...
2852305Sstevel  */
2862305Sstevel static int socal_req_entries[] = {
2872305Sstevel 	SOCAL_SMALL_CQ_ENTRIES,		/* Error (reset, lip) requests */
2882305Sstevel 	SOCAL_MAX_CQ_ENTRIES,		/* Most commands */
2892305Sstevel 	0,				/* Not currently used */
2902305Sstevel 	0				/* Not currently used */
2912305Sstevel };
2922305Sstevel 
2932305Sstevel static int socal_rsp_entries[] = {
2942305Sstevel 	SOCAL_MAX_CQ_ENTRIES,		/* Solicited  "SOC_OK" responses */
2952305Sstevel 	SOCAL_SMALL_CQ_ENTRIES,		/* Solicited error responses */
2962305Sstevel 	0,			/* Unsolicited responses */
2972305Sstevel 	0				/* Not currently used */
2982305Sstevel };
2992305Sstevel 
3002305Sstevel /*
3012305Sstevel  * Bus ops vector
3022305Sstevel  */
3032305Sstevel 
3042305Sstevel static struct bus_ops socal_bus_ops = {
3052305Sstevel 	BUSO_REV,		/* rev */
3062305Sstevel 	nullbusmap,		/* int (*bus_map)() */
3072305Sstevel 	0,			/* ddi_intrspec_t (*bus_get_intrspec)(); */
3082305Sstevel 	0,			/* int (*bus_add_intrspec)(); */
3092305Sstevel 	0,			/* void	(*bus_remove_intrspec)(); */
3102305Sstevel 	i_ddi_map_fault,	/* int (*bus_map_fault)() */
3112305Sstevel 	ddi_dma_map,		/* int (*bus_dma_map)() */
3122305Sstevel 	ddi_dma_allochdl,
3132305Sstevel 	ddi_dma_freehdl,
3142305Sstevel 	ddi_dma_bindhdl,
3152305Sstevel 	ddi_dma_unbindhdl,
3162305Sstevel 	ddi_dma_flush,
3172305Sstevel 	ddi_dma_win,
3182305Sstevel 	ddi_dma_mctl,		/* int (*bus_dma_ctl)() */
3192305Sstevel 	socal_bus_ctl,		/* int (*bus_ctl)() */
320*7656SSherry.Moore@Sun.COM 	ddi_bus_prop_op,	/* int (*bus_prop_op*)() */
3212305Sstevel };
3222305Sstevel 
3232305Sstevel static struct cb_ops socal_cb_ops = {
3242305Sstevel 	socal_open,		/* int (*cb_open)() */
3252305Sstevel 	socal_close,		/* int (*cb_close)() */
3262305Sstevel 	nodev,			/* int (*cb_strategy)() */
3272305Sstevel 	nodev,			/* int (*cb_print)() */
3282305Sstevel 	nodev,			/* int (*cb_dump)() */
3292305Sstevel 	nodev,			/* int (*cb_read)() */
3302305Sstevel 	nodev,			/* int (*cb_write)() */
3312305Sstevel 	socal_ioctl,		/* int (*cb_ioctl)() */
3322305Sstevel 	nodev,			/* int (*cb_devmap)() */
3332305Sstevel 	nodev,			/* int (*cb_mmap)() */
3342305Sstevel 	nodev,			/* int (*cb_segmap)() */
3352305Sstevel 	nochpoll,		/* int (*cb_chpoll)() */
3362305Sstevel 	ddi_prop_op,		/* int (*cb_prop_op)() */
3372305Sstevel 	0,			/* struct streamtab *cb_str */
3382305Sstevel 	D_MP|D_NEW|D_HOTPLUG,	/* cb_flag */
3392305Sstevel 	CB_REV,			/* rev */
3402305Sstevel 	nodev,			/* int (*cb_aread)() */
3412305Sstevel 	nodev			/* int (*cb_awrite)() */
3422305Sstevel };
3432305Sstevel 
3442305Sstevel /*
3452305Sstevel  * Soc driver ops structure.
3462305Sstevel  */
3472305Sstevel 
3482305Sstevel static struct dev_ops socal_ops = {
3492305Sstevel 	DEVO_REV,		/* devo_rev, */
3502305Sstevel 	0,			/* refcnt */
3512305Sstevel 	socal_getinfo,		/* get_dev_info */
3522305Sstevel 	nulldev,		/* identify */
3532305Sstevel 	nulldev,		/* probe */
3542305Sstevel 	socal_attach,		/* attach */
3552305Sstevel 	socal_detach,		/* detach */
3562305Sstevel 	nodev,			/* reset */
3572305Sstevel 	&socal_cb_ops,		/* driver operations */
358*7656SSherry.Moore@Sun.COM 	&socal_bus_ops,		/* bus operations */
359*7656SSherry.Moore@Sun.COM 	NULL,			/* power */
360*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* quiesce */
3612305Sstevel };
3622305Sstevel 
3632305Sstevel /*
3642305Sstevel  * Driver private variables.
3652305Sstevel  */
3662305Sstevel 
3672305Sstevel static void *socal_soft_state_p = NULL;
3682305Sstevel static ddi_dma_lim_t *socallim = NULL;
3692305Sstevel 
3702305Sstevel static uchar_t socal_switch_to_alpa[] = {
3712305Sstevel 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
3722305Sstevel 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
3732305Sstevel 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
3742305Sstevel 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
3752305Sstevel 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
3762305Sstevel 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
3772305Sstevel 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
3782305Sstevel 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
3792305Sstevel 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
3802305Sstevel 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
3812305Sstevel 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
3822305Sstevel 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
3832305Sstevel 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
3842305Sstevel };
3852305Sstevel 
3862305Sstevel /*
3872305Sstevel  * Firmware related externs
3882305Sstevel  */
3892305Sstevel extern uint32_t socal_ucode[];
3902305Sstevel extern size_t socal_ucode_size;
3912305Sstevel 
3922305Sstevel /*
3932305Sstevel  * This is the loadable module wrapper: "module configuration section".
3942305Sstevel  */
3952305Sstevel 
3962305Sstevel #include <sys/modctl.h>
3972305Sstevel extern struct mod_ops mod_driverops;
3982305Sstevel 
3992305Sstevel /*
4002305Sstevel  * Module linkage information for the kernel.
4012305Sstevel  */
4022305Sstevel #define	SOCAL_NAME "SOC+ FC-AL Host Adapter Driver"
403*7656SSherry.Moore@Sun.COM static	char	socal_version[] = "1.62 08/19/2008";
4042305Sstevel static struct modldrv modldrv = {
4052305Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
406*7656SSherry.Moore@Sun.COM 	SOCAL_NAME,
4072305Sstevel 	&socal_ops,		/* driver ops */
4082305Sstevel };
4092305Sstevel 
4102305Sstevel static struct modlinkage modlinkage = {
4112305Sstevel 	MODREV_1, (void *)&modldrv, NULL
4122305Sstevel };
4132305Sstevel 
4142305Sstevel /*
4152305Sstevel  * This is the module initialization/completion routines
4162305Sstevel  */
4172305Sstevel 
4182305Sstevel #if !defined(lint)
419*7656SSherry.Moore@Sun.COM static char socal_initmsg[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
4202305Sstevel #endif
4212305Sstevel 
4222305Sstevel int
_init(void)4232305Sstevel _init(void)
4242305Sstevel {
4252305Sstevel 	int stat;
4262305Sstevel 
4272305Sstevel 	DEBUGF(4, (CE_CONT, socal_initmsg));
4282305Sstevel 
4292305Sstevel 	/* Allocate soft state.  */
4302305Sstevel 	stat = ddi_soft_state_init(&socal_soft_state_p,
431*7656SSherry.Moore@Sun.COM 	    sizeof (socal_state_t), SOCAL_INIT_ITEMS);
4322305Sstevel 	if (stat != 0)
4332305Sstevel 		return (stat);
4342305Sstevel 
4352305Sstevel 	/* Install the module */
4362305Sstevel 	stat = mod_install(&modlinkage);
4372305Sstevel 	if (stat != 0)
4382305Sstevel 		ddi_soft_state_fini(&socal_soft_state_p);
4392305Sstevel 
4402305Sstevel 	DEBUGF(4, (CE_CONT, "socal: _init: return=%d\n", stat));
4412305Sstevel 	return (stat);
4422305Sstevel }
4432305Sstevel 
4442305Sstevel int
_fini(void)4452305Sstevel _fini(void)
4462305Sstevel {
4472305Sstevel 	int stat;
4482305Sstevel 
4492305Sstevel 	if ((stat = mod_remove(&modlinkage)) != 0)
4502305Sstevel 		return (stat);
4512305Sstevel 
4522305Sstevel 	DEBUGF(4, (CE_CONT, "socal: _fini: \n"));
4532305Sstevel 
4542305Sstevel 	ddi_soft_state_fini(&socal_soft_state_p);
4552305Sstevel 
4562305Sstevel 	DEBUGF(4, (CE_CONT, "socal: _fini: return=%d\n", stat));
4572305Sstevel 	return (stat);
4582305Sstevel }
4592305Sstevel 
4602305Sstevel int
_info(struct modinfo * modinfop)4612305Sstevel _info(struct modinfo *modinfop)
4622305Sstevel {
4632305Sstevel 	return (mod_info(&modlinkage, modinfop));
4642305Sstevel }
4652305Sstevel 
4662305Sstevel 
4672305Sstevel int
socal_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4682305Sstevel socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4692305Sstevel {
4702305Sstevel 	int			instance;
4712305Sstevel 	socal_state_t		*socalp;
4722305Sstevel 	struct ether_addr	ourmacaddr;
4732305Sstevel 	socal_port_t		*porta, *portb;
4742305Sstevel 	char			buf[MAXPATHLEN];
4752305Sstevel 	char			*cptr, *wwn;
4762305Sstevel 	int			y;
4772305Sstevel 	int			i, j;
4782305Sstevel 	int			burstsize;
4792305Sstevel 	short			s;
4802305Sstevel 	int			loop_id;
4812305Sstevel 
4822305Sstevel 	int			rval;
4832305Sstevel 
4842305Sstevel 
4852305Sstevel 	instance = ddi_get_instance(dip);
4862305Sstevel 
4872305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d entering attach: cmd=%x\n", instance,
4882305Sstevel 	    cmd));
4892305Sstevel 
4902305Sstevel 	if (cmd == DDI_RESUME) {
4912305Sstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
4922305Sstevel 			return (DDI_FAILURE);
4932305Sstevel 
4942305Sstevel 		if (!socalp->socal_shutdown) {
4952305Sstevel 			/* our work is already done */
4962305Sstevel 			return (DDI_SUCCESS);
4972305Sstevel 		}
4982305Sstevel 		if (socal_start(socalp) != FCAL_SUCCESS) {
4992305Sstevel 			return	(DDI_FAILURE);
5002305Sstevel 		}
5012305Sstevel 		DEBUGF(4, (CE_CONT, "socal%d resumed\n", instance));
5022305Sstevel 		return (DDI_SUCCESS);
5032305Sstevel 	}
5042305Sstevel 
5052305Sstevel 	if (cmd != DDI_ATTACH) {
5062305Sstevel 		return (DDI_FAILURE);
5072305Sstevel 	}
5082305Sstevel 
5092305Sstevel 	if (ddi_dev_is_sid(dip) != DDI_SUCCESS) {
5102305Sstevel 		cmn_err(CE_WARN, "socal%d probe: Not self-identifying",
511*7656SSherry.Moore@Sun.COM 		    instance);
5122305Sstevel 		return (DDI_FAILURE);
5132305Sstevel 	}
5142305Sstevel 
5152305Sstevel 	/* If we are in a slave-slot, then we can't be used. */
5162305Sstevel 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
5172305Sstevel 		cmn_err(CE_WARN,
518*7656SSherry.Moore@Sun.COM 		    "socal%d attach failed: device in slave-only slot",
519*7656SSherry.Moore@Sun.COM 		    instance);
5202305Sstevel 		return (DDI_FAILURE);
5212305Sstevel 	}
5222305Sstevel 
5232305Sstevel 	if (ddi_intr_hilevel(dip, 0)) {
5242305Sstevel 		/*
5252305Sstevel 		 * Interrupt number '0' is a high-level interrupt.
5262305Sstevel 		 * At this point you either add a special interrupt
5272305Sstevel 		 * handler that triggers a soft interrupt at a lower level,
5282305Sstevel 		 * or - more simply and appropriately here - you just
5292305Sstevel 		 * fail the attach.
5302305Sstevel 		 */
5312305Sstevel 		cmn_err(CE_WARN,
5322305Sstevel 		"socal%d attach failed: hilevel interrupt unsupported",
533*7656SSherry.Moore@Sun.COM 		    instance);
5342305Sstevel 		return (DDI_FAILURE);
5352305Sstevel 	}
5362305Sstevel 
5372305Sstevel 	/* Allocate soft state. */
5382305Sstevel 	if (ddi_soft_state_zalloc(socal_soft_state_p, instance)
5392305Sstevel 	    != DDI_SUCCESS) {
5402305Sstevel 		cmn_err(CE_WARN, "socal%d attach failed: alloc soft state",
541*7656SSherry.Moore@Sun.COM 		    instance);
5422305Sstevel 		return (DDI_FAILURE);
5432305Sstevel 	}
5442305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: allocated soft state\n",
545*7656SSherry.Moore@Sun.COM 	    instance));
5462305Sstevel 
5472305Sstevel 	/*
5482305Sstevel 	 * Initialize the state structure.
5492305Sstevel 	 */
5502305Sstevel 	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
5512305Sstevel 	if (socalp == (socal_state_t *)NULL) {
5522305Sstevel 		cmn_err(CE_WARN, "socal%d attach failed: bad soft state",
553*7656SSherry.Moore@Sun.COM 		    instance);
5542305Sstevel 		return (DDI_FAILURE);
5552305Sstevel 	}
5562305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: soc soft state ptr=0x%p\n",
557*7656SSherry.Moore@Sun.COM 	    instance, socalp));
5582305Sstevel 
5592305Sstevel 	socalp->dip = dip;
5602305Sstevel 	socallim = &default_socallim;
5612305Sstevel 	porta = &socalp->port_state[0];
5622305Sstevel 	portb = &socalp->port_state[1];
5632305Sstevel 
5642305Sstevel 	/* Get the full path name for displaying error messages */
5652305Sstevel 	cptr = ddi_pathname(dip, buf);
5662305Sstevel 	(void) strcpy(socalp->socal_name, cptr);
5672305Sstevel 
5682305Sstevel 	porta->sp_unsol_cb = NULL;
5692305Sstevel 	portb->sp_unsol_cb = NULL;
5702305Sstevel 	porta->sp_port = 0;
5712305Sstevel 	portb->sp_port = 1;
5722305Sstevel 	porta->sp_board = socalp;
5732305Sstevel 	portb->sp_board = socalp;
5742305Sstevel 
5752305Sstevel 	porta->sp_lilpmap_valid = 0;
5762305Sstevel 	portb->sp_lilpmap_valid = 0;
5772305Sstevel 
5782305Sstevel 	/*
5792305Sstevel 	 * If an hard loop-id property is present, then the port is going
5802305Sstevel 	 * to be used in target-mode so set the target-mode flag.
5812305Sstevel 	 */
5822305Sstevel 	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
5832305Sstevel 	    "port0-loop-id", 127);
5842305Sstevel 	if (loop_id >= 0 && loop_id <= 126) {
5852305Sstevel 		porta->sp_status |= PORT_TARGET_MODE;
5862305Sstevel 		porta->sp_hard_alpa = socal_switch_to_alpa[loop_id];
5872305Sstevel 	} else porta->sp_hard_alpa = 0xfe;
5882305Sstevel 
5892305Sstevel 	loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
5902305Sstevel 	    "port1-loop-id", 127);
5912305Sstevel 	if (loop_id >= 0 && loop_id <= 126) {
5922305Sstevel 		portb->sp_status |= PORT_TARGET_MODE;
5932305Sstevel 		portb->sp_hard_alpa = socal_switch_to_alpa[loop_id];
5942305Sstevel 	} else portb->sp_hard_alpa = 0xfe;
5952305Sstevel 
5962305Sstevel 	/* Get out Node wwn and calculate port wwns */
5972305Sstevel 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip,
598*7656SSherry.Moore@Sun.COM 	    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
599*7656SSherry.Moore@Sun.COM 	    DDI_PROP_CANSLEEP, "wwn", (caddr_t)&wwn, &i);
6002305Sstevel 
6012305Sstevel 	if ((rval != DDI_PROP_SUCCESS) || (i < FC_WWN_SIZE) ||
6022305Sstevel 	    (bcmp(wwn, "00000000", FC_WWN_SIZE) == 0)) {
6032305Sstevel 		(void) localetheraddr((struct ether_addr *)NULL, &ourmacaddr);
6042305Sstevel 
6052305Sstevel 		bcopy((caddr_t)&ourmacaddr, (caddr_t)&s, sizeof (short));
6062305Sstevel 		socalp->socal_n_wwn.w.wwn_hi = s;
6072305Sstevel 		bcopy((caddr_t)&ourmacaddr+2,
608*7656SSherry.Moore@Sun.COM 		    (caddr_t)&socalp->socal_n_wwn.w.wwn_lo,
609*7656SSherry.Moore@Sun.COM 		    sizeof (uint_t));
6102305Sstevel 		socalp->socal_n_wwn.w.naa_id = NAA_ID_IEEE;
6112305Sstevel 		socalp->socal_n_wwn.w.nport_id = 0;
6122305Sstevel 	} else {
6132305Sstevel 		bcopy((caddr_t)wwn, (caddr_t)&socalp->socal_n_wwn, FC_WWN_SIZE);
6142305Sstevel 	}
6152305Sstevel 
6162305Sstevel 	if (rval == DDI_SUCCESS)
6172305Sstevel 		kmem_free((void *)wwn, i);
6182305Sstevel 
6192305Sstevel 	for (i = 0; i < FC_WWN_SIZE; i++) {
6202305Sstevel 		(void) sprintf(&socalp->socal_stats.node_wwn[i << 1],
621*7656SSherry.Moore@Sun.COM 		    "%02x", socalp->socal_n_wwn.raw_wwn[i]);
6222305Sstevel 	}
6232305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: node wwn: %s\n",
624*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_stats.node_wwn));
6252305Sstevel 
6262305Sstevel 	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&porta->sp_p_wwn,
627*7656SSherry.Moore@Sun.COM 	    sizeof (la_wwn_t));
6282305Sstevel 	bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&portb->sp_p_wwn,
629*7656SSherry.Moore@Sun.COM 	    sizeof (la_wwn_t));
6302305Sstevel 	porta->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
6312305Sstevel 	portb->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
6322305Sstevel 	porta->sp_p_wwn.w.nport_id = instance*2;
6332305Sstevel 	portb->sp_p_wwn.w.nport_id = instance*2+1;
6342305Sstevel 
6352305Sstevel 	for (i = 0; i < FC_WWN_SIZE; i++) {
6362305Sstevel 		(void) sprintf(&socalp->socal_stats.port_wwn[0][i << 1],
637*7656SSherry.Moore@Sun.COM 		    "%02x", porta->sp_p_wwn.raw_wwn[i]);
6382305Sstevel 		(void) sprintf(&socalp->socal_stats.port_wwn[1][i << 1],
639*7656SSherry.Moore@Sun.COM 		    "%02x", portb->sp_p_wwn.raw_wwn[i]);
6402305Sstevel 	}
6412305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: porta wwn: %s\n",
642*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_stats.port_wwn[0]));
6432305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: portb wwn: %s\n",
644*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_stats.port_wwn[1]));
6452305Sstevel 
6462305Sstevel 	if ((porta->sp_transport = (fcal_transport_t *)
647*7656SSherry.Moore@Sun.COM 	    kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
6482305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4011",
649*7656SSherry.Moore@Sun.COM 		    "attach failed: unable to alloc xport struct");
6502305Sstevel 		goto fail;
6512305Sstevel 	}
6522305Sstevel 
6532305Sstevel 	if ((portb->sp_transport = (fcal_transport_t *)
654*7656SSherry.Moore@Sun.COM 	    kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
6552305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4012",
656*7656SSherry.Moore@Sun.COM 		    "attach failed: unable to alloc xport struct");
6572305Sstevel 		goto fail;
6582305Sstevel 	}
6592305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: allocated transport structs\n",
660*7656SSherry.Moore@Sun.COM 	    instance));
6612305Sstevel 
6622305Sstevel 	/*
6632305Sstevel 	 * Map the external ram and registers for SOC+.
6642305Sstevel 	 * Note: Soc+ sbus host adapter provides 3 register definition
6652305Sstevel 	 * but on-board Soc+'s  may have only one register definition.
6662305Sstevel 	 */
6672305Sstevel 	if ((ddi_dev_nregs(dip, &i) == DDI_SUCCESS) && (i == 1)) {
6682305Sstevel 		/* Map XRAM */
6692305Sstevel 		if (ddi_map_regs(dip, 0, &socalp->socal_xrp, 0, 0)
670*7656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
6712305Sstevel 			socalp->socal_xrp = NULL;
6722305Sstevel 			socal_disp_err(socalp, CE_WARN, "attach.4020",
673*7656SSherry.Moore@Sun.COM 			    "attach failed: unable to map XRAM");
6742305Sstevel 			goto fail;
6752305Sstevel 		}
6762305Sstevel 		/* Map registers */
6772305Sstevel 		socalp->socal_rp = (socal_reg_t *)(socalp->socal_xrp +
678*7656SSherry.Moore@Sun.COM 		    SOCAL_XRAM_SIZE);
6792305Sstevel 	} else {
6802305Sstevel 		/* Map EEPROM */
6812305Sstevel 		if (ddi_map_regs(dip, 0, &socalp->socal_eeprom, 0, 0) !=
6822305Sstevel 		    DDI_SUCCESS) {
6832305Sstevel 			socalp->socal_eeprom = NULL;
6842305Sstevel 			socal_disp_err(socalp, CE_WARN, "attach.4010",
685*7656SSherry.Moore@Sun.COM 			    "attach failed: unable to map eeprom");
6862305Sstevel 			goto fail;
6872305Sstevel 		}
6882305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped eeprom 0x%p\n",
689*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_eeprom));
6902305Sstevel 		/* Map XRAM */
6912305Sstevel 		if (ddi_map_regs(dip, 1, &socalp->socal_xrp, 0, 0) !=
692*7656SSherry.Moore@Sun.COM 		    DDI_SUCCESS) {
6932305Sstevel 			socalp->socal_xrp = NULL;
6942305Sstevel 			socal_disp_err(socalp, CE_WARN, "attach.4020",
695*7656SSherry.Moore@Sun.COM 			    "attach failed: unable to map XRAM");
6962305Sstevel 			goto fail;
6972305Sstevel 		}
6982305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped xram 0x%p\n",
699*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_xrp));
7002305Sstevel 		/* Map registers */
7012305Sstevel 		if (ddi_map_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0) !=
702*7656SSherry.Moore@Sun.COM 		    DDI_SUCCESS) {
7032305Sstevel 			socalp->socal_rp = NULL;
7042305Sstevel 			socal_disp_err(socalp, CE_WARN, "attach.4030",
705*7656SSherry.Moore@Sun.COM 			    "attach failed: unable to map registers");
7062305Sstevel 			goto fail;
7072305Sstevel 		}
7082305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: mapped regs 0x%p\n",
709*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_rp));
7102305Sstevel 	}
7112305Sstevel 	/*
7122305Sstevel 	 * Check to see we really have a SOC+ Host Adapter card installed
7132305Sstevel 	 */
7142305Sstevel 	if (ddi_peek32(dip, (int32_t *)&socalp->socal_rp->socal_csr.w,
715*7656SSherry.Moore@Sun.COM 	    (int32_t *)NULL) != DDI_SUCCESS) {
7162305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4040",
717*7656SSherry.Moore@Sun.COM 		    "attach failed: unable to access status register");
7182305Sstevel 		goto fail;
7192305Sstevel 	}
7202305Sstevel 	/* now that we have our registers mapped make sure soc+ reset */
7212305Sstevel 	socal_disable(socalp);
7222305Sstevel 
7232305Sstevel 	/* try defacing a spot in XRAM */
7242305Sstevel 	if (ddi_poke32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
725*7656SSherry.Moore@Sun.COM 	    0xdefaced) != DDI_SUCCESS) {
7262305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4050",
727*7656SSherry.Moore@Sun.COM 		    "attach failed: unable to write host adapter XRAM");
7282305Sstevel 		goto fail;
7292305Sstevel 	}
7302305Sstevel 
7312305Sstevel 	/* see if it stayed defaced */
7322305Sstevel 	if (ddi_peek32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
7332305Sstevel 	    (int32_t *)&y)
734*7656SSherry.Moore@Sun.COM 	    != DDI_SUCCESS) {
7352305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4051",
736*7656SSherry.Moore@Sun.COM 		    "attach failed: unable to access host adapter XRAM");
7372305Sstevel 		goto fail;
7382305Sstevel 	}
7392305Sstevel 
7402305Sstevel #ifdef DEBUG
7412305Sstevel 	for (i = 0; i < 4; i++) {
7422305Sstevel 		socalp->socal_rp->socal_cr.w &=
743*7656SSherry.Moore@Sun.COM 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
7442305Sstevel 		socalp->socal_rp->socal_cr.w |= i<<24;
7452305Sstevel 		cptr = (char *)(socal_xrambuf + (i*0x10000));
7462305Sstevel 		bcopy((caddr_t)socalp->socal_xrp, (caddr_t)cptr, 0x10000);
7472305Sstevel 	}
7482305Sstevel 	socalp->socal_rp->socal_cr.w &= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
7492305Sstevel #endif
7502305Sstevel 
7512305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d attach: read xram\n", instance));
7522305Sstevel 
7532305Sstevel 	if (y != 0xdefaced) {
7542305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4052",
755*7656SSherry.Moore@Sun.COM 		    "attach failed: read/write mismatch in XRAM");
7562305Sstevel 		goto fail;
7572305Sstevel 	}
7582305Sstevel 
7592305Sstevel 	/* Point to the SOC XRAM CQ Descriptor locations. */
7602305Sstevel 	socalp->xram_reqp = (soc_cq_t *)(socalp->socal_xrp +
761*7656SSherry.Moore@Sun.COM 	    SOCAL_XRAM_REQ_DESC);
7622305Sstevel 	socalp->xram_rspp = (soc_cq_t *)(socalp->socal_xrp +
763*7656SSherry.Moore@Sun.COM 	    SOCAL_XRAM_RSP_DESC);
7642305Sstevel 
7652305Sstevel 	if ((socalp->socal_ksp = kstat_create("socal", instance, "statistics",
7662305Sstevel 	    "controller", KSTAT_TYPE_RAW, sizeof (struct socal_stats),
7672305Sstevel 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
7682305Sstevel 		socal_disp_err(socalp, CE_WARN, "attach.4053",
769*7656SSherry.Moore@Sun.COM 		    "unable to create kstats");
7702305Sstevel 	} else {
7712305Sstevel 		socalp->socal_stats.version = 2;
7722305Sstevel 		(void) sprintf(socalp->socal_stats.drvr_name,
773*7656SSherry.Moore@Sun.COM 		    "%s: %s", SOCAL_NAME, socal_version);
7742305Sstevel 		socalp->socal_stats.pstats[0].port = 0;
7752305Sstevel 		socalp->socal_stats.pstats[1].port = 1;
7762305Sstevel 		socalp->socal_ksp->ks_data = (void *)&socalp->socal_stats;
7772305Sstevel 		kstat_install(socalp->socal_ksp);
7782305Sstevel 	}
7792305Sstevel 
7802305Sstevel 	/*
7812305Sstevel 	 * Install a dummy interrupt routine.
7822305Sstevel 	 */
7832305Sstevel 	if (ddi_add_intr(dip,
784*7656SSherry.Moore@Sun.COM 	    (uint_t)0,
785*7656SSherry.Moore@Sun.COM 	    &socalp->iblkc,
786*7656SSherry.Moore@Sun.COM 	    &socalp->idevc,
787*7656SSherry.Moore@Sun.COM 	    socal_dummy_intr,
788*7656SSherry.Moore@Sun.COM 	    (caddr_t)socalp) != DDI_SUCCESS) {
789*7656SSherry.Moore@Sun.COM 			socal_disp_err(socalp, CE_WARN, "attach.4060",
7902305Sstevel 			"attach failed: unable to install interrupt handler");
791*7656SSherry.Moore@Sun.COM 			goto fail;
7922305Sstevel 	}
7932305Sstevel 
7942305Sstevel 	ddi_set_driver_private(dip, socalp);
7952305Sstevel 
7962305Sstevel 	/* initialize the interrupt mutex */
7972305Sstevel 	mutex_init(&socalp->k_imr_mtx, NULL, MUTEX_DRIVER,
7982305Sstevel 	    (void *)socalp->iblkc);
7992305Sstevel 
8002305Sstevel 	mutex_init(&socalp->board_mtx, NULL, MUTEX_DRIVER,
8012305Sstevel 	    (void *)socalp->iblkc);
8022305Sstevel 	mutex_init(&socalp->ioctl_mtx, NULL, MUTEX_DRIVER,
8032305Sstevel 	    (void *)socalp->iblkc);
8042305Sstevel 
8052305Sstevel 	/* initialize the abort mutex */
8062305Sstevel 	mutex_init(&socalp->abort_mtx, NULL, MUTEX_DRIVER,
8072305Sstevel 	    (void *)socalp->iblkc);
8082305Sstevel 
8092305Sstevel 	cv_init(&socalp->board_cv, NULL, CV_DRIVER, NULL);
8102305Sstevel 	DEBUGF(4, (CE_CONT,
811*7656SSherry.Moore@Sun.COM 	    "socal%d: attach: inited imr mutex, board mutex, board cv\n",
812*7656SSherry.Moore@Sun.COM 	    instance));
8132305Sstevel 
8142305Sstevel 	/* init the port mutexes */
8152305Sstevel 	mutex_init(&porta->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
8162305Sstevel 	cv_init(&porta->sp_cv, NULL, CV_DRIVER, NULL);
8172305Sstevel 	mutex_init(&portb->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
8182305Sstevel 	cv_init(&portb->sp_cv, NULL, CV_DRIVER, NULL);
8192305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: inited port mutexes and cvs\n",
820*7656SSherry.Moore@Sun.COM 	    instance));
8212305Sstevel 
8222305Sstevel 	/* get local copy of service params */
8232305Sstevel 	socal_wcopy((uint_t *)socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS,
824*7656SSherry.Moore@Sun.COM 	    (uint_t *)socalp->socal_service_params, SOCAL_SVC_LENGTH);
8252305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: got service params\n", instance));
8262305Sstevel 	/*
8272305Sstevel 	 * Initailize the FCAL transport interface.
8282305Sstevel 	 */
8292305Sstevel 	socal_init_transport_interface(socalp);
8302305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: initalized transport interface\n",
831*7656SSherry.Moore@Sun.COM 	    instance));
8322305Sstevel 
8332305Sstevel 	/*
8342305Sstevel 	 * Allocate request and response queues and init their mutexs.
8352305Sstevel 	 */
8362305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
8372305Sstevel 		if (socal_cqalloc_init(socalp, i) != FCAL_SUCCESS) {
8382305Sstevel 			goto fail;
8392305Sstevel 		}
8402305Sstevel 	}
8412305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: allocated cqs\n", instance));
8422305Sstevel 
8432305Sstevel 	/*
8442305Sstevel 	 * Adjust the burst size we'll use.
8452305Sstevel 	 */
8462305Sstevel 	burstsize = ddi_dma_burstsizes(socalp->request[0].skc_dhandle);
8472305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: burstsize = 0x%x\n",
848*7656SSherry.Moore@Sun.COM 	    instance, burstsize));
8492305Sstevel 	j = burstsize & BURSTSIZE_MASK;
8502305Sstevel 	for (i = 0; socal_burst32_table[i] != SOCAL_CR_BURST_64; i++)
8512305Sstevel 		if (!(j >>= 1)) break;
8522305Sstevel 
8532305Sstevel 	socalp->socal_cfg = (socalp->socal_cfg & ~SOCAL_CR_SBUS_BURST_SIZE_MASK)
854*7656SSherry.Moore@Sun.COM 	    | socal_burst32_table[i];
8552305Sstevel 
8562305Sstevel 	if (socal_64bitsbus) {
857*7656SSherry.Moore@Sun.COM 		if (ddi_dma_set_sbus64(socalp->request[0].skc_dhandle,
858*7656SSherry.Moore@Sun.COM 		    socal_dma_attr.dma_attr_burstsizes | BURST128) ==
859*7656SSherry.Moore@Sun.COM 		    DDI_SUCCESS) {
8602305Sstevel 			DEBUGF(4, (CE_CONT, "socal%d: enabled 64 bit sbus\n",
861*7656SSherry.Moore@Sun.COM 			    instance));
8622305Sstevel 			socalp->socal_cfg |= SOCAL_CR_SBUS_ENHANCED;
8632305Sstevel 			burstsize = ddi_dma_burstsizes(socalp->request[0].
8642305Sstevel 			    skc_dhandle);
8652305Sstevel 		DEBUGF(4, (CE_CONT, "socal%d: attach: 64bit burstsize = 0x%x\n",
8662305Sstevel 		    instance, burstsize));
8672305Sstevel 			j = burstsize & BURSTSIZE_MASK;
8682305Sstevel 			for (i = 0; socal_burst64_table[i] !=
8692305Sstevel 			    (SOCAL_CR_BURST_128 << 8); i++)
8702305Sstevel 				if (!(j >>= 1))
8712305Sstevel 					break;
8722305Sstevel 
8732305Sstevel 			socalp->socal_cfg = (socalp->socal_cfg &
8742305Sstevel 			    ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK) |
8752305Sstevel 			    socal_burst64_table[i];
876*7656SSherry.Moore@Sun.COM 		}
8772305Sstevel 	}
8782305Sstevel 
8792305Sstevel 	ddi_remove_intr(dip, 0, socalp->iblkc);
8802305Sstevel 	socalp->iblkc = (void *)NULL;
8812305Sstevel 	/*
8822305Sstevel 	 * Install the interrupt routine.
8832305Sstevel 	 */
8842305Sstevel 	if (ddi_add_intr(dip,
885*7656SSherry.Moore@Sun.COM 	    (uint_t)0,
886*7656SSherry.Moore@Sun.COM 	    &socalp->iblkc,
887*7656SSherry.Moore@Sun.COM 	    &socalp->idevc,
888*7656SSherry.Moore@Sun.COM 	    socal_intr,
889*7656SSherry.Moore@Sun.COM 	    (caddr_t)socalp) != DDI_SUCCESS) {
890*7656SSherry.Moore@Sun.COM 			socal_disp_err(socalp, CE_WARN, "attach.4060",
8912305Sstevel 			"attach failed: unable to install interrupt handler");
892*7656SSherry.Moore@Sun.COM 			goto fail;
8932305Sstevel 	}
8942305Sstevel 
8952305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: set config reg %x\n",
896*7656SSherry.Moore@Sun.COM 	    instance, socalp->socal_cfg));
8972305Sstevel 
8982305Sstevel 	if (ddi_create_minor_node(dip, SOCAL_PORTA_NAME, S_IFCHR,
899*7656SSherry.Moore@Sun.COM 	    instance*N_SOCAL_NPORTS, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
9002305Sstevel 		goto fail;
9012305Sstevel 	if (ddi_create_minor_node(dip, SOCAL_PORTB_NAME, S_IFCHR,
902*7656SSherry.Moore@Sun.COM 	    instance*N_SOCAL_NPORTS+1, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
9032305Sstevel 		goto fail;
9042305Sstevel 
9052305Sstevel 	if (socal_start(socalp) != FCAL_SUCCESS)
9062305Sstevel 		goto fail;
9072305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: soc+ started\n", instance));
9082305Sstevel 
9092305Sstevel 	ddi_report_dev(dip);
9102305Sstevel 
9112305Sstevel 	DEBUGF(2, (CE_CONT, "socal%d: attach O.K.\n\n", instance));
9122305Sstevel 
9132305Sstevel 	return (DDI_SUCCESS);
9142305Sstevel 
9152305Sstevel fail:
9162305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: attach: DDI_FAILURE\n", instance));
9172305Sstevel 
9182305Sstevel 	/* Make sure soc reset */
9192305Sstevel 	socal_disable(socalp);
9202305Sstevel 
9212305Sstevel 	/* let detach do the dirty work */
9222305Sstevel 	(void) socal_dodetach(dip);
9232305Sstevel 
9242305Sstevel 	return (DDI_FAILURE);
9252305Sstevel }
9262305Sstevel 
9272305Sstevel static int
socal_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)9282305Sstevel socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9292305Sstevel {
9302305Sstevel 	int		resp;
9312305Sstevel 	socal_state_t	*socalp;
9322305Sstevel 	int		i;
9332305Sstevel 
9342305Sstevel 
9352305Sstevel 	switch (cmd) {
9362305Sstevel 
9372305Sstevel 	case DDI_SUSPEND:
9382305Sstevel 		DEBUGF(4, (CE_CONT, "socal: suspend called\n"));
9392305Sstevel 
9402305Sstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
9412305Sstevel 			return (DDI_FAILURE);
9422305Sstevel 
9432305Sstevel 		/*
9442305Sstevel 		 * If any of the ports are in target-mode, don't suspend
9452305Sstevel 		 */
9462305Sstevel 		for (i = 0; i < N_SOCAL_NPORTS; i++) {
9472305Sstevel 			if (socalp->port_state[i].sp_status & PORT_TARGET_MODE)
9482305Sstevel 				return (DDI_FAILURE);
9492305Sstevel 		}
9502305Sstevel 
9512305Sstevel 		/* do not restart socal after reset */
9522305Sstevel 		socal_force_reset((void *)socalp, 0, DONT_RESET_PORT);
9532305Sstevel 
9542305Sstevel 		return (DDI_SUCCESS);
9552305Sstevel 
9562305Sstevel 	case DDI_DETACH:
9572305Sstevel 		DEBUGF(4, (CE_CONT, "socal: detach called\n"));
9582305Sstevel 		resp = socal_dodetach(dip);
9592305Sstevel 		if (resp == DDI_SUCCESS)
9602305Sstevel 			ddi_set_driver_private(dip, NULL);
9612305Sstevel 		return (resp);
9622305Sstevel 
9632305Sstevel 	default:
9642305Sstevel 		return (DDI_FAILURE);
9652305Sstevel 	}
9662305Sstevel }
9672305Sstevel 
9682305Sstevel static int
socal_dodetach(dev_info_t * dip)9692305Sstevel socal_dodetach(dev_info_t *dip)
9702305Sstevel {
9712305Sstevel 
9722305Sstevel 	int		instance = ddi_get_instance(dip);
9732305Sstevel 	int		i;
9742305Sstevel 	socal_state_t	*socalp;
9752305Sstevel 	socal_port_t	*portp;
9762305Sstevel 	socal_unsol_cb_t	*cb, *cbn = NULL;
9772305Sstevel 
9782305Sstevel 	/* Get the soft state struct. */
9792305Sstevel 	if ((socalp = ddi_get_soft_state(socal_soft_state_p, instance)) == 0) {
9802305Sstevel 		return (DDI_FAILURE);
9812305Sstevel 	}
9822305Sstevel 
9832305Sstevel 	/*
9842305Sstevel 	 * If somebody is still attached to us from above fail
9852305Sstevel 	 * detach.
9862305Sstevel 	 */
9872305Sstevel 	mutex_enter(&socalp->board_mtx);
9882305Sstevel 	if (socalp->socal_busy > 0) {
9892305Sstevel 		mutex_exit(&socalp->board_mtx);
9902305Sstevel 		return (DDI_FAILURE);
9912305Sstevel 	}
9922305Sstevel 	/* mark socal_busy = -1 to disallow sftm attach */
9932305Sstevel 	socalp->socal_busy = -1;
9942305Sstevel 	mutex_exit(&socalp->board_mtx);
9952305Sstevel 
9962305Sstevel 	/* Make sure soc+ reset */
9972305Sstevel 	mutex_enter(&socalp->k_imr_mtx);
9982305Sstevel 	socal_disable(socalp);
9992305Sstevel 	mutex_exit(&socalp->k_imr_mtx);
10002305Sstevel 
10012305Sstevel 	/* remove soc+ interrupt */
10022305Sstevel 	if (socalp->iblkc != (void *)NULL) {
10032305Sstevel 		ddi_remove_intr(dip, (uint_t)0, socalp->iblkc);
10042305Sstevel 		DEBUGF(2, (CE_CONT,
1005*7656SSherry.Moore@Sun.COM 		    "socal%d: detach: Removed SOC+ interrupt from ddi\n",
1006*7656SSherry.Moore@Sun.COM 		    instance));
10072305Sstevel 	}
10082305Sstevel 
10092305Sstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
10102305Sstevel 		portp = &socalp->port_state[i];
10112305Sstevel 		mutex_destroy(&portp->sp_mtx);
10122305Sstevel 		cv_destroy(&portp->sp_cv);
10132305Sstevel 		mutex_destroy(&portp->sp_transport->fcal_mtx);
10142305Sstevel 		cv_destroy(&portp->sp_transport->fcal_cv);
10152305Sstevel 		kmem_free((void *)portp->sp_transport,
1016*7656SSherry.Moore@Sun.COM 		    sizeof (fcal_transport_t));
10172305Sstevel 		for (cb = portp->sp_unsol_cb; cb != (socal_unsol_cb_t *)NULL;
1018*7656SSherry.Moore@Sun.COM 		    cb = cbn) {
10192305Sstevel 			cbn = cb->next;
10202305Sstevel 			kmem_free((void *)cb, sizeof (socal_unsol_cb_t));
10212305Sstevel 		}
10222305Sstevel 		portp->sp_unsol_cb = (socal_unsol_cb_t *)NULL;
10232305Sstevel 	}
10242305Sstevel 
10252305Sstevel 	/*
10262305Sstevel 	 * Free request queues, if allocated
10272305Sstevel 	 */
10282305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
10292305Sstevel 		/* Free the queues and destroy their mutexes. */
10302305Sstevel 		mutex_destroy(&socalp->request[i].skc_mtx);
10312305Sstevel 		mutex_destroy(&socalp->response[i].skc_mtx);
10322305Sstevel 		cv_destroy(&socalp->request[i].skc_cv);
10332305Sstevel 		cv_destroy(&socalp->response[i].skc_cv);
10342305Sstevel 
10352305Sstevel 		if (socalp->request[i].skc_dhandle) {
10362305Sstevel 			(void) ddi_dma_unbind_handle(socalp->
10372305Sstevel 			    request[i].skc_dhandle);
10382305Sstevel 			ddi_dma_free_handle(&socalp->request[i].skc_dhandle);
10392305Sstevel 		}
10402305Sstevel 		if (socalp->request[i].skc_cq_raw) {
10412305Sstevel 			ddi_dma_mem_free(&socalp->request[i].skc_acchandle);
10422305Sstevel 			socalp->request[i].skc_cq_raw = NULL;
10432305Sstevel 			socalp->request[i].skc_cq = NULL;
10442305Sstevel 		}
10452305Sstevel 		if (socalp->response[i].skc_dhandle) {
10462305Sstevel 			(void) ddi_dma_unbind_handle(socalp->
10472305Sstevel 			    response[i].skc_dhandle);
10482305Sstevel 			ddi_dma_free_handle(&socalp->response[i].skc_dhandle);
10492305Sstevel 		}
10502305Sstevel 		if (socalp->response[i].skc_cq_raw) {
10512305Sstevel 			ddi_dma_mem_free(&socalp->response[i].skc_acchandle);
10522305Sstevel 			socalp->response[i].skc_cq_raw = NULL;
10532305Sstevel 			socalp->response[i].skc_cq = NULL;
10542305Sstevel 		}
10552305Sstevel 		if (socalp->request[i].deferred_intr_timeoutid) {
10562305Sstevel 			(void) untimeout(socalp->
1057*7656SSherry.Moore@Sun.COM 			    request[i].deferred_intr_timeoutid);
10582305Sstevel 		}
10592305Sstevel 		if (socalp->response[i].deferred_intr_timeoutid) {
10602305Sstevel 			(void) untimeout(socalp->
1061*7656SSherry.Moore@Sun.COM 			    response[i].deferred_intr_timeoutid);
10622305Sstevel 		}
10632305Sstevel 	}
10642305Sstevel 
10652305Sstevel 	mutex_destroy(&socalp->abort_mtx);
10662305Sstevel 	mutex_destroy(&socalp->board_mtx);
10672305Sstevel 	mutex_destroy(&socalp->ioctl_mtx);
10682305Sstevel 	cv_destroy(&socalp->board_cv);
10692305Sstevel 
10702305Sstevel 	/*
10712305Sstevel 	 * Free soc data buffer pool
10722305Sstevel 	 */
10732305Sstevel 	if (socalp->pool_dhandle) {
10742305Sstevel 		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
10752305Sstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
10762305Sstevel 	}
10772305Sstevel 	if (socalp->pool) {
10782305Sstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
10792305Sstevel 	}
10802305Sstevel 
10812305Sstevel 	/* release register maps */
10822305Sstevel 	/* Unmap EEPROM */
10832305Sstevel 	if (socalp->socal_eeprom != NULL) {
10842305Sstevel 		ddi_unmap_regs(dip, 0, &socalp->socal_eeprom, 0, 0);
10852305Sstevel 	}
10862305Sstevel 
10872305Sstevel 	/* Unmap XRAM */
10882305Sstevel 	if (socalp->socal_xrp != NULL) {
10892305Sstevel 		ddi_unmap_regs(dip, 1, &socalp->socal_xrp, 0, 0);
10902305Sstevel 	}
10912305Sstevel 
10922305Sstevel 	/* Unmap registers */
10932305Sstevel 	if (socalp->socal_rp != NULL) {
10942305Sstevel 		ddi_unmap_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0);
10952305Sstevel 	}
10962305Sstevel 
10972305Sstevel 	if (socalp->socal_ksp != NULL)
10982305Sstevel 		kstat_delete(socalp->socal_ksp);
10992305Sstevel 
11002305Sstevel 	mutex_destroy(&socalp->k_imr_mtx);
11012305Sstevel 
11022305Sstevel 	ddi_remove_minor_node(dip, NULL);
11032305Sstevel 
11042305Sstevel 	ddi_soft_state_free(socal_soft_state_p, instance);
11052305Sstevel 
11062305Sstevel 	return (DDI_SUCCESS);
11072305Sstevel }
11082305Sstevel 
11092305Sstevel 
11102305Sstevel int
socal_bus_ctl(dev_info_t * dip,dev_info_t * rip,ddi_ctl_enum_t op,void * a,void * v)11112305Sstevel socal_bus_ctl(dev_info_t *dip, dev_info_t *rip, ddi_ctl_enum_t op,
11122305Sstevel 	void *a, void *v)
11132305Sstevel {
11142305Sstevel 	int		port;
11152305Sstevel 
11162305Sstevel 
11172305Sstevel 	switch (op) {
11182305Sstevel 	case DDI_CTLOPS_REPORTDEV:
11192305Sstevel 		port = ddi_getprop(DDI_DEV_T_ANY, rip, DDI_PROP_DONTPASS,
11202305Sstevel 		    SOCAL_PORT_NO_PROP, -1);
11212305Sstevel 		if ((port < 0) || (port > 1)) {
11222305Sstevel 			port = ddi_getprop(DDI_DEV_T_ANY, rip,
11232305Sstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11242305Sstevel 		}
11252305Sstevel 		/* log text identifying this driver (d) & its child (r) */
11262305Sstevel 		cmn_err(CE_CONT, "?%s%d at %s%d: socal_port %d\n",
11272305Sstevel 		    ddi_driver_name(rip), ddi_get_instance(rip),
11282305Sstevel 		    ddi_driver_name(dip), ddi_get_instance(dip),
11292305Sstevel 		    port);
11302305Sstevel 		break;
11312305Sstevel 
11322305Sstevel 	case DDI_CTLOPS_INITCHILD: {
11332305Sstevel 		dev_info_t	*child_dip = (dev_info_t *)a;
11342305Sstevel 		char		name[MAXNAMELEN];
11352305Sstevel 		socal_state_t	*socalp;
11362305Sstevel 
11372305Sstevel 		if ((socalp = ddi_get_driver_private(dip)) == NULL)
11382305Sstevel 			return (DDI_FAILURE);
11392305Sstevel 
11402305Sstevel 		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1141*7656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
11422305Sstevel 
11432305Sstevel 		if ((port < 0) || (port > 1)) {
11442305Sstevel 			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11452305Sstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11462305Sstevel 			if ((port < 0) || (port > 1)) {
11472305Sstevel 				return (DDI_NOT_WELL_FORMED);
11482305Sstevel 			}
11492305Sstevel 		}
11502305Sstevel 		mutex_enter(&socalp->board_mtx);
11512305Sstevel 		mutex_enter(&socalp->port_state[port].sp_mtx);
11522305Sstevel 		if (socalp->port_state[port].sp_status &
11532305Sstevel 		    (PORT_CHILD_INIT | PORT_TARGET_MODE)) {
11542305Sstevel 			mutex_exit(&socalp->port_state[port].sp_mtx);
11552305Sstevel 			mutex_exit(&socalp->board_mtx);
11562305Sstevel 			return (DDI_FAILURE);
11572305Sstevel 		}
11582305Sstevel 		socalp->socal_busy++;
11592305Sstevel 		socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
11602305Sstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
11612305Sstevel 		mutex_exit(&socalp->board_mtx);
11622305Sstevel 		ddi_set_parent_data(child_dip,
11632305Sstevel 		    socalp->port_state[port].sp_transport);
11642305Sstevel 		(void) sprintf((char *)name, "%x,0", port);
11652305Sstevel 		ddi_set_name_addr(child_dip, name);
11662305Sstevel 		break;
11672305Sstevel 	}
11682305Sstevel 
11692305Sstevel 	case DDI_CTLOPS_UNINITCHILD: {
11702305Sstevel 		dev_info_t	*child_dip = (dev_info_t *)a;
11712305Sstevel 		socal_state_t	*socalp;
11722305Sstevel 
11732305Sstevel 		socalp = ddi_get_driver_private(dip);
11742305Sstevel 		port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1175*7656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
11762305Sstevel 
11772305Sstevel 		if ((port < 0) || (port > 1)) {
11782305Sstevel 			port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
11792305Sstevel 			    DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
11802305Sstevel 			if ((port < 0) || (port > 1)) {
11812305Sstevel 				return (DDI_NOT_WELL_FORMED);
11822305Sstevel 			}
11832305Sstevel 		}
11842305Sstevel 
11852305Sstevel 		ddi_set_parent_data(child_dip, NULL);
11862305Sstevel 		(void) ddi_set_name_addr(child_dip, NULL);
11872305Sstevel 		mutex_enter(&socalp->board_mtx);
11882305Sstevel 		mutex_enter(&socalp->port_state[port].sp_mtx);
11892305Sstevel 		socalp->socal_busy--;
11902305Sstevel 		socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
11912305Sstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
11922305Sstevel 		mutex_exit(&socalp->board_mtx);
11932305Sstevel 
11942305Sstevel 		break;
11952305Sstevel 	}
11962305Sstevel 
11972305Sstevel 	case DDI_CTLOPS_IOMIN: {
11982305Sstevel 		int val;
11992305Sstevel 
12002305Sstevel 		val = *((int *)v);
12012305Sstevel 		val = maxbit(val, socallim->dlim_minxfer);
12022305Sstevel 		/*
12032305Sstevel 		 * The 'arg' value of nonzero indicates 'streaming' mode.
12042305Sstevel 		 * If in streaming mode, pick the largest of our burstsizes
12052305Sstevel 		 * available and say that that is our minimum value (modulo
12062305Sstevel 		 * what minxfer is).
12072305Sstevel 		 */
12082305Sstevel 		if ((int)(uintptr_t)a) {
12092305Sstevel 			val = maxbit(val,
12102305Sstevel 			    1<<(ddi_fls(socallim->dlim_burstsizes)-1));
12112305Sstevel 		} else {
12122305Sstevel 			val = maxbit(val,
12132305Sstevel 			    1<<(ddi_ffs(socallim->dlim_burstsizes)-1));
12142305Sstevel 		}
12152305Sstevel 
12162305Sstevel 		*((int *)v) = val;
12172305Sstevel 		return (ddi_ctlops(dip, rip, op, a, v));
12182305Sstevel 	}
12192305Sstevel 
12202305Sstevel 	/*
12212305Sstevel 	 * These ops are not available on this nexus.
12222305Sstevel 	 */
12232305Sstevel 
12242305Sstevel 	case DDI_CTLOPS_DMAPMAPC:
12252305Sstevel 	case DDI_CTLOPS_REGSIZE:
12262305Sstevel 	case DDI_CTLOPS_NREGS:
12272305Sstevel 	case DDI_CTLOPS_AFFINITY:
12282305Sstevel 	case DDI_CTLOPS_SIDDEV:
12292305Sstevel 	case DDI_CTLOPS_POKE:
12302305Sstevel 	case DDI_CTLOPS_PEEK:
12312305Sstevel 		return (DDI_FAILURE);
12322305Sstevel 
12332305Sstevel 	case DDI_CTLOPS_SLAVEONLY:
12342305Sstevel 	case DDI_CTLOPS_REPORTINT:
12352305Sstevel 	default:
12362305Sstevel 		/*
12372305Sstevel 		 * Remaining requests get passed up to our parent
12382305Sstevel 		 */
12392305Sstevel 		DEBUGF(2, (CE_CONT, "%s%d: op (%d) from %s%d\n",
1240*7656SSherry.Moore@Sun.COM 		    ddi_get_name(dip), ddi_get_instance(dip),
1241*7656SSherry.Moore@Sun.COM 		    op, ddi_get_name(rip), ddi_get_instance(rip)));
12422305Sstevel 		return (ddi_ctlops(dip, rip, op, a, v));
12432305Sstevel 	}
12442305Sstevel 
12452305Sstevel 	return (DDI_SUCCESS);
12462305Sstevel }
12472305Sstevel 
12482305Sstevel 
12492305Sstevel /*ARGSUSED*/
12502305Sstevel /*
12512305Sstevel  * int
12522305Sstevel  * socal_getinfo() - Given the device number, return the devinfo
12532305Sstevel  * 	pointer or the instance number.  Note: this routine must be
12542305Sstevel  * 	successful on DDI_INFO_DEVT2INSTANCE even before attach.
12552305Sstevel  */
12562305Sstevel int
socal_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)12572305Sstevel socal_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
12582305Sstevel 	void **result)
12592305Sstevel {
12602305Sstevel 	int instance;
12612305Sstevel 	socal_state_t *socalp;
12622305Sstevel 
12632305Sstevel 	instance = getminor((dev_t)arg) / 2;
12642305Sstevel 
12652305Sstevel 	switch (cmd) {
12662305Sstevel 	case DDI_INFO_DEVT2DEVINFO:
12672305Sstevel 		socalp = ddi_get_soft_state(socal_soft_state_p, instance);
12682305Sstevel 		if (socalp)
12692305Sstevel 			*result = socalp->dip;
12702305Sstevel 		else
12712305Sstevel 			*result = NULL;
12722305Sstevel 		break;
12732305Sstevel 
12742305Sstevel 	case DDI_INFO_DEVT2INSTANCE:
12752305Sstevel 		*result = (void *)(uintptr_t)instance;
12762305Sstevel 		break;
12772305Sstevel 
12782305Sstevel 	default:
12792305Sstevel 		return (DDI_FAILURE);
12802305Sstevel 	}
12812305Sstevel 
12822305Sstevel 	return (DDI_SUCCESS);
12832305Sstevel }
12842305Sstevel 
12852305Sstevel /*ARGSUSED*/
12862305Sstevel int
socal_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)12872305Sstevel socal_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
12882305Sstevel {
12892305Sstevel 	int 	instance = getminor(*devp)/2;
12902305Sstevel 	socal_state_t	*socalp =
1291*7656SSherry.Moore@Sun.COM 	    ddi_get_soft_state(socal_soft_state_p, instance);
12922305Sstevel 	socal_port_t	*port_statep;
12932305Sstevel 	int		port;
12942305Sstevel 
12952305Sstevel 	if (socalp == NULL)
12962305Sstevel 		return (ENXIO);
12972305Sstevel 
12982305Sstevel 	port = getminor(*devp)%2;
12992305Sstevel 	port_statep = &socalp->port_state[port];
13002305Sstevel 
13012305Sstevel 	mutex_enter(&port_statep->sp_mtx);
13022305Sstevel 	port_statep->sp_status |= PORT_OPEN;
13032305Sstevel 	mutex_exit(&port_statep->sp_mtx);
13042305Sstevel 	DEBUGF(2, (CE_CONT,
13052305Sstevel 	    "socal%d: open of port %d\n", instance, port));
13062305Sstevel 	return (0);
13072305Sstevel }
13082305Sstevel 
13092305Sstevel /*ARGSUSED*/
13102305Sstevel int
socal_close(dev_t dev,int flag,int otyp,cred_t * cred_p)13112305Sstevel socal_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
13122305Sstevel {
13132305Sstevel 	int 	instance = getminor(dev)/2;
13142305Sstevel 	socal_state_t	*socalp =
1315*7656SSherry.Moore@Sun.COM 	    ddi_get_soft_state(socal_soft_state_p, instance);
13162305Sstevel 	socal_port_t	*port_statep;
13172305Sstevel 	int		port;
13182305Sstevel 
13192305Sstevel 	port = getminor(dev)%2;
13202305Sstevel 	port_statep = &socalp->port_state[port];
13212305Sstevel 
13222305Sstevel 	mutex_enter(&port_statep->sp_mtx);
13232305Sstevel 	port_statep->sp_status &= ~PORT_OPEN;
13242305Sstevel 	mutex_exit(&port_statep->sp_mtx);
13252305Sstevel 	DEBUGF(2, (CE_CONT,
13262305Sstevel 	    "socal%d: clsoe of port %d\n", instance, port));
13272305Sstevel 	return (0);
13282305Sstevel }
13292305Sstevel 
13302305Sstevel /*ARGSUSED*/
13312305Sstevel int
socal_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)13322305Sstevel socal_ioctl(dev_t dev,
13332305Sstevel     int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
13342305Sstevel {
13352305Sstevel 	int 	instance = getminor(dev)/2;
13362305Sstevel 	socal_state_t	*socalp =
1337*7656SSherry.Moore@Sun.COM 	    ddi_get_soft_state(socal_soft_state_p, instance);
13382305Sstevel 	int		port;
13392305Sstevel 	socal_port_t	*port_statep;
13402305Sstevel 	int 		i;
13412305Sstevel 	uint_t		r;
13422305Sstevel 	int		offset;
13432305Sstevel 	int 		retval = FCAL_SUCCESS;
13442305Sstevel 	la_els_adisc_t		*adisc_pl;
13452305Sstevel 	la_els_rls_reply_t	*rls_pl;
13462305Sstevel 	dev_info_t	*dip;
13472305Sstevel 	char		*buffer, tmp[10];
13482305Sstevel 	struct socal_fm_version ver;
13492305Sstevel #ifdef _MULTI_DATAMODEL
13502305Sstevel 	struct socal_fm_version32 {
13512305Sstevel 		uint_t	fcode_ver_len;
13522305Sstevel 		uint_t	mcode_ver_len;
13532305Sstevel 		uint_t	prom_ver_len;
13542305Sstevel 		caddr32_t	fcode_ver;
13552305Sstevel 		caddr32_t	mcode_ver;
13562305Sstevel 		caddr32_t	prom_ver;
13572305Sstevel 	} ver32;
13582305Sstevel 	uint_t		dm32 = 0;
13592305Sstevel #endif
13602305Sstevel 
13612305Sstevel 	uchar_t		*flb_pl;
13622305Sstevel 	flb_hdr_t	*flb_hdr;
13632305Sstevel 	uint_t		flb_size;
13642305Sstevel 
13652305Sstevel 	if (socalp == NULL)
13662305Sstevel 		return (ENXIO);
13672305Sstevel 
13682305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d ioctl: got command %x\n", instance, cmd));
13692305Sstevel 	port = getminor(dev)%2;
13702305Sstevel 
13712305Sstevel 	switch (cmd) {
1372*7656SSherry.Moore@Sun.COM 	case FCIO_FCODE_MCODE_VERSION:
13732305Sstevel #ifdef _MULTI_DATAMODEL
1374*7656SSherry.Moore@Sun.COM 		switch (ddi_model_convert_from(mode & FMODELS)) {
1375*7656SSherry.Moore@Sun.COM 			case DDI_MODEL_ILP32:
1376*7656SSherry.Moore@Sun.COM 				dm32 = 1;
1377*7656SSherry.Moore@Sun.COM 				if (ddi_copyin((caddr_t)arg,
1378*7656SSherry.Moore@Sun.COM 				    (caddr_t)&ver32, sizeof (ver32),
1379*7656SSherry.Moore@Sun.COM 				    mode) == -1)
13802305Sstevel 					return (EFAULT);
1381*7656SSherry.Moore@Sun.COM 				ver.fcode_ver_len =
1382*7656SSherry.Moore@Sun.COM 				    ver32.fcode_ver_len;
1383*7656SSherry.Moore@Sun.COM 				ver.mcode_ver_len =
1384*7656SSherry.Moore@Sun.COM 				    ver32.mcode_ver_len;
1385*7656SSherry.Moore@Sun.COM 				ver.prom_ver_len =
1386*7656SSherry.Moore@Sun.COM 				    ver32.prom_ver_len;
1387*7656SSherry.Moore@Sun.COM 				ver.fcode_ver =
1388*7656SSherry.Moore@Sun.COM 				    (caddr_t)(uintptr_t)ver32.fcode_ver;
1389*7656SSherry.Moore@Sun.COM 				ver.mcode_ver =
1390*7656SSherry.Moore@Sun.COM 				    (caddr_t)(uintptr_t)ver32.mcode_ver;
1391*7656SSherry.Moore@Sun.COM 				ver.prom_ver =
1392*7656SSherry.Moore@Sun.COM 				    (caddr_t)(uintptr_t)ver32.prom_ver;
1393*7656SSherry.Moore@Sun.COM 				break;
1394*7656SSherry.Moore@Sun.COM 			case DDI_MODEL_NONE:
1395*7656SSherry.Moore@Sun.COM 				if (ddi_copyin((caddr_t)arg,
1396*7656SSherry.Moore@Sun.COM 				    (caddr_t)&ver, sizeof (ver),
13972305Sstevel 				    mode) == -1)
13982305Sstevel 					return (EFAULT);
1399*7656SSherry.Moore@Sun.COM 		}
1400*7656SSherry.Moore@Sun.COM #else /* _MULTI_DATAMODEL */
1401*7656SSherry.Moore@Sun.COM 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ver,
1402*7656SSherry.Moore@Sun.COM 		    sizeof (ver), mode) == -1)
1403*7656SSherry.Moore@Sun.COM 			return (EFAULT);
14042305Sstevel #endif /* _MULTI_DATAMODEL */
1405*7656SSherry.Moore@Sun.COM 		dip = socalp->dip;
1406*7656SSherry.Moore@Sun.COM 		if (ddi_prop_op(DDI_DEV_T_ANY, dip,
1407*7656SSherry.Moore@Sun.COM 		    PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
1408*7656SSherry.Moore@Sun.COM 		    DDI_PROP_CANSLEEP, "version", (caddr_t)&buffer,
1409*7656SSherry.Moore@Sun.COM 		    &i) != DDI_PROP_SUCCESS)
1410*7656SSherry.Moore@Sun.COM 			return (EIO);
1411*7656SSherry.Moore@Sun.COM 		if (i < ver.fcode_ver_len)
1412*7656SSherry.Moore@Sun.COM 			ver.fcode_ver_len = i;
1413*7656SSherry.Moore@Sun.COM 		if (ddi_copyout((caddr_t)buffer,
1414*7656SSherry.Moore@Sun.COM 		    (caddr_t)ver.fcode_ver, ver.fcode_ver_len,
1415*7656SSherry.Moore@Sun.COM 		    mode) == -1) {
1416*7656SSherry.Moore@Sun.COM 			kmem_free((caddr_t)buffer, i);
1417*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1418*7656SSherry.Moore@Sun.COM 		}
1419*7656SSherry.Moore@Sun.COM 		kmem_free((caddr_t)buffer, i);
1420*7656SSherry.Moore@Sun.COM 		if (socalp->socal_eeprom) {
14212305Sstevel 			for (i = 0; i < SOCAL_N_CQS; i++) {
1422*7656SSherry.Moore@Sun.COM 				mutex_enter(
1423*7656SSherry.Moore@Sun.COM 				    &socalp->request[i].skc_mtx);
1424*7656SSherry.Moore@Sun.COM 				mutex_enter(
1425*7656SSherry.Moore@Sun.COM 				    &socalp->response[i].skc_mtx);
14262305Sstevel 			}
1427*7656SSherry.Moore@Sun.COM 			i = socalp->socal_rp->socal_cr.w;
14282305Sstevel 			socalp->socal_rp->socal_cr.w &=
1429*7656SSherry.Moore@Sun.COM 			    ~SOCAL_CR_EEPROM_BANK_MASK;
1430*7656SSherry.Moore@Sun.COM 			socalp->socal_rp->socal_cr.w |= 3 << 16;
1431*7656SSherry.Moore@Sun.COM 			if (ver.prom_ver_len > 10)
1432*7656SSherry.Moore@Sun.COM 				ver.prom_ver_len = 10;
1433*7656SSherry.Moore@Sun.COM 			bcopy((caddr_t)socalp->socal_eeprom + (unsigned)
1434*7656SSherry.Moore@Sun.COM 			    0xfff6, tmp, 10);
1435*7656SSherry.Moore@Sun.COM 			socalp->socal_rp->socal_cr.w  = i;
14362305Sstevel 			for (i = SOCAL_N_CQS-1; i >= 0; i--) {
14372305Sstevel 				mutex_exit(&socalp->request[i].skc_mtx);
1438*7656SSherry.Moore@Sun.COM 				mutex_exit(
1439*7656SSherry.Moore@Sun.COM 				    &socalp->response[i].skc_mtx);
14402305Sstevel 			}
1441*7656SSherry.Moore@Sun.COM 			if (ddi_copyout((caddr_t)tmp,
1442*7656SSherry.Moore@Sun.COM 			    (caddr_t)ver.prom_ver,
1443*7656SSherry.Moore@Sun.COM 			    ver.prom_ver_len, mode) == -1)
1444*7656SSherry.Moore@Sun.COM 				return (EFAULT);
1445*7656SSherry.Moore@Sun.COM 		} else {
1446*7656SSherry.Moore@Sun.COM 			ver.prom_ver_len = 0;
1447*7656SSherry.Moore@Sun.COM 		}
1448*7656SSherry.Moore@Sun.COM 		ver.mcode_ver_len = 0;
1449*7656SSherry.Moore@Sun.COM #ifdef _MULTI_DATAMODEL
1450*7656SSherry.Moore@Sun.COM 		if (dm32) {
1451*7656SSherry.Moore@Sun.COM 			ver32.fcode_ver_len = ver.fcode_ver_len;
1452*7656SSherry.Moore@Sun.COM 			ver32.mcode_ver_len = ver.mcode_ver_len;
1453*7656SSherry.Moore@Sun.COM 			ver32.prom_ver_len = ver.prom_ver_len;
1454*7656SSherry.Moore@Sun.COM 			ver32.fcode_ver = (caddr32_t)(uintptr_t)
1455*7656SSherry.Moore@Sun.COM 			    ver.fcode_ver;
1456*7656SSherry.Moore@Sun.COM 			ver32.mcode_ver = (caddr32_t)(uintptr_t)
1457*7656SSherry.Moore@Sun.COM 			    ver.mcode_ver;
1458*7656SSherry.Moore@Sun.COM 			ver32.prom_ver = (caddr32_t)(uintptr_t)
1459*7656SSherry.Moore@Sun.COM 			    ver.prom_ver;
1460*7656SSherry.Moore@Sun.COM 			if (ddi_copyout((caddr_t)&ver32,
1461*7656SSherry.Moore@Sun.COM 			    (caddr_t)arg, sizeof (ver32),
1462*7656SSherry.Moore@Sun.COM 			    mode) == -1)
1463*7656SSherry.Moore@Sun.COM 				return (EFAULT);
1464*7656SSherry.Moore@Sun.COM 		} else
1465*7656SSherry.Moore@Sun.COM #endif /* _MULTI_DATAMODEL */
1466*7656SSherry.Moore@Sun.COM 		if (ddi_copyout((caddr_t)&ver, (caddr_t)arg,
1467*7656SSherry.Moore@Sun.COM 		    sizeof (struct socal_fm_version), mode) == -1)
14682305Sstevel 			return (EFAULT);
1469*7656SSherry.Moore@Sun.COM 		break;
1470*7656SSherry.Moore@Sun.COM 	case FCIO_LOADUCODE:
1471*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->k_imr_mtx);
1472*7656SSherry.Moore@Sun.COM 		socal_disable(socalp);
1473*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->k_imr_mtx);
1474*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)arg, (caddr_t)socal_ucode, 0x10000)
1475*7656SSherry.Moore@Sun.COM 		    == -1)
1476*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1477*7656SSherry.Moore@Sun.COM 		/* restart socal after resetting */
1478*7656SSherry.Moore@Sun.COM 		(void) socal_force_reset((void *)socalp, 0,
1479*7656SSherry.Moore@Sun.COM 		    RESET_PORT);
1480*7656SSherry.Moore@Sun.COM 		break;
1481*7656SSherry.Moore@Sun.COM 	case FCIO_DUMPXRAM:
1482*7656SSherry.Moore@Sun.COM 		for (i = 0; i < SOCAL_N_CQS; i++) {
1483*7656SSherry.Moore@Sun.COM 			mutex_enter(&socalp->request[i].skc_mtx);
1484*7656SSherry.Moore@Sun.COM 			mutex_enter(&socalp->response[i].skc_mtx);
1485*7656SSherry.Moore@Sun.COM 		}
1486*7656SSherry.Moore@Sun.COM 		for (i = 0; i < 4; i++) {
1487*7656SSherry.Moore@Sun.COM 			offset = arg+(0x10000 * i);
1488*7656SSherry.Moore@Sun.COM 			socalp->socal_rp->socal_cr.w &=
1489*7656SSherry.Moore@Sun.COM 			    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
1490*7656SSherry.Moore@Sun.COM 			socalp->socal_rp->socal_cr.w |= i<<24;
1491*7656SSherry.Moore@Sun.COM 			(void) copyout((caddr_t)socalp->socal_xrp,
1492*7656SSherry.Moore@Sun.COM 			    (caddr_t)(uintptr_t)offset, 0x10000);
1493*7656SSherry.Moore@Sun.COM 		}
1494*7656SSherry.Moore@Sun.COM 		socalp->socal_rp->socal_cr.w &=
1495*7656SSherry.Moore@Sun.COM 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
1496*7656SSherry.Moore@Sun.COM 		for (i = SOCAL_N_CQS-1; i >= 0; i--) {
1497*7656SSherry.Moore@Sun.COM 			mutex_exit(&socalp->request[i].skc_mtx);
1498*7656SSherry.Moore@Sun.COM 			mutex_exit(&socalp->response[i].skc_mtx);
14992305Sstevel 		}
1500*7656SSherry.Moore@Sun.COM 		break;
1501*7656SSherry.Moore@Sun.COM #ifdef DEBUG
1502*7656SSherry.Moore@Sun.COM 	case FCIO_DUMPXRAMBUF:
1503*7656SSherry.Moore@Sun.COM 		(void) copyout((caddr_t)socal_xrambuf, (caddr_t)arg,
1504*7656SSherry.Moore@Sun.COM 		    0x40000);
1505*7656SSherry.Moore@Sun.COM 		break;
1506*7656SSherry.Moore@Sun.COM #endif
1507*7656SSherry.Moore@Sun.COM 	case FCIO_GETMAP:
1508*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1509*7656SSherry.Moore@Sun.COM 		if (socal_getmap(socalp, port, (caddr_t)arg, 0, 0) ==
1510*7656SSherry.Moore@Sun.COM 		    -1)
1511*7656SSherry.Moore@Sun.COM 			retval = FCAL_ALLOC_FAILED;
1512*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1513*7656SSherry.Moore@Sun.COM 		break;
1514*7656SSherry.Moore@Sun.COM 	case FCIO_BYPASS_DEV:
1515*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1516*7656SSherry.Moore@Sun.COM 		retval = socal_bypass_dev((void *)socalp, port, arg);
1517*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1518*7656SSherry.Moore@Sun.COM 		break;
1519*7656SSherry.Moore@Sun.COM 	case FCIO_FORCE_LIP:
1520*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1521*7656SSherry.Moore@Sun.COM 		retval = socal_force_lip((void *)socalp, port, 0,
1522*7656SSherry.Moore@Sun.COM 		    FCAL_FORCE_LIP);
1523*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1524*7656SSherry.Moore@Sun.COM 		break;
1525*7656SSherry.Moore@Sun.COM 	case FCIO_FORCE_OFFLINE:
1526*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1527*7656SSherry.Moore@Sun.COM 		retval = socal_force_offline((void *)socalp, port, 0);
1528*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1529*7656SSherry.Moore@Sun.COM 		break;
1530*7656SSherry.Moore@Sun.COM 	case FCIO_ADISC_ELS:
1531*7656SSherry.Moore@Sun.COM 	{
1532*7656SSherry.Moore@Sun.COM 		if ((adisc_pl =
1533*7656SSherry.Moore@Sun.COM 		    (la_els_adisc_t *)kmem_zalloc(
1534*7656SSherry.Moore@Sun.COM 		    sizeof (la_els_adisc_t),
1535*7656SSherry.Moore@Sun.COM 		    KM_NOSLEEP)) == NULL)
1536*7656SSherry.Moore@Sun.COM 			return (ENOMEM);
1537*7656SSherry.Moore@Sun.COM 
1538*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)arg, (caddr_t)adisc_pl,
1539*7656SSherry.Moore@Sun.COM 		    sizeof (la_els_adisc_t)) == -1) {
1540*7656SSherry.Moore@Sun.COM 			kmem_free((void *)adisc_pl,
1541*7656SSherry.Moore@Sun.COM 			    sizeof (la_els_adisc_t));
15422305Sstevel 			return (EFAULT);
1543*7656SSherry.Moore@Sun.COM 		}
1544*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1545*7656SSherry.Moore@Sun.COM 		retval = socal_issue_adisc(socalp, port,
1546*7656SSherry.Moore@Sun.COM 		    adisc_pl->nport_id,
1547*7656SSherry.Moore@Sun.COM 		    adisc_pl, 0);
1548*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1549*7656SSherry.Moore@Sun.COM 
1550*7656SSherry.Moore@Sun.COM 		if (retval == FCAL_SUCCESS) {
1551*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)adisc_pl, (caddr_t)arg,
1552*7656SSherry.Moore@Sun.COM 		    sizeof (la_els_adisc_t)) == -1) {
1553*7656SSherry.Moore@Sun.COM 			kmem_free((void *)adisc_pl,
1554*7656SSherry.Moore@Sun.COM 			    sizeof (la_els_adisc_t));
1555*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1556*7656SSherry.Moore@Sun.COM 		}
15572305Sstevel 		}
1558*7656SSherry.Moore@Sun.COM 
1559*7656SSherry.Moore@Sun.COM 		kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
1560*7656SSherry.Moore@Sun.COM 		break;
1561*7656SSherry.Moore@Sun.COM 	}
1562*7656SSherry.Moore@Sun.COM 	case FCIO_LINKSTATUS:
1563*7656SSherry.Moore@Sun.COM 	{
1564*7656SSherry.Moore@Sun.COM 		int dest;
1565*7656SSherry.Moore@Sun.COM 		if ((rls_pl =
1566*7656SSherry.Moore@Sun.COM 		    (la_els_rls_reply_t *)
1567*7656SSherry.Moore@Sun.COM 		    kmem_zalloc(sizeof (la_els_rls_reply_t),
1568*7656SSherry.Moore@Sun.COM 		    KM_NOSLEEP)) == NULL)
1569*7656SSherry.Moore@Sun.COM 			return (ENOMEM);
1570*7656SSherry.Moore@Sun.COM 
1571*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)arg, (caddr_t)rls_pl,
1572*7656SSherry.Moore@Sun.COM 		    sizeof (la_els_rls_reply_t)) == -1) {
1573*7656SSherry.Moore@Sun.COM 			kmem_free((void *)rls_pl,
1574*7656SSherry.Moore@Sun.COM 			    sizeof (la_els_rls_reply_t));
1575*7656SSherry.Moore@Sun.COM 		return (EFAULT);
1576*7656SSherry.Moore@Sun.COM 		}
1577*7656SSherry.Moore@Sun.COM 		dest = (rls_pl->mbz[0] << 16) + (rls_pl->mbz[1] << 8) +
1578*7656SSherry.Moore@Sun.COM 		    rls_pl->mbz[2];
1579*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1580*7656SSherry.Moore@Sun.COM 		retval = socal_issue_rls(socalp, port, dest,
1581*7656SSherry.Moore@Sun.COM 		    rls_pl, 0);
1582*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1583*7656SSherry.Moore@Sun.COM 
1584*7656SSherry.Moore@Sun.COM 		if (retval == FCAL_SUCCESS) {
1585*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)rls_pl, (caddr_t)arg,
1586*7656SSherry.Moore@Sun.COM 		    sizeof (la_els_rls_reply_t)) == -1) {
1587*7656SSherry.Moore@Sun.COM 			kmem_free((void *)rls_pl,
1588*7656SSherry.Moore@Sun.COM 			    sizeof (la_els_rls_reply_t));
1589*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1590*7656SSherry.Moore@Sun.COM 		}
1591*7656SSherry.Moore@Sun.COM 		}
1592*7656SSherry.Moore@Sun.COM 		kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
1593*7656SSherry.Moore@Sun.COM 		break;
1594*7656SSherry.Moore@Sun.COM 	}
1595*7656SSherry.Moore@Sun.COM 	case FCIO_LOOPBACK_INTERNAL:
1596*7656SSherry.Moore@Sun.COM 		/*
1597*7656SSherry.Moore@Sun.COM 		 * If userland doesn't provide a location for a return
1598*7656SSherry.Moore@Sun.COM 		 * value the driver will permanently offline the port,
1599*7656SSherry.Moore@Sun.COM 		 * ignoring any checks for devices on the loop.
1600*7656SSherry.Moore@Sun.COM 		 */
1601*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1602*7656SSherry.Moore@Sun.COM 		if (arg == 0) {
16032305Sstevel 			port_statep = &socalp->port_state[port];
16042305Sstevel 			mutex_enter(&port_statep->sp_mtx);
16052305Sstevel 			if (port_statep->sp_status & PORT_DISABLED) {
1606*7656SSherry.Moore@Sun.COM 				/* Already disabled */
16072305Sstevel 				mutex_exit(&port_statep->sp_mtx);
16082305Sstevel 				mutex_exit(&socalp->ioctl_mtx);
1609*7656SSherry.Moore@Sun.COM 				return (EALREADY);
1610*7656SSherry.Moore@Sun.COM 			}
1611*7656SSherry.Moore@Sun.COM 			port_statep->sp_status |= PORT_DISABLED;
1612*7656SSherry.Moore@Sun.COM 			mutex_exit(&port_statep->sp_mtx);
1613*7656SSherry.Moore@Sun.COM 		}
1614*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1615*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_INT_LOOP);
1616*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1617*7656SSherry.Moore@Sun.COM 		if (arg == 0) break;
1618*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1619*7656SSherry.Moore@Sun.COM 		    == -1)
1620*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1621*7656SSherry.Moore@Sun.COM 		break;
1622*7656SSherry.Moore@Sun.COM 	case FCIO_LOOPBACK_MANUAL:
1623*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1624*7656SSherry.Moore@Sun.COM 		port_statep = &socalp->port_state[port];
1625*7656SSherry.Moore@Sun.COM 		mutex_enter(&port_statep->sp_mtx);
1626*7656SSherry.Moore@Sun.COM 		if (port_statep->sp_status & PORT_DISABLED) {
1627*7656SSherry.Moore@Sun.COM 			mutex_exit(&port_statep->sp_mtx);
1628*7656SSherry.Moore@Sun.COM 			mutex_exit(&socalp->ioctl_mtx);
1629*7656SSherry.Moore@Sun.COM 			return (EBUSY);
1630*7656SSherry.Moore@Sun.COM 		}
1631*7656SSherry.Moore@Sun.COM 		mutex_exit(&port_statep->sp_mtx);
1632*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1633*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_EXT_LOOP);
1634*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1635*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1636*7656SSherry.Moore@Sun.COM 		    == -1)
1637*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1638*7656SSherry.Moore@Sun.COM 		break;
1639*7656SSherry.Moore@Sun.COM 	case FCIO_NO_LOOPBACK:
1640*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1641*7656SSherry.Moore@Sun.COM 		port_statep = &socalp->port_state[port];
1642*7656SSherry.Moore@Sun.COM 		mutex_enter(&port_statep->sp_mtx);
1643*7656SSherry.Moore@Sun.COM 		/* Do not allow online if we're disabled */
1644*7656SSherry.Moore@Sun.COM 		if (port_statep->sp_status & PORT_DISABLED) {
1645*7656SSherry.Moore@Sun.COM 			if (arg != 0) {
1646*7656SSherry.Moore@Sun.COM 				mutex_exit(&port_statep->sp_mtx);
1647*7656SSherry.Moore@Sun.COM 				mutex_exit(&socalp->ioctl_mtx);
1648*7656SSherry.Moore@Sun.COM 				/*
1649*7656SSherry.Moore@Sun.COM 				 * It's permanently disabled -- Need to
1650*7656SSherry.Moore@Sun.COM 				 * enable it first
1651*7656SSherry.Moore@Sun.COM 				 */
16522305Sstevel 				return (EBUSY);
16532305Sstevel 			}
1654*7656SSherry.Moore@Sun.COM 			/* This was a request to online. */
1655*7656SSherry.Moore@Sun.COM 			port_statep->sp_status &= ~PORT_DISABLED;
1656*7656SSherry.Moore@Sun.COM 		}
1657*7656SSherry.Moore@Sun.COM 		mutex_exit(&port_statep->sp_mtx);
1658*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1659*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_REM_LOOP);
1660*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1661*7656SSherry.Moore@Sun.COM 		if (arg == 0) break;
1662*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1663*7656SSherry.Moore@Sun.COM 		    == -1)
1664*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1665*7656SSherry.Moore@Sun.COM 		break;
1666*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_NOP:
1667*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1668*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1669*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_NOP);
1670*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1671*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1672*7656SSherry.Moore@Sun.COM 		    == -1)
1673*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1674*7656SSherry.Moore@Sun.COM 		break;
1675*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_XRAM:
1676*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1677*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1678*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_XRAM_TEST);
1679*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1680*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1681*7656SSherry.Moore@Sun.COM 		    == -1)
1682*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1683*7656SSherry.Moore@Sun.COM 		break;
1684*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_SOC:
1685*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1686*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1687*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_SOC_TEST);
1688*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1689*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1690*7656SSherry.Moore@Sun.COM 		    == -1)
1691*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1692*7656SSherry.Moore@Sun.COM 		break;
1693*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_HCB:
1694*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1695*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1696*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_HCB_TEST);
1697*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1698*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1699*7656SSherry.Moore@Sun.COM 		    == -1)
1700*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1701*7656SSherry.Moore@Sun.COM 		break;
1702*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_SOCLB:
1703*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1704*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1705*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_SOCLB_TEST);
1706*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1707*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1708*7656SSherry.Moore@Sun.COM 		    == -1)
1709*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1710*7656SSherry.Moore@Sun.COM 		break;
1711*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_SRDSLB:
1712*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1713*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1714*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_SRDSLB_TEST);
1715*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1716*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1717*7656SSherry.Moore@Sun.COM 		    == -1)
1718*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1719*7656SSherry.Moore@Sun.COM 		break;
1720*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_EXTLB:
1721*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1722*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1723*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_EXTOE_TEST);
1724*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1725*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1726*7656SSherry.Moore@Sun.COM 		    == -1)
1727*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1728*7656SSherry.Moore@Sun.COM 		break;
1729*7656SSherry.Moore@Sun.COM 	case FCIO_DIAG_RAW:
1730*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)arg, (caddr_t)&i, sizeof (uint_t))
1731*7656SSherry.Moore@Sun.COM 		    == -1)
1732*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1733*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1734*7656SSherry.Moore@Sun.COM 		retval = socal_diag_request((void *)socalp, port, &r,
1735*7656SSherry.Moore@Sun.COM 		    (uint_t)i);
1736*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1737*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1738*7656SSherry.Moore@Sun.COM 		    == -1)
1739*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1740*7656SSherry.Moore@Sun.COM 		break;
1741*7656SSherry.Moore@Sun.COM 	case FCIO_LOOPBACK_FRAME:
1742*7656SSherry.Moore@Sun.COM 		if ((flb_hdr = (flb_hdr_t *)kmem_zalloc(sizeof (flb_hdr_t),
1743*7656SSherry.Moore@Sun.COM 		    KM_NOSLEEP)) == NULL)
1744*7656SSherry.Moore@Sun.COM 			return (ENOMEM);
1745*7656SSherry.Moore@Sun.COM 
1746*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)arg,
1747*7656SSherry.Moore@Sun.COM 		    (caddr_t)flb_hdr, sizeof (flb_hdr_t)) == -1) {
1748*7656SSherry.Moore@Sun.COM 		kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1749*7656SSherry.Moore@Sun.COM 		return (EFAULT);
1750*7656SSherry.Moore@Sun.COM 		}
1751*7656SSherry.Moore@Sun.COM 
1752*7656SSherry.Moore@Sun.COM 		flb_size = flb_hdr->length;
1753*7656SSherry.Moore@Sun.COM 
1754*7656SSherry.Moore@Sun.COM 		if ((flb_pl =
1755*7656SSherry.Moore@Sun.COM 		    (uchar_t *)kmem_zalloc(flb_size, KM_NOSLEEP)) == NULL)
1756*7656SSherry.Moore@Sun.COM 			return (ENOMEM);
1757*7656SSherry.Moore@Sun.COM 
1758*7656SSherry.Moore@Sun.COM 		if (copyin((caddr_t)(arg + sizeof (flb_hdr_t)),
1759*7656SSherry.Moore@Sun.COM 		    (caddr_t)flb_pl, flb_size) == -1) {
1760*7656SSherry.Moore@Sun.COM 			kmem_free((void *)flb_pl, flb_size);
1761*7656SSherry.Moore@Sun.COM 			return (EFAULT);
1762*7656SSherry.Moore@Sun.COM 		}
1763*7656SSherry.Moore@Sun.COM 		mutex_enter(&socalp->ioctl_mtx);
1764*7656SSherry.Moore@Sun.COM 		retval = socal_issue_lbf(socalp, port, flb_pl,
1765*7656SSherry.Moore@Sun.COM 		    flb_size, 1);
1766*7656SSherry.Moore@Sun.COM 		mutex_exit(&socalp->ioctl_mtx);
1767*7656SSherry.Moore@Sun.COM 
1768*7656SSherry.Moore@Sun.COM 		if (retval == FCAL_SUCCESS) {
1769*7656SSherry.Moore@Sun.COM 		if (copyout((caddr_t)flb_pl,
1770*7656SSherry.Moore@Sun.COM 		    (caddr_t)(arg + sizeof (flb_hdr_t) +
1771*7656SSherry.Moore@Sun.COM 		    flb_hdr->max_length), flb_size) == -1) {
1772*7656SSherry.Moore@Sun.COM 			kmem_free((void *)flb_pl, flb_size);
17732305Sstevel 			kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
17742305Sstevel 			return (EFAULT);
1775*7656SSherry.Moore@Sun.COM 		}
1776*7656SSherry.Moore@Sun.COM 		}
1777*7656SSherry.Moore@Sun.COM 
1778*7656SSherry.Moore@Sun.COM 		kmem_free((void *)flb_pl, flb_size);
1779*7656SSherry.Moore@Sun.COM 		kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1780*7656SSherry.Moore@Sun.COM 		break;
1781*7656SSherry.Moore@Sun.COM 	default:
1782*7656SSherry.Moore@Sun.COM 		return (ENOTTY);
17832305Sstevel 
17842305Sstevel 	}
17852305Sstevel 	switch (retval) {
17862305Sstevel 		case FCAL_SUCCESS:
17872305Sstevel 			return (0);
17882305Sstevel 		case FCAL_ALLOC_FAILED:
17892305Sstevel 			return (ENOMEM);
17902305Sstevel 		case FCAL_STATUS_DIAG_BUSY:
17912305Sstevel 			return (EALREADY);
17922305Sstevel 		case FCAL_STATUS_DIAG_INVALID:
17932305Sstevel 			return (EINVAL);
17942305Sstevel 		default:
17952305Sstevel 			return (EIO);
17962305Sstevel 	}
17972305Sstevel 
17982305Sstevel }
17992305Sstevel 
18002305Sstevel /*
18012305Sstevel  * Function name : socal_disable()
18022305Sstevel  *
18032305Sstevel  * Return Values :  none
18042305Sstevel  *
18052305Sstevel  * Description	 : Reset the soc+
18062305Sstevel  *
18072305Sstevel  * Context	 : Can be called from different kernel process threads.
18082305Sstevel  *		   Can be called by interrupt thread.
18092305Sstevel  *
18102305Sstevel  * Note:  before calling this, the interface should be locked down
18112305Sstevel  * so that it is guaranteed that no other threads are accessing
18122305Sstevel  * the hardware.
18132305Sstevel  */
18142305Sstevel static	void
socal_disable(socal_state_t * socalp)18152305Sstevel socal_disable(socal_state_t *socalp)
18162305Sstevel {
18172305Sstevel #if !defined(lint)
18182305Sstevel 	int i;
18192305Sstevel #endif
18202305Sstevel 	/* Don't touch the hardware if the registers aren't mapped */
18212305Sstevel 	if (!socalp->socal_rp)
18222305Sstevel 		return;
18232305Sstevel 
18242305Sstevel 	socalp->socal_rp->socal_imr = socalp->socal_k_imr = 0;
18252305Sstevel 	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOFT_RESET;
18262305Sstevel #if !defined(lint)
18272305Sstevel 	i = socalp->socal_rp->socal_csr.w;
18282305Sstevel #endif
18292305Sstevel 	DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
18302305Sstevel }
18312305Sstevel 
18322305Sstevel /*
18332305Sstevel  * Function name : socal_init_transport_interface()
18342305Sstevel  *
18352305Sstevel  * Return Values :  none
18362305Sstevel  *
18372305Sstevel  * Description	 : Fill up the fcal_tranpsort struct for ULPs
18382305Sstevel  *
18392305Sstevel  *
18402305Sstevel  * Note:  Only called during attach, so no protection
18412305Sstevel  */
18422305Sstevel static void
socal_init_transport_interface(socal_state_t * socalp)18432305Sstevel socal_init_transport_interface(socal_state_t *socalp)
18442305Sstevel {
18452305Sstevel 	int			i;
18462305Sstevel 	fcal_transport_t	*xport;
18472305Sstevel 
18482305Sstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
18492305Sstevel 		xport = socalp->port_state[i].sp_transport;
18502305Sstevel 		mutex_init(&xport->fcal_mtx, NULL, MUTEX_DRIVER,
1851*7656SSherry.Moore@Sun.COM 		    (void *)(socalp->iblkc));
18522305Sstevel 
18532305Sstevel 		cv_init(&xport->fcal_cv, NULL, CV_DRIVER, NULL);
18542305Sstevel 
18552305Sstevel 		xport->fcal_handle = (void *)socalp;
18562305Sstevel 		xport->fcal_dmalimp = socallim;
18572305Sstevel 		xport->fcal_iblock = socalp->iblkc;
18582305Sstevel 		xport->fcal_dmaattr = &socal_dma_attr;
18592305Sstevel 		xport->fcal_accattr = &socal_acc_attr;
18602305Sstevel 		xport->fcal_loginparms = socalp->socal_service_params;
18612305Sstevel 		bcopy((caddr_t)&socalp->socal_n_wwn,
1862*7656SSherry.Moore@Sun.COM 		    (caddr_t)&xport->fcal_n_wwn, sizeof (la_wwn_t));
18632305Sstevel 		bcopy((caddr_t)&socalp->port_state[i].sp_p_wwn,
1864*7656SSherry.Moore@Sun.COM 		    (caddr_t)&xport->fcal_p_wwn, sizeof (la_wwn_t));
18652305Sstevel 		xport->fcal_portno = i;
18662305Sstevel 		xport->fcal_cmdmax = SOCAL_MAX_XCHG;
18672305Sstevel 		xport->fcal_ops = &socal_transport_ops;
18682305Sstevel 	}
18692305Sstevel }
18702305Sstevel 
18712305Sstevel /*
18722305Sstevel  * static int
18732305Sstevel  * socal_cqalloc_init() - Inialize the circular queue tables.
18742305Sstevel  *	Also, init the locks that are associated with the tables.
18752305Sstevel  *
18762305Sstevel  *	Returns:	FCAL_SUCCESS, if able to init properly.
18772305Sstevel  *			FCAL_FAILURE, if unable to init properly.
18782305Sstevel  */
18792305Sstevel 
18802305Sstevel static int
socal_cqalloc_init(socal_state_t * socalp,uint32_t index)18812305Sstevel socal_cqalloc_init(socal_state_t *socalp, uint32_t index)
18822305Sstevel {
18832305Sstevel 	uint32_t cq_size;
18842305Sstevel 	size_t real_len;
18852305Sstevel 	uint_t ccount;
18862305Sstevel 	socal_kcq_t *cqp;
18872305Sstevel 	int	req_bound = 0, rsp_bound = 0;
18882305Sstevel 
18892305Sstevel 	/*
18902305Sstevel 	 * Initialize the Request and Response Queue locks.
18912305Sstevel 	 */
18922305Sstevel 
18932305Sstevel 	mutex_init(&socalp->request[index].skc_mtx, NULL, MUTEX_DRIVER,
18942305Sstevel 	    (void *)socalp->iblkc);
18952305Sstevel 	mutex_init(&socalp->response[index].skc_mtx, NULL, MUTEX_DRIVER,
18962305Sstevel 	    (void *)socalp->iblkc);
18972305Sstevel 	cv_init(&socalp->request[index].skc_cv, NULL, CV_DRIVER, NULL);
18982305Sstevel 	cv_init(&socalp->response[index].skc_cv, NULL, CV_DRIVER, NULL);
18992305Sstevel 
19002305Sstevel 	/* Allocate DVMA resources for the Request Queue. */
19012305Sstevel 	cq_size = socal_req_entries[index] * sizeof (cqe_t);
19022305Sstevel 	if (cq_size) {
19032305Sstevel 		cqp = &socalp->request[index];
19042305Sstevel 
19052305Sstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
19062305Sstevel 		    DDI_DMA_DONTWAIT, NULL,
19072305Sstevel 		    &cqp->skc_dhandle) != DDI_SUCCESS) {
19082305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4020",
19092305Sstevel 			    "!alloc of dma handle failed");
19102305Sstevel 			goto fail;
19112305Sstevel 		}
19122305Sstevel 
19132305Sstevel 		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
19142305Sstevel 		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
19152305Sstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
19162305Sstevel 		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
19172305Sstevel 		    &cqp->skc_acchandle) != DDI_SUCCESS) {
19182305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4030",
19192305Sstevel 			    "!alloc of dma space failed");
1920*7656SSherry.Moore@Sun.COM 				goto fail;
19212305Sstevel 		}
19222305Sstevel 
19232305Sstevel 		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
19242305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4035",
19252305Sstevel 			    "!alloc of dma space failed");
19262305Sstevel 			goto fail;
19272305Sstevel 		}
19282305Sstevel 		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
1929*7656SSherry.Moore@Sun.COM 		    (uintptr_t)SOCAL_CQ_ALIGN - 1) &
1930*7656SSherry.Moore@Sun.COM 		    ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
19312305Sstevel 
19322305Sstevel 		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
19332305Sstevel 		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
19342305Sstevel 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
19352305Sstevel 		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
19362305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4040",
19372305Sstevel 			    "!bind of dma handle failed");
19382305Sstevel 			goto fail;
19392305Sstevel 		}
19402305Sstevel 
19412305Sstevel 		req_bound = 1;
19422305Sstevel 		if (ccount != 1) {
19432305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4045",
19442305Sstevel 			    "!bind of dma handle failed");
19452305Sstevel 			goto fail;
19462305Sstevel 		}
19472305Sstevel 
19482305Sstevel 	} else {
19492305Sstevel 		socalp->request[index].skc_cq_raw = NULL;
19502305Sstevel 		socalp->request[index].skc_cq = (cqe_t *)NULL;
19512305Sstevel 		socalp->request[index].skc_dhandle = 0;
19522305Sstevel 	}
19532305Sstevel 
19542305Sstevel 	/* Allocate DVMA resources for the response Queue. */
19552305Sstevel 	cq_size = socal_rsp_entries[index] * sizeof (cqe_t);
19562305Sstevel 	if (cq_size) {
19572305Sstevel 		cqp = &socalp->response[index];
19582305Sstevel 
19592305Sstevel 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
19602305Sstevel 		    DDI_DMA_DONTWAIT, NULL,
19612305Sstevel 		    &cqp->skc_dhandle) != DDI_SUCCESS) {
19622305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4050",
19632305Sstevel 			    "!alloc of dma handle failed");
19642305Sstevel 			goto fail;
19652305Sstevel 		}
19662305Sstevel 
19672305Sstevel 		if (ddi_dma_mem_alloc(cqp->skc_dhandle,
19682305Sstevel 		    cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
19692305Sstevel 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
19702305Sstevel 		    (caddr_t *)&cqp->skc_cq_raw, &real_len,
19712305Sstevel 		    &cqp->skc_acchandle) != DDI_SUCCESS) {
19722305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4060",
19732305Sstevel 			    "!alloc of dma space failed");
1974*7656SSherry.Moore@Sun.COM 				goto fail;
19752305Sstevel 		}
19762305Sstevel 
19772305Sstevel 		if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
19782305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4065",
19792305Sstevel 			    "!alloc of dma space failed");
19802305Sstevel 			goto fail;
19812305Sstevel 		}
19822305Sstevel 
19832305Sstevel 		cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
1984*7656SSherry.Moore@Sun.COM 		    (uintptr_t)SOCAL_CQ_ALIGN - 1) &
1985*7656SSherry.Moore@Sun.COM 		    ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
19862305Sstevel 
19872305Sstevel 		if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
19882305Sstevel 		    (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
19892305Sstevel 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
19902305Sstevel 		    NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
19912305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4070",
19922305Sstevel 			    "!bind of dma handle failed");
19932305Sstevel 			goto fail;
19942305Sstevel 		}
19952305Sstevel 
19962305Sstevel 		rsp_bound = 1;
19972305Sstevel 		if (ccount != 1) {
19982305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4075",
19992305Sstevel 			    "!bind of dma handle failed");
20002305Sstevel 			goto fail;
20012305Sstevel 		}
20022305Sstevel 
20032305Sstevel 	} else {
20042305Sstevel 		socalp->response[index].skc_cq_raw = NULL;
20052305Sstevel 		socalp->response[index].skc_cq = (cqe_t *)NULL;
20062305Sstevel 		socalp->response[index].skc_dhandle = 0;
20072305Sstevel 	}
20082305Sstevel 
20092305Sstevel 	/*
20102305Sstevel 	 * Initialize the queue pointers
20112305Sstevel 	 */
20122305Sstevel 	socal_cqinit(socalp, index);
20132305Sstevel 
20142305Sstevel 	return (FCAL_SUCCESS);
20152305Sstevel fail:
20162305Sstevel 	if (socalp->request[index].skc_dhandle) {
20172305Sstevel 		if (req_bound)
20182305Sstevel 			(void) ddi_dma_unbind_handle(socalp->
20192305Sstevel 			    request[index].skc_dhandle);
20202305Sstevel 		ddi_dma_free_handle(&socalp->request[index].skc_dhandle);
20212305Sstevel 	}
20222305Sstevel 	if (socalp->request[index].skc_cq_raw)
20232305Sstevel 		ddi_dma_mem_free(&socalp->request[index].skc_acchandle);
20242305Sstevel 
20252305Sstevel 	if (socalp->response[index].skc_dhandle) {
20262305Sstevel 		if (rsp_bound)
20272305Sstevel 			(void) ddi_dma_unbind_handle(socalp->
20282305Sstevel 			    response[index].skc_dhandle);
20292305Sstevel 		ddi_dma_free_handle(&socalp->response[index].skc_dhandle);
20302305Sstevel 	}
20312305Sstevel 	if (socalp->response[index].skc_cq_raw)
20322305Sstevel 		ddi_dma_mem_free(&socalp->response[index].skc_acchandle);
20332305Sstevel 
20342305Sstevel 	socalp->request[index].skc_dhandle = NULL;
20352305Sstevel 	socalp->response[index].skc_dhandle = NULL;
20362305Sstevel 	socalp->request[index].skc_cq_raw = NULL;
20372305Sstevel 	socalp->request[index].skc_cq = NULL;
20382305Sstevel 	socalp->response[index].skc_cq_raw = NULL;
20392305Sstevel 	socalp->response[index].skc_cq = NULL;
20402305Sstevel 	mutex_destroy(&socalp->request[index].skc_mtx);
20412305Sstevel 	mutex_destroy(&socalp->response[index].skc_mtx);
20422305Sstevel 	cv_destroy(&socalp->request[index].skc_cv);
20432305Sstevel 	cv_destroy(&socalp->response[index].skc_cv);
20442305Sstevel 	return (FCAL_FAILURE);
20452305Sstevel 
20462305Sstevel }
20472305Sstevel 
20482305Sstevel /*
20492305Sstevel  * socal_cqinit() - initializes the driver's circular queue pointers, etc.
20502305Sstevel  */
20512305Sstevel 
20522305Sstevel static void
socal_cqinit(socal_state_t * socalp,uint32_t index)20532305Sstevel socal_cqinit(socal_state_t *socalp, uint32_t index)
20542305Sstevel {
20552305Sstevel 	socal_kcq_t *kcq_req = &socalp->request[index];
20562305Sstevel 	socal_kcq_t *kcq_rsp = &socalp->response[index];
20572305Sstevel 
20582305Sstevel 	/*
20592305Sstevel 	 * Initialize the Request and Response Queue pointers
20602305Sstevel 	 */
20612305Sstevel 	kcq_req->skc_seqno = 1;
20622305Sstevel 	kcq_rsp->skc_seqno = 1;
20632305Sstevel 	kcq_req->skc_in = 0;
20642305Sstevel 	kcq_rsp->skc_in = 0;
20652305Sstevel 	kcq_req->skc_out = 0;
20662305Sstevel 	kcq_rsp->skc_out = 0;
20672305Sstevel 	kcq_req->skc_last_index = socal_req_entries[index] - 1;
20682305Sstevel 	kcq_rsp->skc_last_index = socal_rsp_entries[index] - 1;
20692305Sstevel 	kcq_req->skc_full = 0;
20702305Sstevel 	kcq_rsp->deferred_intr_timeoutid = 0;
20712305Sstevel 	kcq_req->skc_socalp = socalp;
20722305Sstevel 	kcq_rsp->skc_socalp = socalp;
20732305Sstevel 
20742305Sstevel 	kcq_req->skc_xram_cqdesc =
2075*7656SSherry.Moore@Sun.COM 	    (socalp->xram_reqp + (index * sizeof (struct cq))/8);
20762305Sstevel 	kcq_rsp->skc_xram_cqdesc =
2077*7656SSherry.Moore@Sun.COM 	    (socalp->xram_rspp + (index * sizeof (struct cq))/8);
20782305Sstevel 
20792305Sstevel 	/*  Clear out memory we have allocated */
20802305Sstevel 	if (kcq_req->skc_cq != NULL)
20812305Sstevel 		bzero((caddr_t)kcq_req->skc_cq,
20822305Sstevel 		    socal_req_entries[index] * sizeof (cqe_t));
20832305Sstevel 	if (kcq_rsp->skc_cq != NULL)
20842305Sstevel 		bzero((caddr_t)kcq_rsp->skc_cq,
20852305Sstevel 		    socal_rsp_entries[index] * sizeof (cqe_t));
20862305Sstevel }
20872305Sstevel 
20882305Sstevel 
20892305Sstevel static int
socal_start(socal_state_t * socalp)20902305Sstevel socal_start(socal_state_t *socalp)
20912305Sstevel {
20922305Sstevel 	uint_t r;
20932305Sstevel 
20942305Sstevel 	if (!socalp)
20952305Sstevel 		return (FCAL_FAILURE);
20962305Sstevel 
20972305Sstevel 	socal_download_ucode(socalp);
20982305Sstevel 	socal_init_cq_desc(socalp);
20992305Sstevel 	socal_init_wwn(socalp);
21002305Sstevel 
21012305Sstevel 	mutex_enter(&socalp->port_state[0].sp_mtx);
21022305Sstevel 	socalp->port_state[0].sp_status
2103*7656SSherry.Moore@Sun.COM 	    &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
21042305Sstevel 	socalp->port_state[0].sp_status |= PORT_OFFLINE;
21052305Sstevel 	mutex_exit(&socalp->port_state[0].sp_mtx);
21062305Sstevel 
21072305Sstevel 	mutex_enter(&socalp->port_state[1].sp_mtx);
21082305Sstevel 	socalp->port_state[1].sp_status
2109*7656SSherry.Moore@Sun.COM 	    &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
21102305Sstevel 	socalp->port_state[1].sp_status |= PORT_OFFLINE;
21112305Sstevel 	mutex_exit(&socalp->port_state[1].sp_mtx);
21122305Sstevel 
21132305Sstevel 	socal_enable(socalp);
21142305Sstevel 	/* Make sure disabled ports stay disabled. */
21152305Sstevel 	if (socalp->port_state[0].sp_status & PORT_DISABLED)
21162305Sstevel 		(void) socal_diag_request((void *)socalp, 0, &r,
2117*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_INT_LOOP);
21182305Sstevel 	if (socalp->port_state[1].sp_status & PORT_DISABLED)
21192305Sstevel 		(void) socal_diag_request((void *)socalp, 1, &r,
2120*7656SSherry.Moore@Sun.COM 		    SOC_DIAG_INT_LOOP);
21212305Sstevel 
21222305Sstevel 	mutex_enter(&socalp->k_imr_mtx);
21232305Sstevel 	socalp->socal_shutdown = 0;
21242305Sstevel 	mutex_exit(&socalp->k_imr_mtx);
21252305Sstevel 
21262305Sstevel 	mutex_enter(&socalp->board_mtx);
21272305Sstevel 	if (socal_establish_pool(socalp, 1) != FCAL_SUCCESS) {
21282305Sstevel 		mutex_exit(&socalp->board_mtx);
21292305Sstevel 		return (FCAL_FAILURE);
21302305Sstevel 	}
21312305Sstevel 	if (socal_add_pool_buffer(socalp, 1) != FCAL_SUCCESS) {
21322305Sstevel 		mutex_exit(&socalp->board_mtx);
21332305Sstevel 		return (FCAL_FAILURE);
21342305Sstevel 	}
21352305Sstevel 
21362305Sstevel 	mutex_exit(&socalp->board_mtx);
21372305Sstevel 	return (FCAL_SUCCESS);
21382305Sstevel }
21392305Sstevel 
21402305Sstevel static void
socal_doreset(socal_state_t * socalp)21412305Sstevel socal_doreset(socal_state_t *socalp)
21422305Sstevel {
21432305Sstevel 	int		i;
21442305Sstevel 	socal_port_t	*port_statep;
21452305Sstevel 	socal_unsol_cb_t *scbp;
21462305Sstevel 
21472305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
21482305Sstevel 		mutex_enter(&socalp->request[i].skc_mtx);
21492305Sstevel 		mutex_enter(&socalp->response[i].skc_mtx);
21502305Sstevel 	}
21512305Sstevel 
21522305Sstevel 	mutex_enter(&socalp->k_imr_mtx);
21532305Sstevel 	socal_disable(socalp);
21542305Sstevel 
21552305Sstevel 	if (socalp->pool_dhandle) {
21562305Sstevel 		(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
21572305Sstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
21582305Sstevel 	}
21592305Sstevel 
21602305Sstevel 	if (socalp->pool)
21612305Sstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
21622305Sstevel 
21632305Sstevel 	socalp->pool_dhandle = NULL;
21642305Sstevel 	socalp->pool = NULL;
21652305Sstevel 
21662305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++)
21672305Sstevel 		socal_cqinit(socalp, i);
21682305Sstevel 
21692305Sstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
21702305Sstevel 		port_statep = &socalp->port_state[i];
21712305Sstevel 
21722305Sstevel 		mutex_enter(&port_statep->sp_mtx);
21732305Sstevel 		port_statep->sp_status &= ~ (PORT_STATUS_MASK |
2174*7656SSherry.Moore@Sun.COM 		    PORT_LILP_PENDING | PORT_LIP_PENDING |
2175*7656SSherry.Moore@Sun.COM 		    PORT_ABORT_PENDING | PORT_BYPASS_PENDING |
2176*7656SSherry.Moore@Sun.COM 		    PORT_ELS_PENDING);
21772305Sstevel 		mutex_exit(&port_statep->sp_mtx);
21782305Sstevel 	}
21792305Sstevel 
21802305Sstevel 	mutex_exit(&socalp->k_imr_mtx);
21812305Sstevel 
21822305Sstevel 	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
21832305Sstevel 		mutex_exit(&socalp->request[i].skc_mtx);
21842305Sstevel 		mutex_exit(&socalp->response[i].skc_mtx);
21852305Sstevel 	}
21862305Sstevel 
21872305Sstevel 	for (i = 0; i < N_SOCAL_NPORTS; i++) {
21882305Sstevel 		for (scbp = socalp->port_state[i].sp_unsol_cb; scbp;
2189*7656SSherry.Moore@Sun.COM 		    scbp = scbp->next)
21902305Sstevel 			(scbp->statec_cb)(scbp->arg, FCAL_STATE_RESET);
21912305Sstevel 	}
21922305Sstevel 
21932305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
21942305Sstevel 		mutex_enter(&socalp->request[i].skc_mtx);
21952305Sstevel 		mutex_enter(&socalp->response[i].skc_mtx);
21962305Sstevel 	}
21972305Sstevel 
21982305Sstevel 
21992305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
22002305Sstevel 		socalp->request[i].skc_overflowh = NULL;
22012305Sstevel 		if (socalp->request[i].skc_full & SOCAL_SKC_SLEEP)
22022305Sstevel 			cv_broadcast(&socalp->request[i].skc_cv);
22032305Sstevel 	}
22042305Sstevel 
22052305Sstevel 	for (i = SOCAL_N_CQS-1; i >= 0; i--) {
22062305Sstevel 		mutex_exit(&socalp->request[i].skc_mtx);
22072305Sstevel 		mutex_exit(&socalp->response[i].skc_mtx);
22082305Sstevel 	}
22092305Sstevel 
22102305Sstevel }
22112305Sstevel 
22122305Sstevel 
22132305Sstevel /*
22142305Sstevel  * Function name : socal_download_ucode ()
22152305Sstevel  *
22162305Sstevel  * Return Values :
22172305Sstevel  *
22182305Sstevel  * Description	 : Copies firmware from code that has been linked into
22192305Sstevel  *		   the socal module into the soc+'s XRAM.  Prints the date
22202305Sstevel  *		   string
22212305Sstevel  *
22222305Sstevel  */
22232305Sstevel static void
socal_download_ucode(socal_state_t * socalp)22242305Sstevel socal_download_ucode(socal_state_t *socalp)
22252305Sstevel {
22262305Sstevel 	uint_t	fw_len = 0;
22272305Sstevel 	uint_t	date_str[16];
22282305Sstevel 	auto	char buf[256];
22292305Sstevel 
22302305Sstevel 	fw_len = (uint_t)socal_ucode_size;
22312305Sstevel 
22322305Sstevel 	/* Copy the firmware image */
22332305Sstevel 	socal_wcopy((uint_t *)&socal_ucode,
2234*7656SSherry.Moore@Sun.COM 	    (uint_t *)socalp->socal_xrp, fw_len);
22352305Sstevel 
22362305Sstevel 	socal_fix_harda(socalp, 0);
22372305Sstevel 	socal_fix_harda(socalp, 1);
22382305Sstevel 
22392305Sstevel 	/* Get the date string from the firmware image */
22402305Sstevel 	socal_wcopy((uint_t *)(socalp->socal_xrp+SOCAL_XRAM_FW_DATE_STR),
22412305Sstevel 	    date_str, sizeof (date_str));
22422305Sstevel 	date_str[sizeof (date_str) / sizeof (uint_t) - 1] = 0;
22432305Sstevel 
22442305Sstevel 	if (*(caddr_t)date_str != '\0') {
2245*7656SSherry.Moore@Sun.COM 		(void) sprintf(buf,
2246*7656SSherry.Moore@Sun.COM 		    "!Downloading host adapter, fw date code: %s\n",
2247*7656SSherry.Moore@Sun.COM 		    (caddr_t)date_str);
2248*7656SSherry.Moore@Sun.COM 		socal_disp_err(socalp, CE_CONT, "driver.1010", buf);
2249*7656SSherry.Moore@Sun.COM 		(void) strcpy(socalp->socal_stats.fw_revision,
2250*7656SSherry.Moore@Sun.COM 		    (char *)date_str);
22512305Sstevel 	} else {
2252*7656SSherry.Moore@Sun.COM 		(void) sprintf(buf,
2253*7656SSherry.Moore@Sun.COM 		    "!Downloading host adapter fw, "
2254*7656SSherry.Moore@Sun.COM 		    "date code: <not available>\n");
2255*7656SSherry.Moore@Sun.COM 		socal_disp_err(socalp, CE_CONT, "driver.3010", buf);
2256*7656SSherry.Moore@Sun.COM 		(void) strcpy(socalp->socal_stats.fw_revision,
2257*7656SSherry.Moore@Sun.COM 		    "<Not Available>");
22582305Sstevel 	}
22592305Sstevel }
22602305Sstevel 
22612305Sstevel /*
22622305Sstevel  * Function name : socal_disp_err()
22632305Sstevel  *
22642305Sstevel  * Return Values : none
22652305Sstevel  *
22662305Sstevel  * Description   : displays an error message on the system console
22672305Sstevel  *		   with the full device pathname displayed
22682305Sstevel  */
22692305Sstevel static void
socal_disp_err(socal_state_t * socalp,uint_t level,char * mid,char * msg)22702305Sstevel socal_disp_err(
22712305Sstevel 	socal_state_t	*socalp,
22722305Sstevel 	uint_t		level,
22732305Sstevel 	char		*mid,
22742305Sstevel 	char		*msg)
22752305Sstevel {
22762305Sstevel 	char c;
22772305Sstevel 	int instance;
22782305Sstevel 
22792305Sstevel 	instance = ddi_get_instance(socalp->dip);
22802305Sstevel 
22812305Sstevel 	c = *msg;
22822305Sstevel 
22832305Sstevel 	if (c == '!')		/* log only */
2284*7656SSherry.Moore@Sun.COM 		cmn_err(level,
22852305Sstevel 		"!ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
22862305Sstevel 	else if (c == '?')	/* boot message - log && maybe console */
2287*7656SSherry.Moore@Sun.COM 		cmn_err(level,
22882305Sstevel 		"?ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
22892305Sstevel 	else if (c == '^')	/* console only */
2290*7656SSherry.Moore@Sun.COM 		cmn_err(level, "^socal%d: %s", instance, msg+1);
22912305Sstevel 	else	{		/* log and console */
2292*7656SSherry.Moore@Sun.COM 		cmn_err(level, "^socal%d: %s", instance, msg);
2293*7656SSherry.Moore@Sun.COM 		cmn_err(level, "!ID[SUNWssa.socal.%s] socal%d: %s", mid,
2294*7656SSherry.Moore@Sun.COM 		    instance, msg);
22952305Sstevel 	}
22962305Sstevel }
22972305Sstevel 
22982305Sstevel /*
22992305Sstevel  * Function name : socal_init_cq_desc()
23002305Sstevel  *
23012305Sstevel  * Return Values : none
23022305Sstevel  *
23032305Sstevel  * Description	 : Initializes the request and response queue
23042305Sstevel  *		   descriptors in the SOC+'s XRAM
23052305Sstevel  *
23062305Sstevel  * Context	 : Should only be called during initialiation when
23072305Sstevel  *		   the SOC+ is reset.
23082305Sstevel  */
23092305Sstevel static void
socal_init_cq_desc(socal_state_t * socalp)23102305Sstevel socal_init_cq_desc(socal_state_t *socalp)
23112305Sstevel {
23122305Sstevel 	soc_cq_t	que_desc[SOCAL_N_CQS];
23132305Sstevel 	uint32_t	i;
23142305Sstevel 
23152305Sstevel 	/*
23162305Sstevel 	 * Finish CQ table initialization and give the descriptor
23172305Sstevel 	 * table to the soc+.  Note that we don't use all of the queues
23182305Sstevel 	 * provided by the hardware, but we make sure we initialize the
23192305Sstevel 	 * quantities in the unused fields in the hardware to zeroes.
23202305Sstevel 	 */
23212305Sstevel 
23222305Sstevel 	/*
23232305Sstevel 	 * Do request queues
23242305Sstevel 	 */
23252305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
23262305Sstevel 		if (socal_req_entries[i]) {
2327*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_address =
2328*7656SSherry.Moore@Sun.COM 			    (uint32_t)socalp->request[i].
2329*7656SSherry.Moore@Sun.COM 			    skc_dcookie.dmac_address;
2330*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_last_index = socal_req_entries[i] - 1;
23312305Sstevel 		} else {
2332*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_address = (uint32_t)0;
2333*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_last_index = 0;
23342305Sstevel 		}
23352305Sstevel 		que_desc[i].cq_in = 0;
23362305Sstevel 		que_desc[i].cq_out = 0;
23372305Sstevel 		que_desc[i].cq_seqno = 1; /* required by SOC+ microcode */
23382305Sstevel 	}
23392305Sstevel 
23402305Sstevel 	/* copy to XRAM */
23412305Sstevel 	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
2342*7656SSherry.Moore@Sun.COM 	    (uint_t *)socalp->xram_reqp,	/* pointer to xram location */
2343*7656SSherry.Moore@Sun.COM 	    SOCAL_N_CQS * sizeof (soc_cq_t));
23442305Sstevel 
23452305Sstevel 	/*
23462305Sstevel 	 * Do response queues
23472305Sstevel 	 */
23482305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
23492305Sstevel 		if (socal_rsp_entries[i]) {
2350*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_last_index = socal_rsp_entries[i] - 1;
2351*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_address =
2352*7656SSherry.Moore@Sun.COM 			    (uint32_t)socalp->response[i].
2353*7656SSherry.Moore@Sun.COM 			    skc_dcookie.dmac_address;
23542305Sstevel 
23552305Sstevel 		} else {
2356*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_address = 0;
2357*7656SSherry.Moore@Sun.COM 			que_desc[i].cq_last_index = 0;
23582305Sstevel 		}
23592305Sstevel 	}
23602305Sstevel 
23612305Sstevel 	/* copy to XRAM */
23622305Sstevel 	socal_wcopy((uint_t *)que_desc,		/* pointer to kernel copy */
2363*7656SSherry.Moore@Sun.COM 	    (uint_t *)socalp->xram_rspp,	/* pointer to xram location */
2364*7656SSherry.Moore@Sun.COM 	    SOCAL_N_CQS * sizeof (soc_cq_t));
23652305Sstevel }
23662305Sstevel 
23672305Sstevel static void
socal_init_wwn(socal_state_t * socalp)23682305Sstevel socal_init_wwn(socal_state_t *socalp)
23692305Sstevel {
23702305Sstevel 	/* copy the node wwn to xram */
23712305Sstevel 	socal_wcopy((uint_t *)&socalp->socal_n_wwn,
2372*7656SSherry.Moore@Sun.COM 	    (uint_t *)(socalp->socal_xrp +
2373*7656SSherry.Moore@Sun.COM 	    SOCAL_XRAM_NODE_WWN), sizeof (la_wwn_t));
23742305Sstevel 
23752305Sstevel 	/* copy port a's wwn to xram */
23762305Sstevel 	socal_wcopy((uint_t *)&socalp->port_state[0].sp_p_wwn,
2377*7656SSherry.Moore@Sun.COM 	    (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTA_WWN),
2378*7656SSherry.Moore@Sun.COM 	    sizeof (la_wwn_t));
23792305Sstevel 
23802305Sstevel 	/* copy port b's wwn to xram */
23812305Sstevel 	socal_wcopy((uint_t *)&socalp->port_state[1].sp_p_wwn,
2382*7656SSherry.Moore@Sun.COM 	    (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTB_WWN),
2383*7656SSherry.Moore@Sun.COM 	    sizeof (la_wwn_t));
23842305Sstevel 
23852305Sstevel 	/*
23862305Sstevel 	 * need to avoid deadlock by assuring no other thread grabs both of
23872305Sstevel 	 * these at once
23882305Sstevel 	 */
23892305Sstevel 	mutex_enter(&socalp->port_state[0].sp_transport->fcal_mtx);
23902305Sstevel 	mutex_enter(&socalp->port_state[1].sp_transport->fcal_mtx);
23912305Sstevel 
23922305Sstevel 	socal_wcopy((uint_t *)(socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS),
2393*7656SSherry.Moore@Sun.COM 	    (uint_t *)&socalp->socal_service_params, SOCAL_SVC_LENGTH);
23942305Sstevel 	mutex_exit(&socalp->port_state[1].sp_transport->fcal_mtx);
23952305Sstevel 	mutex_exit(&socalp->port_state[0].sp_transport->fcal_mtx);
23962305Sstevel }
23972305Sstevel 
23982305Sstevel static void
socal_enable(socal_state_t * socalp)23992305Sstevel socal_enable(socal_state_t *socalp)
24002305Sstevel {
24012305Sstevel 	DEBUGF(2, (CE_CONT, "socal%d: enable:\n",
2402*7656SSherry.Moore@Sun.COM 	    ddi_get_instance(socalp->dip)));
24032305Sstevel 
24042305Sstevel 	socalp->socal_rp->socal_cr.w = socalp->socal_cfg;
24052305Sstevel 	socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOCAL_TO_HOST;
24062305Sstevel 
24072305Sstevel 	socalp->socal_k_imr = (uint32_t)SOCAL_CSR_SOCAL_TO_HOST |
24082305Sstevel 	    SOCAL_CSR_SLV_ACC_ERR;
24092305Sstevel 	socalp->socal_rp->socal_imr = (uint32_t)socalp->socal_k_imr;
24102305Sstevel }
24112305Sstevel 
24122305Sstevel /*
24132305Sstevel  * static int
24142305Sstevel  * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
24152305Sstevel  *	to place LINK ctl application data as it arrives.
24162305Sstevel  *
24172305Sstevel  *	Returns:
24182305Sstevel  *		FCAL_SUCCESS, upon establishing the pool.
24192305Sstevel  *		FCAL_FAILURE, if unable to establish the pool.
24202305Sstevel  */
24212305Sstevel 
24222305Sstevel static int
socal_establish_pool(socal_state_t * socalp,uint32_t poolid)24232305Sstevel socal_establish_pool(socal_state_t *socalp, uint32_t poolid)
24242305Sstevel {
24252305Sstevel 	soc_pool_request_t	*prq;
24262305Sstevel 	int			result;
24272305Sstevel 
24282305Sstevel 	if ((prq =
2429*7656SSherry.Moore@Sun.COM 	    (soc_pool_request_t *)kmem_zalloc(sizeof (soc_pool_request_t),
2430*7656SSherry.Moore@Sun.COM 	    KM_NOSLEEP)) == NULL)
24312305Sstevel 			return (FCAL_FAILURE);
24322305Sstevel 	/*
24332305Sstevel 	 * Fill in the request structure.
24342305Sstevel 	 */
24352305Sstevel 	prq->spr_soc_hdr.sh_request_token = 1;
24362305Sstevel 	prq->spr_soc_hdr.sh_flags = SOC_FC_HEADER | SOC_UNSOLICITED |
2437*7656SSherry.Moore@Sun.COM 	    SOC_NO_RESPONSE;
24382305Sstevel 	prq->spr_soc_hdr.sh_class = 0;
24392305Sstevel 	prq->spr_soc_hdr.sh_seg_cnt = 1;
24402305Sstevel 	prq->spr_soc_hdr.sh_byte_cnt = 0;
24412305Sstevel 
24422305Sstevel 	prq->spr_pool_id = poolid;
24432305Sstevel 	prq->spr_header_mask = SOCPR_MASK_RCTL;
24442305Sstevel 	prq->spr_buf_size = SOCAL_POOL_SIZE;
24452305Sstevel 	prq->spr_n_entries = 0;
24462305Sstevel 
24472305Sstevel 	prq->spr_fc_frame_hdr.r_ctl = R_CTL_ELS_REQ;
24482305Sstevel 	prq->spr_fc_frame_hdr.d_id = 0;
24492305Sstevel 	prq->spr_fc_frame_hdr.s_id = 0;
24502305Sstevel 	prq->spr_fc_frame_hdr.type = 0;
24512305Sstevel 	prq->spr_fc_frame_hdr.f_ctl = 0;
24522305Sstevel 	prq->spr_fc_frame_hdr.seq_id = 0;
24532305Sstevel 	prq->spr_fc_frame_hdr.df_ctl = 0;
24542305Sstevel 	prq->spr_fc_frame_hdr.seq_cnt = 0;
24552305Sstevel 	prq->spr_fc_frame_hdr.ox_id = 0;
24562305Sstevel 	prq->spr_fc_frame_hdr.rx_id = 0;
24572305Sstevel 	prq->spr_fc_frame_hdr.ro = 0;
24582305Sstevel 
24592305Sstevel 	prq->spr_cqhdr.cq_hdr_count = 1;
24602305Sstevel 	prq->spr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_POOL;
24612305Sstevel 	prq->spr_cqhdr.cq_hdr_flags = 0;
24622305Sstevel 	prq->spr_cqhdr.cq_hdr_seqno = 0;
24632305Sstevel 
24642305Sstevel 	/* Enque the request. */
24652305Sstevel 	result = socal_cq_enque(socalp, NULL, (cqe_t *)prq, CQ_REQUEST_1,
2466*7656SSherry.Moore@Sun.COM 	    FCAL_NOSLEEP, NULL, 0);
24672305Sstevel 	kmem_free((void *)prq, sizeof (soc_pool_request_t));
24682305Sstevel 	return (result);
24692305Sstevel 
24702305Sstevel }
24712305Sstevel 
24722305Sstevel 
24732305Sstevel /*
24742305Sstevel  * static int
24752305Sstevel  * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
24762305Sstevel  *	to an established pool of buffers
24772305Sstevel  *
24782305Sstevel  *	Returns:
24792305Sstevel  *		DDI_SUCCESS, upon establishing the pool.
24802305Sstevel  *		DDI_FAILURE, if unable to establish the pool.
24812305Sstevel  */
24822305Sstevel 
24832305Sstevel static int
socal_add_pool_buffer(socal_state_t * socalp,uint32_t poolid)24842305Sstevel socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid)
24852305Sstevel {
24862305Sstevel 	soc_data_request_t	*drq;
24872305Sstevel 	int			result;
24882305Sstevel 	size_t			real_len;
24892305Sstevel 	int			bound = 0;
24902305Sstevel 	uint_t			ccount;
24912305Sstevel 
24922305Sstevel 	if ((drq =
2493*7656SSherry.Moore@Sun.COM 	    (soc_data_request_t *)kmem_zalloc(sizeof (soc_data_request_t),
2494*7656SSherry.Moore@Sun.COM 	    KM_NOSLEEP)) == NULL)
24952305Sstevel 			return (FCAL_FAILURE);
24962305Sstevel 
24972305Sstevel 	/* Allocate DVMA resources for the buffer pool */
24982305Sstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
24992305Sstevel 	    DDI_DMA_DONTWAIT, NULL, &socalp->pool_dhandle) != DDI_SUCCESS)
25002305Sstevel 		goto fail;
25012305Sstevel 
25022305Sstevel 	if (ddi_dma_mem_alloc(socalp->pool_dhandle, SOCAL_POOL_SIZE,
25032305Sstevel 	    &socal_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
25042305Sstevel 	    (caddr_t *)&socalp->pool, &real_len, &socalp->pool_acchandle)
25052305Sstevel 	    != DDI_SUCCESS)
25062305Sstevel 		goto fail;
25072305Sstevel 
25082305Sstevel 	if (real_len < SOCAL_POOL_SIZE)
25092305Sstevel 		goto fail;
25102305Sstevel 
25112305Sstevel 	if (ddi_dma_addr_bind_handle(socalp->pool_dhandle, (struct as *)NULL,
25122305Sstevel 	    (caddr_t)socalp->pool, SOCAL_POOL_SIZE,
25132305Sstevel 	    DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
25142305Sstevel 	    NULL, &socalp->pool_dcookie, &ccount) != DDI_DMA_MAPPED)
25152305Sstevel 		goto fail;
25162305Sstevel 
25172305Sstevel 	bound = 1;
25182305Sstevel 	if (ccount != 1)
25192305Sstevel 		goto fail;
25202305Sstevel 
25212305Sstevel 	/*
25222305Sstevel 	 * Fill in the request structure.
25232305Sstevel 	 */
25242305Sstevel 	drq->sdr_soc_hdr.sh_request_token = poolid;
25252305Sstevel 	drq->sdr_soc_hdr.sh_flags = SOC_UNSOLICITED | SOC_NO_RESPONSE;
25262305Sstevel 	drq->sdr_soc_hdr.sh_class = 0;
25272305Sstevel 	drq->sdr_soc_hdr.sh_seg_cnt = 1;
25282305Sstevel 	drq->sdr_soc_hdr.sh_byte_cnt = 0;
25292305Sstevel 
25302305Sstevel 	drq->sdr_dataseg[0].fc_base =
2531*7656SSherry.Moore@Sun.COM 	    (uint32_t)socalp->pool_dcookie.dmac_address;
25322305Sstevel 	drq->sdr_dataseg[0].fc_count = SOCAL_POOL_SIZE;
25332305Sstevel 	drq->sdr_dataseg[1].fc_base = 0;
25342305Sstevel 	drq->sdr_dataseg[1].fc_count = 0;
25352305Sstevel 	drq->sdr_dataseg[2].fc_base = 0;
25362305Sstevel 	drq->sdr_dataseg[2].fc_count = 0;
25372305Sstevel 	drq->sdr_dataseg[3].fc_base = 0;
25382305Sstevel 	drq->sdr_dataseg[3].fc_count = 0;
25392305Sstevel 	drq->sdr_dataseg[4].fc_base = 0;
25402305Sstevel 	drq->sdr_dataseg[4].fc_count = 0;
25412305Sstevel 	drq->sdr_dataseg[5].fc_base = 0;
25422305Sstevel 	drq->sdr_dataseg[5].fc_count = 0;
25432305Sstevel 
25442305Sstevel 	drq->sdr_cqhdr.cq_hdr_count = 1;
25452305Sstevel 	drq->sdr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_BUFFER;
25462305Sstevel 	drq->sdr_cqhdr.cq_hdr_flags = 0;
25472305Sstevel 	drq->sdr_cqhdr.cq_hdr_seqno = 0;
25482305Sstevel 
25492305Sstevel 	/* Transport the request. */
25502305Sstevel 	result = socal_cq_enque(socalp, NULL, (cqe_t *)drq, CQ_REQUEST_1,
2551*7656SSherry.Moore@Sun.COM 	    FCAL_NOSLEEP, NULL, 0);
25522305Sstevel 	kmem_free((void *)drq, sizeof (soc_data_request_t));
25532305Sstevel 	return (result);
25542305Sstevel 
25552305Sstevel fail:
25562305Sstevel 	socal_disp_err(socalp, CE_WARN, "driver.4110",
2557*7656SSherry.Moore@Sun.COM 	    "!Buffer pool DVMA alloc failed");
25582305Sstevel 	if (socalp->pool_dhandle) {
25592305Sstevel 		if (bound)
25602305Sstevel 			(void) ddi_dma_unbind_handle(socalp->pool_dhandle);
25612305Sstevel 		ddi_dma_free_handle(&socalp->pool_dhandle);
25622305Sstevel 	}
25632305Sstevel 	if (socalp->pool)
25642305Sstevel 		ddi_dma_mem_free(&socalp->pool_acchandle);
25652305Sstevel 	socalp->pool_dhandle = NULL;
25662305Sstevel 	return (FCAL_FAILURE);
25672305Sstevel }
25682305Sstevel 
25692305Sstevel static uint_t
socal_transport(fcal_packet_t * fcalpkt,fcal_sleep_t sleep,int req_q_no)25702305Sstevel socal_transport(fcal_packet_t *fcalpkt, fcal_sleep_t sleep, int req_q_no)
25712305Sstevel {
25722305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
25732305Sstevel 	socal_port_t	*port_statep;
25742305Sstevel #if defined(DEBUG) && !defined(lint)
25752305Sstevel 	int		instance = ddi_get_instance(socalp->dip);
25762305Sstevel #endif
25772305Sstevel 	int		port;
25782305Sstevel 	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
25792305Sstevel 
25802305Sstevel 	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
25812305Sstevel 		port = 1;
25822305Sstevel 	else
25832305Sstevel 		port = 0;
25842305Sstevel 	port_statep = &socalp->port_state[port];
25852305Sstevel 
25862305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d: transport: packet, sleep = %p, %d\n",
2587*7656SSherry.Moore@Sun.COM 	    instance, fcalpkt, sleep));
25882305Sstevel 
25892305Sstevel 	fcalpkt->fcal_cmd_state = 0;
25902305Sstevel 	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
25912305Sstevel 
25922305Sstevel 	return (socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
25932305Sstevel 	    req_q_no, sleep, fcalpkt, 0));
25942305Sstevel }
25952305Sstevel 
25962305Sstevel /*
25972305Sstevel  * Function name : socal_cq_enque()
25982305Sstevel  *
25992305Sstevel  * Return Values :
26002305Sstevel  *		FCAL_TRANSPORT_SUCCESS, if able to que the entry.
26012305Sstevel  *		FCAL_TRANSPORT_QFULL, if queue full & sleep not set
26022305Sstevel  *		FCAL_TRANSPORT_UNAVAIL if this port down
26032305Sstevel  *
26042305Sstevel  * Description	 : Enqueues an entry into the solicited request
26052305Sstevel  *		   queue
26062305Sstevel  *
26072305Sstevel  * Context	:
26082305Sstevel  */
26092305Sstevel 
26102305Sstevel /*ARGSUSED*/
26112305Sstevel static int
socal_cq_enque(socal_state_t * socalp,socal_port_t * port_statep,cqe_t * cqe,int rqix,fcal_sleep_t sleep,fcal_packet_t * to_queue,int mtxheld)26122305Sstevel socal_cq_enque(socal_state_t *socalp, socal_port_t *port_statep, cqe_t *cqe,
26132305Sstevel 		int rqix, fcal_sleep_t sleep, fcal_packet_t *to_queue,
26142305Sstevel 		int mtxheld)
26152305Sstevel {
26162305Sstevel #if defined(DEBUG) && !defined(lint)
26172305Sstevel 	int 		instance = ddi_get_instance(socalp->dip);
26182305Sstevel #endif
26192305Sstevel 	socal_kcq_t	*kcq;
26202305Sstevel 	cqe_t		*sp;
26212305Sstevel 	uint_t		bitmask, wmask;
26222305Sstevel 	uchar_t		out;
26232305Sstevel 	uchar_t		s_out;
26242305Sstevel 	longlong_t	*p, *q;
26252305Sstevel 
26262305Sstevel 	kcq = &socalp->request[rqix];
26272305Sstevel 
26282305Sstevel 	bitmask = SOCAL_CSR_1ST_H_TO_S << rqix;
26292305Sstevel 	wmask = SOCAL_CSR_SOCAL_TO_HOST | bitmask;
26302305Sstevel 	p = (longlong_t *)cqe;
26312305Sstevel 
26322305Sstevel 	/*
26332305Sstevel 	 * Since we're only reading we don't need a mutex.
26342305Sstevel 	 */
26352305Sstevel 	if (socalp->socal_shutdown) {
26362305Sstevel 		return (FCAL_TRANSPORT_UNAVAIL);
26372305Sstevel 	}
26382305Sstevel 	/*
26392305Sstevel 	 * Get a token early.  That way we won't sleep
26402305Sstevel 	 * in id32_alloc() with a mutex held.
26412305Sstevel 	 */
26422305Sstevel 	if (to_queue) {
26432305Sstevel 		if ((to_queue->fcal_socal_request.sr_soc_hdr.sh_request_token =
2644*7656SSherry.Moore@Sun.COM 		    SOCAL_ID_GET(to_queue, mtxheld ? FCAL_NOSLEEP :
2645*7656SSherry.Moore@Sun.COM 		    sleep)) == NULL) {
26462305Sstevel 			return (FCAL_TRANSPORT_QFULL);
26472305Sstevel 		}
26482305Sstevel 	}
26492305Sstevel 	/*
26502305Sstevel 	 * Grab lock for request queue.
26512305Sstevel 	 */
26522305Sstevel 
26532305Sstevel 	if (!mtxheld)
26542305Sstevel 		mutex_enter(&kcq->skc_mtx);
26552305Sstevel 
26562305Sstevel 	/*
26572305Sstevel 	 * Determine if the queue is full
26582305Sstevel 	 */
26592305Sstevel 
26602305Sstevel 	do {
26612305Sstevel 
2662*7656SSherry.Moore@Sun.COM 		if (kcq->skc_full) {
26632305Sstevel 		/*
26642305Sstevel 		 * If soc's queue full, then we wait for an interrupt
26652305Sstevel 		 * telling us we are not full.
26662305Sstevel 		 */
26672305Sstevel 
2668*7656SSherry.Moore@Sun.COM 			if (to_queue) {
26692305Sstevel 			to_queue->fcal_pkt_next = NULL;
26702305Sstevel 			if (!kcq->skc_overflowh) {
2671*7656SSherry.Moore@Sun.COM 				DEBUGF(2, (CE_CONT,
2672*7656SSherry.Moore@Sun.COM 				    "socal%d: cq_enque: request "
2673*7656SSherry.Moore@Sun.COM 				    "que %d is full\n",
2674*7656SSherry.Moore@Sun.COM 				    instance, rqix));
2675*7656SSherry.Moore@Sun.COM 				kcq->skc_overflowh = to_queue;
2676*7656SSherry.Moore@Sun.COM 				socalp->socal_stats.qfulls++;
26772305Sstevel 			} else
2678*7656SSherry.Moore@Sun.COM 				kcq->skc_overflowt->fcal_pkt_next = to_queue;
26792305Sstevel 			kcq->skc_overflowt = to_queue;
26802305Sstevel 
26812305Sstevel 			mutex_enter(&socalp->k_imr_mtx);
26822305Sstevel 			socalp->socal_rp->socal_imr =
26832305Sstevel 			    (socalp->socal_k_imr |= bitmask);
26842305Sstevel 			mutex_exit(&socalp->k_imr_mtx);
26852305Sstevel 			to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
26862305Sstevel 			if (!mtxheld)
26872305Sstevel 				mutex_exit(&kcq->skc_mtx);
26882305Sstevel 			return (FCAL_TRANSPORT_SUCCESS);
2689*7656SSherry.Moore@Sun.COM 			}
2690*7656SSherry.Moore@Sun.COM 
2691*7656SSherry.Moore@Sun.COM 			if (!mtxheld)
26922305Sstevel 			mutex_exit(&kcq->skc_mtx);
2693*7656SSherry.Moore@Sun.COM 			return (FCAL_TRANSPORT_QFULL);
2694*7656SSherry.Moore@Sun.COM 		}
2695*7656SSherry.Moore@Sun.COM 
2696*7656SSherry.Moore@Sun.COM 		if (((kcq->skc_in + 1) & kcq->skc_last_index)
2697*7656SSherry.Moore@Sun.COM 		    == (out = kcq->skc_out)) {
26982305Sstevel 		/*
26992305Sstevel 		 * get SOC+'s copy of out to update our copy of out
27002305Sstevel 		 */
27012305Sstevel 		s_out =
27022305Sstevel 		    SOCAL_REQUESTQ_INDEX(rqix, socalp->socal_rp->socal_reqp.w);
27032305Sstevel 		DEBUGF(2, (CE_CONT,
2704*7656SSherry.Moore@Sun.COM 		    "socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
2705*7656SSherry.Moore@Sun.COM 		    instance, &kcq->skc_xram_cqdesc->cq_in, s_out));
27062305Sstevel 
27072305Sstevel 		kcq->skc_out = out = s_out;
27082305Sstevel 		/* if soc+'s que still full set flag */
27092305Sstevel 		kcq->skc_full = ((((kcq->skc_in + 1) &
2710*7656SSherry.Moore@Sun.COM 		    kcq->skc_last_index) == out)) ? SOCAL_SKC_FULL : 0;
2711*7656SSherry.Moore@Sun.COM 		}
27122305Sstevel 
27132305Sstevel 	} while (kcq->skc_full);
27142305Sstevel 
27152305Sstevel 	/* Now enque the entry. */
27162305Sstevel 	sp = &(kcq->skc_cq[kcq->skc_in]);
27172305Sstevel 	cqe->cqe_hdr.cq_hdr_seqno = kcq->skc_seqno;
27182305Sstevel 
27192305Sstevel 	/* Give the entry to the SOC. */
27202305Sstevel 	q = (longlong_t *)sp;
27212305Sstevel 	*q++ = *p++;
27222305Sstevel 	*q++ = *p++;
27232305Sstevel 	*q++ = *p++;
27242305Sstevel 	*q++ = *p++;
27252305Sstevel 	*q++ = *p++;
27262305Sstevel 	*q++ = *p++;
27272305Sstevel 	*q++ = *p++;
27282305Sstevel 	*q = *p;
27292305Sstevel 	(void) ddi_dma_sync(kcq->skc_dhandle, (int)((caddr_t)sp -
27302305Sstevel 	    (caddr_t)kcq->skc_cq), sizeof (cqe_t), DDI_DMA_SYNC_FORDEV);
27312305Sstevel 	if (to_queue)
27322305Sstevel 		to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
27332305Sstevel 
27342305Sstevel 	/*
27352305Sstevel 	 * Update circular queue and ring SOC's doorbell.
27362305Sstevel 	 */
27372305Sstevel 	kcq->skc_in++;
27382305Sstevel 	if ((kcq->skc_in & kcq->skc_last_index) == 0) {
27392305Sstevel 		kcq->skc_in = 0;
27402305Sstevel 		kcq->skc_seqno++;
27412305Sstevel 	}
27422305Sstevel 
27432305Sstevel 	socalp->socal_rp->socal_csr.w = wmask | (kcq->skc_in << 24);
27442305Sstevel 	/* Let lock go for request queue. */
27452305Sstevel 	if (!mtxheld)
27462305Sstevel 		mutex_exit(&kcq->skc_mtx);
27472305Sstevel 
27482305Sstevel 	return (FCAL_TRANSPORT_SUCCESS);
27492305Sstevel }
27502305Sstevel 
27512305Sstevel static uint_t
socal_transport_poll(fcal_packet_t * fcalpkt,uint_t timeout,int req_q_no)27522305Sstevel socal_transport_poll(fcal_packet_t *fcalpkt, uint_t timeout, int req_q_no)
27532305Sstevel {
27542305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
27552305Sstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
27562305Sstevel 	uint_t			csr;
27572305Sstevel 	socal_port_t	*port_statep;
27582305Sstevel 	int		port;
27592305Sstevel 	soc_request_t	*sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
27602305Sstevel 	uint32_t	retval;
27612305Sstevel 	clock_t		ticker, t;
27622305Sstevel 
27632305Sstevel 	/* make the timeout meaningful */
27642305Sstevel 	timeout = drv_usectohz(timeout);
27652305Sstevel 	if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
27662305Sstevel 		port = 1;
27672305Sstevel 	else
27682305Sstevel 		port = 0;
27692305Sstevel 	port_statep = &socalp->port_state[port];
27702305Sstevel 
27712305Sstevel 	fcalpkt->fcal_cmd_state = 0;
27722305Sstevel 	fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
27732305Sstevel 
27742305Sstevel 	ticker = ddi_get_lbolt();
27752305Sstevel 
27762305Sstevel 	if ((retval = socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
27772305Sstevel 	    req_q_no, FCAL_NOSLEEP, fcalpkt, 0)) != FCAL_TRANSPORT_SUCCESS) {
27782305Sstevel 		return (retval);
27792305Sstevel 	} else {
27802305Sstevel 		while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
27812305Sstevel 			drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME);
27822305Sstevel 			t = ddi_get_lbolt();
27832305Sstevel 			if ((ticker + timeout) < t)
27842305Sstevel 				return (FCAL_TRANSPORT_TIMEOUT);
27852305Sstevel 			csr = socalreg->socal_csr.w;
27862305Sstevel 			if ((SOCAL_INTR_CAUSE(socalp, csr)) &
27872305Sstevel 			    SOCAL_CSR_RSP_QUE_0) {
27882305Sstevel 				socal_intr_solicited(socalp, 0);
27892305Sstevel 			}
27902305Sstevel 		}
27912305Sstevel 	}
27922305Sstevel 	return (FCAL_TRANSPORT_SUCCESS);
27932305Sstevel }
27942305Sstevel 
27952305Sstevel static uint_t
socal_doit(fcal_packet_t * fcalpkt,socal_port_t * port_statep,int polled,void (* func)(),int timo,int flag,uint_t * diagcode)27962305Sstevel socal_doit(fcal_packet_t *fcalpkt, socal_port_t *port_statep, int polled,
27972305Sstevel     void (*func)(), int timo, int flag, uint_t *diagcode)
27982305Sstevel {
27992305Sstevel 	clock_t lb;
28002305Sstevel 	uint32_t retval, status;
28012305Sstevel 	socal_state_t   *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
28022305Sstevel 
28032305Sstevel 	if (polled) {
28042305Sstevel 		fcalpkt->fcal_pkt_comp = NULL;
28052305Sstevel 		status = socal_transport_poll(fcalpkt, timo, CQ_REQUEST_0);
28062305Sstevel 	} else {
28072305Sstevel 		fcalpkt->fcal_pkt_comp = func;
28082305Sstevel 		mutex_enter(&port_statep->sp_mtx);
28092305Sstevel 		port_statep->sp_status |= flag;
28102305Sstevel 		if ((status = socal_transport(fcalpkt, FCAL_NOSLEEP,
28112305Sstevel 		    CQ_REQUEST_0)) == FCAL_TRANSPORT_SUCCESS) {
2812*7656SSherry.Moore@Sun.COM 			lb = ddi_get_lbolt();
28132305Sstevel 			while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
28142305Sstevel 			if ((retval = cv_timedwait(&port_statep->sp_cv,
28152305Sstevel 			    &port_statep->sp_mtx,
28162305Sstevel 			    lb+drv_usectohz(timo))) == -1) {
2817*7656SSherry.Moore@Sun.COM 				status = FCAL_TRANSPORT_TIMEOUT;
2818*7656SSherry.Moore@Sun.COM 				break;
28192305Sstevel 			}
2820*7656SSherry.Moore@Sun.COM 			}
28212305Sstevel 		}
28222305Sstevel 		port_statep->sp_status &= ~flag;
28232305Sstevel 		mutex_exit(&port_statep->sp_mtx);
28242305Sstevel 	}
28252305Sstevel 
28262305Sstevel 	switch (status) {
28272305Sstevel 		case FCAL_TRANSPORT_SUCCESS:
28282305Sstevel 			status = fcalpkt->fcal_pkt_status;
28292305Sstevel 			if (diagcode)
28302305Sstevel 				*diagcode = fcalpkt->fcal_diag_status;
28312305Sstevel 			switch (status) {
28322305Sstevel 				case FCAL_STATUS_ABORT_FAILED:
28332305Sstevel 					if (flag == PORT_ABORT_PENDING)
28342305Sstevel 						retval = FCAL_ABORT_FAILED;
28352305Sstevel 					break;
28362305Sstevel 				case FCAL_STATUS_OK:
28372305Sstevel 					if (flag == PORT_ABORT_PENDING)
28382305Sstevel 						retval = FCAL_ABORT_FAILED;
28392305Sstevel 					else
28402305Sstevel 						retval = FCAL_SUCCESS;
28412305Sstevel 					break;
28422305Sstevel 				case FCAL_STATUS_OLD_PORT:
28432305Sstevel 					retval = FCAL_OLD_PORT;
28442305Sstevel 					break;
28452305Sstevel 				case FCAL_STATUS_ERR_OFFLINE:
28462305Sstevel 					retval = FCAL_OFFLINE;
28472305Sstevel 					break;
28482305Sstevel 				case FCAL_STATUS_ABORTED:
28492305Sstevel 					retval = FCAL_ABORTED;
28502305Sstevel 					port_statep->sp_board->
28512305Sstevel 					    socal_stats.pstats[port_statep
28522305Sstevel 					    ->sp_port].abts_ok++;
28532305Sstevel 					break;
28542305Sstevel 				case FCAL_STATUS_BAD_XID:
28552305Sstevel 					retval = FCAL_BAD_ABORT;
28562305Sstevel 					break;
28572305Sstevel 				case FCAL_STATUS_BAD_DID:
28582305Sstevel 					retval = FCAL_BAD_PARAMS;
28592305Sstevel 					break;
28602305Sstevel 				case FCAL_STATUS_DIAG_BUSY:
28612305Sstevel 				case FCAL_STATUS_DIAG_INVALID:
28622305Sstevel 					retval = status;
28632305Sstevel 					break;
28642305Sstevel 				default:
28652305Sstevel 					retval = FCAL_LINK_ERROR;
28662305Sstevel 			}
28672305Sstevel 			break;
28682305Sstevel 		case FCAL_TRANSPORT_TIMEOUT:
28692305Sstevel 			if (flag == PORT_LIP_PENDING ||
28702305Sstevel 			    flag == PORT_LILP_PENDING) {
28712305Sstevel 				if (socal_core &&
2872*7656SSherry.Moore@Sun.COM 				    (socal_core & SOCAL_FAILED_LIP)) {
28732305Sstevel 					socal_core = 0;
28742305Sstevel 					socal_take_core(socalp);
28752305Sstevel 				}
28762305Sstevel 				socal_disp_err(socalp, CE_WARN, "link.6040",
28772305Sstevel 				"SOCAL:Forcing SOC+ reset as LIP timed out\n");
28782305Sstevel 				/* restart socal after resetting */
28792305Sstevel 				(void) socal_force_reset(port_statep->sp_board,
28802305Sstevel 				    polled, RESET_PORT);
28812305Sstevel 			}
28822305Sstevel 			else
28832305Sstevel 				(void) socal_force_lip(port_statep->sp_board,
2884*7656SSherry.Moore@Sun.COM 				    port_statep->sp_port, polled,
2885*7656SSherry.Moore@Sun.COM 				    FCAL_FORCE_LIP);
28862305Sstevel 			retval = FCAL_TIMEOUT;
28872305Sstevel 			break;
28882305Sstevel 		case FCAL_TRANSPORT_FAILURE:
28892305Sstevel 		case FCAL_BAD_PACKET:
28902305Sstevel 		case FCAL_TRANSPORT_UNAVAIL:
28912305Sstevel 		case FCAL_TRANSPORT_QFULL:
28922305Sstevel 			retval = status;
28932305Sstevel 			break;
28942305Sstevel 		default:
28952305Sstevel 			retval = FCAL_LINK_ERROR;
28962305Sstevel 	}
28972305Sstevel 	socal_packet_free(fcalpkt);
28982305Sstevel 	return (retval);
28992305Sstevel }
29002305Sstevel 
29012305Sstevel static uint_t
socal_lilp_map(void * ssp,uint_t port,uint32_t bufid,uint_t polled)29022305Sstevel socal_lilp_map(void *ssp, uint_t port, uint32_t bufid, uint_t polled)
29032305Sstevel {
29042305Sstevel 	fcal_packet_t		*fcalpkt;
29052305Sstevel 	soc_data_request_t	*sdr;
29062305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29072305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29082305Sstevel 
29092305Sstevel 	if ((fcalpkt =
29102305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
29112305Sstevel 	    == (fcal_packet_t *)NULL)
29122305Sstevel 		return (FCAL_ALLOC_FAILED);
29132305Sstevel 
29142305Sstevel 	sdr = (soc_data_request_t *)&fcalpkt->fcal_socal_request;
29152305Sstevel 	if (port)
2916*7656SSherry.Moore@Sun.COM 		sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
29172305Sstevel 	sdr->sdr_soc_hdr.sh_seg_cnt = 1;
29182305Sstevel 	sdr->sdr_soc_hdr.sh_byte_cnt = 132;
29192305Sstevel 	sdr->sdr_dataseg[0].fc_base = bufid;
29202305Sstevel 	sdr->sdr_dataseg[0].fc_count = 132;
29212305Sstevel 	sdr->sdr_cqhdr.cq_hdr_count = 1;
29222305Sstevel 	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_REPORT_MAP;
29232305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
29242305Sstevel 
29252305Sstevel 	return (socal_doit(fcalpkt, port_statep, polled, socal_lilp_map_done,
29262305Sstevel 	    SOCAL_LILP_TIMEOUT, PORT_LILP_PENDING, NULL));
29272305Sstevel }
29282305Sstevel 
29292305Sstevel static uint_t
socal_force_lip(void * ssp,uint_t port,uint_t polled,uint_t lip_req)29302305Sstevel socal_force_lip(void *ssp, uint_t port, uint_t polled, uint_t lip_req)
29312305Sstevel {
29322305Sstevel 	fcal_packet_t		*fcalpkt;
29332305Sstevel 	soc_cmdonly_request_t	*scr;
29342305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29352305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29362305Sstevel 
29372305Sstevel 
29382305Sstevel 	if (lip_req == FCAL_NO_LIP) {
29392305Sstevel 		mutex_enter(&port_statep->sp_mtx);
29402305Sstevel 		if ((port_statep->sp_status & PORT_ONLINE_LOOP) &&
2941*7656SSherry.Moore@Sun.COM 		    (port_statep->sp_unsol_cb->statec_cb != NULL)) {
29422305Sstevel 				mutex_exit(&port_statep->sp_mtx);
29432305Sstevel 				(*port_statep->sp_unsol_cb->statec_cb)
2944*7656SSherry.Moore@Sun.COM 				    (port_statep->sp_unsol_cb->arg,
2945*7656SSherry.Moore@Sun.COM 				    FCAL_STATUS_LOOP_ONLINE);
29462305Sstevel 			return (FCAL_SUCCESS);
29472305Sstevel 
29482305Sstevel 		} else
29492305Sstevel 			mutex_exit(&port_statep->sp_mtx);
29502305Sstevel 	}
29512305Sstevel 	socalp->socal_stats.pstats[port].lips++;
29522305Sstevel 	if ((fcalpkt =
29532305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
29542305Sstevel 	    == (fcal_packet_t *)NULL)
29552305Sstevel 		return (FCAL_ALLOC_FAILED);
29562305Sstevel 
29572305Sstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
29582305Sstevel 	if (port)
2959*7656SSherry.Moore@Sun.COM 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
29602305Sstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
29612305Sstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_LIP;
29622305Sstevel 
29632305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
29642305Sstevel 	return (socal_doit(fcalpkt, port_statep, polled, socal_force_lip_done,
29652305Sstevel 	    SOCAL_LIP_TIMEOUT, PORT_LIP_PENDING, NULL));
29662305Sstevel }
29672305Sstevel 
29682305Sstevel static uint_t
socal_abort_cmd(void * ssp,uint_t port,fcal_packet_t * fcalpkt,uint_t polled)29692305Sstevel socal_abort_cmd(void *ssp, uint_t port, fcal_packet_t *fcalpkt, uint_t polled)
29702305Sstevel {
29712305Sstevel 	fcal_packet_t		*fcalpkt2, *fpkt;
29722305Sstevel 	soc_cmdonly_request_t	*scr, *tscr;
29732305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
29742305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
29752305Sstevel 	socal_kcq_t		*kcq;
29762305Sstevel 
29772305Sstevel 	socalp->socal_stats.pstats[port].abts++;
29782305Sstevel 	kcq = &socalp->request[CQ_REQUEST_1];
29792305Sstevel 	mutex_enter(&kcq->skc_mtx);
29802305Sstevel 	fcalpkt2 = kcq->skc_overflowh;
29812305Sstevel 	fpkt = NULL;
29822305Sstevel 	while (fcalpkt2 != NULL) {
29832305Sstevel 		if (fcalpkt2 == fcalpkt) {
29842305Sstevel 			if (fpkt == NULL)
29852305Sstevel 				kcq->skc_overflowh = fcalpkt->fcal_pkt_next;
29862305Sstevel 			else {
29872305Sstevel 				fpkt->fcal_pkt_next = fcalpkt->fcal_pkt_next;
29882305Sstevel 				if (kcq->skc_overflowt == fcalpkt)
29892305Sstevel 					kcq->skc_overflowt = fpkt;
29902305Sstevel 			}
29912305Sstevel 			mutex_exit(&kcq->skc_mtx);
29922305Sstevel 			socalp->socal_stats.pstats[port].abts_ok++;
29932305Sstevel 			SOCAL_ID_FREE(fcalpkt->fcal_socal_request.
2994*7656SSherry.Moore@Sun.COM 			    sr_soc_hdr.sh_request_token);
29952305Sstevel 			return (FCAL_ABORTED);
29962305Sstevel 		} else {
29972305Sstevel 			fpkt = fcalpkt2;
29982305Sstevel 			fcalpkt2 = fcalpkt2->fcal_pkt_next;
29992305Sstevel 		}
30002305Sstevel 	}
30012305Sstevel 	mutex_exit(&kcq->skc_mtx);
30022305Sstevel 	if ((fcalpkt2 =
30032305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
30042305Sstevel 	    == (fcal_packet_t *)NULL)
30052305Sstevel 		return (FCAL_ALLOC_FAILED);
30062305Sstevel 
30072305Sstevel 	mutex_enter(&socalp->abort_mtx);
30082305Sstevel 	/* Too late? */
30092305Sstevel 	if (fcalpkt->fcal_pkt_flags & FCFLAG_COMPLETE) {
30102305Sstevel 		socal_packet_free(fcalpkt2);
30112305Sstevel 		mutex_exit(&socalp->abort_mtx);
30122305Sstevel 		return (FCAL_ABORTED);
30132305Sstevel 		/* I lied.  So shoot me. */
30142305Sstevel 	}
30152305Sstevel 	/* Mark packet as being aborted and put it in the abort pending list. */
30162305Sstevel 	fcalpkt->fcal_pkt_flags |= FCFLAG_ABORTING;
30172305Sstevel 
30182305Sstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt2->fcal_socal_request;
30192305Sstevel 	tscr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
30202305Sstevel 	scr->scr_soc_hdr.sh_byte_cnt = tscr->scr_soc_hdr.sh_request_token;
30212305Sstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
30222305Sstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_ABORT;
30232305Sstevel 	if (port)
30242305Sstevel 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
30252305Sstevel 	fcalpkt2->fcal_pkt_cookie = (void *)socalp;
30262305Sstevel 	mutex_exit(&socalp->abort_mtx);
30272305Sstevel 
30282305Sstevel 	return (socal_doit(fcalpkt2, port_statep, polled, socal_abort_done,
30292305Sstevel 	    SOCAL_ABORT_TIMEOUT, PORT_ABORT_PENDING, NULL));
30302305Sstevel }
30312305Sstevel 
30322305Sstevel /*ARGSUSED*/
30332305Sstevel static uint_t
socal_els(void * ssp,uint_t port,uint_t elscode,uint_t dest,void (* callback)(),void * arg,caddr_t reqpl,caddr_t * rsppl,uint_t sleep)30342305Sstevel socal_els(void *ssp, uint_t port, uint_t elscode, uint_t dest,
30352305Sstevel 	void (*callback)(), void *arg, caddr_t reqpl, caddr_t *rsppl,
30362305Sstevel 	uint_t sleep)
30372305Sstevel {
30382305Sstevel 	return (FCAL_TRANSPORT_FAILURE);
30392305Sstevel }
30402305Sstevel 
30412305Sstevel static uint_t
socal_bypass_dev(void * ssp,uint_t port,uint_t dest)30422305Sstevel socal_bypass_dev(void *ssp, uint_t port, uint_t dest)
30432305Sstevel {
30442305Sstevel 	fcal_packet_t		*fcalpkt;
30452305Sstevel 	soc_cmdonly_request_t	*scr;
30462305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
30472305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
30482305Sstevel 
30492305Sstevel 	if ((fcalpkt =
30502305Sstevel 	    socal_packet_alloc(socalp, FCAL_SLEEP))
30512305Sstevel 	    == (fcal_packet_t *)NULL)
30522305Sstevel 		return (FCAL_ALLOC_FAILED);
30532305Sstevel 
30542305Sstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
30552305Sstevel 	if (port)
3056*7656SSherry.Moore@Sun.COM 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
30572305Sstevel 	scr->scr_soc_hdr.sh_byte_cnt = dest;
30582305Sstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
30592305Sstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_BYPASS_DEV;
30602305Sstevel 	return (socal_doit(fcalpkt, port_statep, 0, socal_bypass_dev_done,
30612305Sstevel 	    SOCAL_BYPASS_TIMEOUT, PORT_BYPASS_PENDING, NULL));
30622305Sstevel }
30632305Sstevel 
30642305Sstevel 
30652305Sstevel /*ARGSUSED*/
30662305Sstevel static void
socal_force_reset(void * ssp,uint_t port,uint_t restart)30672305Sstevel socal_force_reset(void *ssp, uint_t port, uint_t restart)
30682305Sstevel {
30692305Sstevel 	socal_state_t 	*socalp = (socal_state_t *)ssp;
30702305Sstevel 
30712305Sstevel 	mutex_enter(&socalp->k_imr_mtx);
30722305Sstevel 	if (socalp->socal_shutdown) {
30732305Sstevel 		mutex_exit(&socalp->k_imr_mtx);
30742305Sstevel 		return;
30752305Sstevel 	} else {
30762305Sstevel 		socalp->socal_shutdown = 1;
30772305Sstevel 		mutex_exit(&socalp->k_imr_mtx);
30782305Sstevel 	}
30792305Sstevel 	socalp->socal_stats.resets++;
30802305Sstevel 	socal_doreset(socalp);
30812305Sstevel 	if (restart) {
30822305Sstevel 		if (socal_start(socalp) != FCAL_SUCCESS) {
30832305Sstevel 			cmn_err(CE_WARN, "socal: start failed.\n");
30842305Sstevel 		}
30852305Sstevel 	}
30862305Sstevel }
30872305Sstevel 
30882305Sstevel 
30892305Sstevel static void
socal_add_ulp(void * ssp,uint_t port,uchar_t type,void (* ulp_statec_callback)(),void (* ulp_els_callback)(),void (* ulp_data_callback)(),void * arg)30902305Sstevel socal_add_ulp(void *ssp, uint_t port, uchar_t type,
30912305Sstevel 	void (*ulp_statec_callback)(), void (*ulp_els_callback)(),
30922305Sstevel 	void (*ulp_data_callback)(), void *arg)
30932305Sstevel {
30942305Sstevel 	socal_state_t	*socalp = (socal_state_t *)ssp;
30952305Sstevel 	socal_port_t	*port_statep = &socalp->port_state[port];
30962305Sstevel 	socal_unsol_cb_t *cbentry;
30972305Sstevel 
30982305Sstevel 	mutex_enter(&port_statep->sp_mtx);
30992305Sstevel 	for (cbentry = port_statep->sp_unsol_cb; cbentry;
31002305Sstevel 	    cbentry = cbentry->next) {
31012305Sstevel 		if (cbentry->type == type) {
31022305Sstevel 			cbentry->statec_cb = ulp_statec_callback;
31032305Sstevel 			cbentry->els_cb = ulp_els_callback;
31042305Sstevel 			cbentry->data_cb = ulp_data_callback;
31052305Sstevel 			cbentry->arg = arg;
31062305Sstevel 			mutex_exit(&port_statep->sp_mtx);
31072305Sstevel 			return;
31082305Sstevel 		}
31092305Sstevel 	}
31102305Sstevel 	mutex_exit(&port_statep->sp_mtx);
31112305Sstevel 	if ((cbentry =
31122305Sstevel 	    (socal_unsol_cb_t *)kmem_zalloc(sizeof (socal_unsol_cb_t),
31132305Sstevel 	    KM_SLEEP)) == (socal_unsol_cb_t *)NULL) {
31142305Sstevel 		return;
31152305Sstevel 	}
31162305Sstevel 	mutex_enter(&port_statep->sp_mtx);
31172305Sstevel 	cbentry->statec_cb = ulp_statec_callback;
31182305Sstevel 	cbentry->els_cb = ulp_els_callback;
31192305Sstevel 	cbentry->data_cb = ulp_data_callback;
31202305Sstevel 	cbentry->arg = arg;
31212305Sstevel 	cbentry->type = type;
31222305Sstevel 
31232305Sstevel 	cbentry->next = port_statep->sp_unsol_cb;
31242305Sstevel 	port_statep->sp_unsol_cb = cbentry;
31252305Sstevel 	mutex_exit(&port_statep->sp_mtx);
31262305Sstevel }
31272305Sstevel 
31282305Sstevel 
31292305Sstevel /*
31302305Sstevel  * remove a ULP with matching type and arg
31312305Sstevel  */
31322305Sstevel static void
socal_remove_ulp(void * ssp,uint_t port,uchar_t type,void * arg)31332305Sstevel socal_remove_ulp(void *ssp, uint_t port, uchar_t type, void *arg)
31342305Sstevel {
31352305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
31362305Sstevel 	socal_port_t		*port_statep;
31372305Sstevel 	socal_unsol_cb_t	*cbentry;
31382305Sstevel 	socal_unsol_cb_t	*p_cbentry;
31392305Sstevel 
31402305Sstevel 
31412305Sstevel 	ASSERT(ssp != NULL);
31422305Sstevel 	port_statep = &socalp->port_state[port];
31432305Sstevel 	ASSERT(port_statep != NULL);
31442305Sstevel 
31452305Sstevel 	/* scan the list of unsolicited callback entries */
31462305Sstevel 	mutex_enter(&port_statep->sp_mtx);
31472305Sstevel 	p_cbentry = NULL;
31482305Sstevel 	for (cbentry = port_statep->sp_unsol_cb;
31492305Sstevel 	    cbentry != NULL;
31502305Sstevel 	    p_cbentry = cbentry, cbentry = cbentry->next) {
31512305Sstevel 		if ((cbentry->type != type) || (cbentry->arg != arg)) {
31522305Sstevel 			continue;	/* this entry  doesn't match */
31532305Sstevel 		}
31542305Sstevel 		/* found entry to remove */
31552305Sstevel 		if (port_statep->sp_unsol_cb == cbentry) {
31562305Sstevel 			/* remove first entry in list */
31572305Sstevel 			port_statep->sp_unsol_cb = cbentry->next;
31582305Sstevel 		} else {
31592305Sstevel 			/* remove other entry in list */
31602305Sstevel 			if (p_cbentry)
31612305Sstevel 				p_cbentry->next = cbentry->next;
31622305Sstevel 		}
31632305Sstevel 		kmem_free((void *)cbentry, sizeof (socal_unsol_cb_t));
31642305Sstevel 		DEBUGF(2, (CE_CONT, "socal port %d ULP removed\n", port));
31652305Sstevel 		break;
31662305Sstevel 	}
31672305Sstevel 	mutex_exit(&port_statep->sp_mtx);
31682305Sstevel }
31692305Sstevel 
31702305Sstevel 
31712305Sstevel /*
31722305Sstevel  * static unsigned int
31732305Sstevel  * socal_intr() - this is the interrupt routine for the SOC. Process all
31742305Sstevel  *	possible incoming interrupts from the soc device.
31752305Sstevel  */
31762305Sstevel 
31772305Sstevel static unsigned int
socal_intr(caddr_t arg)31782305Sstevel socal_intr(caddr_t arg)
31792305Sstevel {
31802305Sstevel 	socal_state_t *socalp = (socal_state_t *)arg;
31812305Sstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
31822305Sstevel 	unsigned csr;
31832305Sstevel 	int cause = 0;
31842305Sstevel #if !defined(lint)
31852305Sstevel 	int instance = ddi_get_instance(socalp->dip);
31862305Sstevel #endif
31872305Sstevel 	int i, j, request;
31882305Sstevel 	char full;
31892305Sstevel 	struct fcal_packet *fpkt, *nfpkt;
31902305Sstevel 
31912305Sstevel 	csr = socalreg->socal_csr.w;
31922305Sstevel 	cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
31932305Sstevel 
31942305Sstevel 	DEBUGF(2, (CE_CONT,
3195*7656SSherry.Moore@Sun.COM 	    "socal%d: intr: csr: 0x%x cause: 0x%x\n",
3196*7656SSherry.Moore@Sun.COM 	    instance, csr, cause));
31972305Sstevel 
31982305Sstevel 	if (!cause) {
31992305Sstevel 		socalp->socal_on_intr = 0;
32002305Sstevel 		return (DDI_INTR_UNCLAIMED);
32012305Sstevel 	}
32022305Sstevel 
32032305Sstevel 	socalp->socal_on_intr = 1;
32042305Sstevel 
32052305Sstevel 	while (cause) {
32062305Sstevel 
32072305Sstevel 	/*
32082305Sstevel 	 * Process the unsolicited messages first in case there are some
32092305Sstevel 	 * high priority async events that we should act on.
32102305Sstevel 	 *
32112305Sstevel 	 */
32122305Sstevel 
3213*7656SSherry.Moore@Sun.COM 		if (cause & SOCAL_CSR_RSP_QUE_1) {
3214*7656SSherry.Moore@Sun.COM 			socal_intr_unsolicited(socalp, 1);
32152305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did unsolicited\n", instance));
3216*7656SSherry.Moore@Sun.COM 		}
3217*7656SSherry.Moore@Sun.COM 
3218*7656SSherry.Moore@Sun.COM 		if (cause & SOCAL_CSR_RSP_QUE_0) {
3219*7656SSherry.Moore@Sun.COM 			socal_intr_solicited(socalp, 0);
32202305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did solicited\n", instance));
3221*7656SSherry.Moore@Sun.COM 		}
32222305Sstevel 
32232305Sstevel 	/*
32242305Sstevel 	 * for use with token-only response queues in the future
32252305Sstevel 	 * if (cause & SOCAL_CSR_RSP_QUE_0) {
32262305Sstevel 	 *	socal_intr_solicited(socalp, 0);
32272305Sstevel 	 * }
32282305Sstevel 	 */
32292305Sstevel 
32302305Sstevel 
32312305Sstevel 	/*
32322305Sstevel 	 * Process any request interrupts
32332305Sstevel 	 * We only allow request interrupts when the request
32342305Sstevel 	 * queue is full and we are waiting so we can enque
32352305Sstevel 	 * another command.
32362305Sstevel 	 */
3237*7656SSherry.Moore@Sun.COM 		if ((request = (cause & SOCAL_CSR_HOST_TO_SOCAL)) != 0) {
32382305Sstevel 		socalp->socal_stats.reqq_intrs++;
32392305Sstevel 		for (i = SOCAL_CSR_1ST_H_TO_S, j = 0; j < SOCAL_N_CQS;
3240*7656SSherry.Moore@Sun.COM 		    j++, i <<= 1) {
3241*7656SSherry.Moore@Sun.COM 			if (request & i) {
32422305Sstevel 			socal_kcq_t *kcq = &socalp->request[j];
32432305Sstevel 
32442305Sstevel 			if (kcq->skc_full) {
3245*7656SSherry.Moore@Sun.COM 				mutex_enter(&kcq->skc_mtx);
3246*7656SSherry.Moore@Sun.COM 				full = kcq->skc_full;
3247*7656SSherry.Moore@Sun.COM 				kcq->skc_full = 0;
3248*7656SSherry.Moore@Sun.COM 				while ((fpkt = kcq->skc_overflowh) != NULL) {
32492305Sstevel 				nfpkt = fpkt->fcal_pkt_next;
32502305Sstevel 				fpkt->fcal_pkt_next = NULL;
32512305Sstevel 				kcq->skc_overflowh = nfpkt;
32522305Sstevel 				if (socal_cq_enque(socalp, (socal_port_t *)
32532305Sstevel 				    fpkt->fcal_pkt_cookie,
32542305Sstevel 				    (cqe_t *)&fpkt->fcal_socal_request,
32552305Sstevel 				    j, FCAL_NOSLEEP, NULL, 1) !=
32562305Sstevel 				    FCAL_TRANSPORT_SUCCESS) {
3257*7656SSherry.Moore@Sun.COM 					break;
3258*7656SSherry.Moore@Sun.COM 				}
32592305Sstevel 				}
3260*7656SSherry.Moore@Sun.COM 				if (!kcq->skc_overflowh) {
32612305Sstevel 				if (full & SOCAL_SKC_SLEEP)
3262*7656SSherry.Moore@Sun.COM 					cv_broadcast(&kcq->skc_cv);
32632305Sstevel 
32642305Sstevel 			    /* Disable this queue's intrs */
32652305Sstevel 				DEBUGF(2, (CE_CONT,
32662305Sstevel 				    "socal%d: req que %d overflow cleared\n",
32672305Sstevel 				    instance, j));
32682305Sstevel 				mutex_enter(&socalp->k_imr_mtx);
32692305Sstevel 				socalp->socal_rp->socal_imr =
32702305Sstevel 				    (socalp->socal_k_imr &= ~i);
32712305Sstevel 				mutex_exit(&socalp->k_imr_mtx);
3272*7656SSherry.Moore@Sun.COM 				}
3273*7656SSherry.Moore@Sun.COM 				mutex_exit(&kcq->skc_mtx);
3274*7656SSherry.Moore@Sun.COM 			}
32752305Sstevel 			}
3276*7656SSherry.Moore@Sun.COM 		}
32772305Sstevel 		}
3278*7656SSherry.Moore@Sun.COM 		csr = socalreg->socal_csr.w;
3279*7656SSherry.Moore@Sun.COM 		cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
32802305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d intr: did request queues\n", instance));
32812305Sstevel 
32822305Sstevel 	}
32832305Sstevel 
32842305Sstevel 	socalp->socal_on_intr = 0;
32852305Sstevel 	return (DDI_INTR_CLAIMED);
32862305Sstevel }
32872305Sstevel 
32882305Sstevel static void
socal_intr_solicited(socal_state_t * socalp,uint32_t srq)32892305Sstevel socal_intr_solicited(socal_state_t *socalp, uint32_t srq)
32902305Sstevel {
32912305Sstevel 	socal_kcq_t		*kcq;
32922305Sstevel 	volatile socal_kcq_t	*kcqv;
32932305Sstevel 	soc_response_t		*srp;
32942305Sstevel 	cqe_t			*cqe;
32952305Sstevel 	uint_t			status, i;
32962305Sstevel 	fcal_packet_t		*fcalpkt = NULL;
32972305Sstevel 	soc_header_t		*shp;
32982305Sstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
32992305Sstevel 	caddr_t			src, dst;
33002305Sstevel 	uchar_t			index_in;
33012305Sstevel 	cq_hdr_t		*cq_hdr;
33022305Sstevel 	char			val;
33032305Sstevel 	int			port;
33042305Sstevel 
33052305Sstevel #if defined(DEBUG) && !defined(lint)
33062305Sstevel 	int instance = ddi_get_instance(socalp->dip);
33072305Sstevel #endif
33082305Sstevel 	auto char buf[80];
33092305Sstevel 
33102305Sstevel 	kcq = &socalp->response[srq];
33112305Sstevel 	kcqv = (volatile socal_kcq_t *)kcq;
33122305Sstevel 	DEBUGF(4, (CE_CONT, "socal%d intr_sol: entered \n", instance));
33132305Sstevel 
33142305Sstevel 	/*
33152305Sstevel 	 * Grab lock for request queue.
33162305Sstevel 	 */
33172305Sstevel 	mutex_enter(&kcq->skc_mtx);
33182305Sstevel 
33192305Sstevel 	/*
33202305Sstevel 	 * Process as many response queue entries as we can.
33212305Sstevel 	 */
33222305Sstevel 	cqe = &(kcq->skc_cq[kcqv->skc_out]);
33232305Sstevel 
33242305Sstevel 	index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
33252305Sstevel 
33262305Sstevel 	if (index_in == kcqv->skc_out) {
33272305Sstevel 		socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
33282305Sstevel 		    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
33292305Sstevel 
33302305Sstevel 		/* make sure the write completed */
33312305Sstevel 		i = socalreg->socal_csr.w;
33322305Sstevel 
33332305Sstevel 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
33342305Sstevel 	}
33352305Sstevel 
33362305Sstevel 	kcqv->skc_in = index_in;
33372305Sstevel 
33382305Sstevel 	while (kcqv->skc_out != index_in) {
33392305Sstevel 		/* Find out where the newest entry lives in the queue */
33402305Sstevel 		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
3341*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
33422305Sstevel 
33432305Sstevel 		srp = (soc_response_t *)cqe;
33442305Sstevel 		port = srp->sr_soc_hdr.sh_flags & SOC_PORT_B;
33452305Sstevel 		shp = &srp->sr_soc_hdr;
33462305Sstevel 		cq_hdr = &srp->sr_cqhdr;
33472305Sstevel 		/*
33482305Sstevel 		 * It turns out that on faster CPU's we have a problem where
33492305Sstevel 		 * the soc interrupts us before the response has been DMA'ed
33502305Sstevel 		 * in. This should not happen but does !!. So to workaround
33512305Sstevel 		 * the problem for now, check the sequence # of the response.
33522305Sstevel 		 * If it does not match with what we have, we must be
33532305Sstevel 		 * reading stale data
33542305Sstevel 		 */
33552305Sstevel 		if (cq_hdr->cq_hdr_seqno != kcqv->skc_seqno) {
33562305Sstevel #if defined(DEBUG) && !defined(lint)
33572305Sstevel 			socal_read_stale_data++;
33582305Sstevel #endif
33592305Sstevel 			if (kcq->deferred_intr_timeoutid) {
33602305Sstevel 				mutex_exit(&kcq->skc_mtx);
33612305Sstevel 				return;
33622305Sstevel 			} else {
33632305Sstevel 				kcq->skc_saved_out = kcqv->skc_out;
33642305Sstevel 				kcq->skc_saved_seqno = kcqv->skc_seqno;
33652305Sstevel 				kcq->deferred_intr_timeoutid = timeout(
3366*7656SSherry.Moore@Sun.COM 				    socal_deferred_intr, (caddr_t)kcq,
3367*7656SSherry.Moore@Sun.COM 				    drv_usectohz(10000));
33682305Sstevel 				mutex_exit(&kcq->skc_mtx);
33692305Sstevel 				return;
33702305Sstevel 			}
33712305Sstevel 		}
33722305Sstevel 
33732305Sstevel 		fcalpkt = (fcal_packet_t *)
3374*7656SSherry.Moore@Sun.COM 		    SOCAL_ID_LOOKUP(shp->sh_request_token);
33752305Sstevel 
33762305Sstevel 		if ((socal_core & SOCAL_TAKE_CORE) && ddi_peek8(socalp->dip,
33772305Sstevel 		    (char *)fcalpkt, &val) != DDI_SUCCESS) {
33782305Sstevel 			cmn_err(CE_WARN, "bad token = %p\n", (void *)fcalpkt);
33792305Sstevel 			mutex_exit(&kcq->skc_mtx);
33802305Sstevel 			socal_take_core(socalp);
33812305Sstevel 		}
33822305Sstevel 
33832305Sstevel 		if ((fcalpkt == (fcal_packet_t *)NULL) ||
3384*7656SSherry.Moore@Sun.COM 		    (fcalpkt->fcal_magic != FCALP_MAGIC)) {
3385*7656SSherry.Moore@Sun.COM 			(void) sprintf(buf, "!invalid FC packet; \n\
3386*7656SSherry.Moore@Sun.COM 			    in, out, seqno = 0x%x, 0x%x, 0x%x\n",
3387*7656SSherry.Moore@Sun.COM 			    kcqv->skc_in, kcqv->skc_out, kcqv->skc_seqno);
3388*7656SSherry.Moore@Sun.COM 			socal_disp_err(socalp, CE_WARN, "link.4060", buf);
3389*7656SSherry.Moore@Sun.COM 			DEBUGF(4, (CE_CONT,
3390*7656SSherry.Moore@Sun.COM 			    "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
33912305Sstevel 			    socalreg->socal_cr.w,
33922305Sstevel 			    socalreg->socal_sae.w,
33932305Sstevel 			    socalreg->socal_csr.w,
33942305Sstevel 			    socalreg->socal_imr));
33952305Sstevel 		/*
33962305Sstevel 		 * Update response queue ptrs and soc registers.
33972305Sstevel 		 */
3398*7656SSherry.Moore@Sun.COM 			kcqv->skc_out++;
3399*7656SSherry.Moore@Sun.COM 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3400*7656SSherry.Moore@Sun.COM 				kcqv->skc_out = 0;
3401*7656SSherry.Moore@Sun.COM 				kcqv->skc_seqno++;
3402*7656SSherry.Moore@Sun.COM 			}
34032305Sstevel 
34042305Sstevel 		} else {
34052305Sstevel 
34062305Sstevel 			DEBUGF(2, (CE_CONT, "packet 0x%p complete\n",
3407*7656SSherry.Moore@Sun.COM 			    fcalpkt));
34082305Sstevel 			status = srp->sr_soc_status;
34092305Sstevel 			fcalpkt->fcal_pkt_status = status;
34102305Sstevel 			DEBUGF(2, (CE_CONT, "SOC status: 0x%x\n", status));
34112305Sstevel 			/*
34122305Sstevel 			 * map soc status codes to
34132305Sstevel 			 * transport status codes
34142305Sstevel 			 */
34152305Sstevel 
34162305Sstevel 			ASSERT((fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)
3417*7656SSherry.Moore@Sun.COM 			    == 0);
34182305Sstevel 			mutex_enter(&socalp->abort_mtx);
34192305Sstevel 			fcalpkt->fcal_pkt_flags |= FCFLAG_COMPLETE;
34202305Sstevel 			mutex_exit(&socalp->abort_mtx);
34212305Sstevel 
34222305Sstevel 			/*
34232305Sstevel 			 * Copy the response frame header (if there is one)
34242305Sstevel 			 * so that the upper levels can use it.  Note that,
34252305Sstevel 			 * for now, we'll copy the header only if there was
34262305Sstevel 			 * some sort of non-OK status, to save the PIO reads
34272305Sstevel 			 * required to get the header from the host adapter's
34282305Sstevel 			 * xRAM.
34292305Sstevel 			 */
34302305Sstevel 			if (((status != FCAL_STATUS_OK) ||
34312305Sstevel 			    (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags
34322305Sstevel 			    & SOC_RESP_HEADER)) &&
34332305Sstevel 			    (srp->sr_soc_hdr.sh_flags & SOC_FC_HEADER)) {
34342305Sstevel 				src = (caddr_t)&srp->sr_fc_frame_hdr;
34352305Sstevel 				dst = (caddr_t)&fcalpkt->fcal_resp_hdr;
34362305Sstevel 				bcopy(src, dst, sizeof (fc_frame_header_t));
34372305Sstevel 				fcalpkt->fcal_pkt_flags |= FCFLAG_RESP_HEADER;
34382305Sstevel 				i = srp->sr_soc_hdr.sh_flags & SOC_PORT_B ?
34392305Sstevel 				    1 : 0;
34402305Sstevel 				if ((status != FCAL_STATUS_OK) &&
3441*7656SSherry.Moore@Sun.COM 				    (status <= FCAL_STATUS_MAX_STATUS)) {
34422305Sstevel 					socalp->socal_stats.pstats[i].
3443*7656SSherry.Moore@Sun.COM 					    resp_status[status]++;
34442305Sstevel 				} else {
34452305Sstevel 					socalp->socal_stats.pstats[i].
3446*7656SSherry.Moore@Sun.COM 					    resp_status[FCAL_STATUS_ERROR]++;
34472305Sstevel 				}
34482305Sstevel 			} else if (status == FCAL_STATUS_OK) {
3449*7656SSherry.Moore@Sun.COM 				fcalpkt->fcal_socal_request.
3450*7656SSherry.Moore@Sun.COM 				    sr_soc_hdr.sh_byte_cnt =
3451*7656SSherry.Moore@Sun.COM 				    shp->sh_byte_cnt;
34522305Sstevel 			}
34532305Sstevel 			fcalpkt->fcal_diag_status =
34542305Sstevel 			    (uint32_t)srp->sr_dataseg.fc_base;
34552305Sstevel 			fcalpkt->fcal_ncmds = srp->sr_ncmds;
34562305Sstevel 
34572305Sstevel 			/*
34582305Sstevel 			 * Update response queue ptrs and soc registers.
34592305Sstevel 			 */
34602305Sstevel 			kcqv->skc_out++;
34612305Sstevel 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
34622305Sstevel 				kcqv->skc_out = 0;
34632305Sstevel 				kcqv->skc_seqno++;
34642305Sstevel 			}
34652305Sstevel 
34662305Sstevel 			/* For incmplt DMA offline loop by loopback */
34672305Sstevel 			if (fcalpkt->fcal_pkt_status ==
3468*7656SSherry.Moore@Sun.COM 			    FCAL_STATUS_INCOMPLETE_DMA_ERR) {
34692305Sstevel 				socal_port_t	*port_statep;
34702305Sstevel 				uint_t		r;
34712305Sstevel 
34722305Sstevel 				/*
34732305Sstevel 				 * Give up the mutex to avoid a deadlock
34742305Sstevel 				 * with the loopback routine.
34752305Sstevel 				 */
34762305Sstevel 				mutex_exit(&kcq->skc_mtx);
34772305Sstevel 
34782305Sstevel 				port_statep = &socalp->port_state[port];
34792305Sstevel 				mutex_enter(&port_statep->sp_mtx);
34802305Sstevel 				if (port_statep->sp_status &
34812305Sstevel 				    PORT_DISABLED) {
34822305Sstevel 					/* Already disabled */
34832305Sstevel 					mutex_exit(&port_statep->sp_mtx);
34842305Sstevel 				} else {
34852305Sstevel 					port_statep->sp_status |=
34862305Sstevel 					    PORT_DISABLED;
34872305Sstevel 					mutex_exit(&port_statep->sp_mtx);
34882305Sstevel 					(void) socal_diag_request(
34892305Sstevel 					    (void *)socalp, port,
34902305Sstevel 					    &r, SOC_DIAG_INT_LOOP);
34912305Sstevel 				}
34922305Sstevel 				/* reacquire mutex */
34932305Sstevel 				mutex_enter(&kcq->skc_mtx);
34942305Sstevel 			}
34952305Sstevel 
34962305Sstevel 			/*
34972305Sstevel 			 * Complete the packet *ONLY* if it not being aborted
34982305Sstevel 			 * or the abort has already completed.  Otherwise it is
34992305Sstevel 			 * not safe to free the ID.
35002305Sstevel 			 */
35012305Sstevel 			mutex_enter(&socalp->abort_mtx);
35022305Sstevel 			if (!(fcalpkt->fcal_pkt_flags & FCFLAG_ABORTING)) {
35032305Sstevel 				/*
35042305Sstevel 				 * Call the completion routine
35052305Sstevel 				 */
35062305Sstevel 				SOCAL_ID_FREE(shp->sh_request_token);
35072305Sstevel 				if (fcalpkt->fcal_pkt_comp != NULL) {
35082305Sstevel 					fcalpkt->fcal_cmd_state |=
35092305Sstevel 					    FCAL_CMD_COMPLETE;
35102305Sstevel 
35112305Sstevel 					/*
35122305Sstevel 					 * Give up the mutex to avoid a
35132305Sstevel 					 * deadlock with the callback routine.
35142305Sstevel 					 */
35152305Sstevel 					mutex_exit(&socalp->abort_mtx);
35162305Sstevel 					mutex_exit(&kcq->skc_mtx);
35172305Sstevel 
35182305Sstevel 					/* callback */
35192305Sstevel 					(*fcalpkt->fcal_pkt_comp)(fcalpkt);
35202305Sstevel 
35212305Sstevel 					/* reacquire mutex */
35222305Sstevel 					mutex_enter(&kcq->skc_mtx);
35232305Sstevel 				} else {
35242305Sstevel 					fcalpkt->fcal_cmd_state |=
35252305Sstevel 					    FCAL_CMD_COMPLETE;
35262305Sstevel 					mutex_exit(&socalp->abort_mtx);
35272305Sstevel 				}
35282305Sstevel 			} else {
35292305Sstevel 				mutex_exit(&socalp->abort_mtx);
35302305Sstevel 			}
35312305Sstevel 		}
35322305Sstevel 
35332305Sstevel 
35342305Sstevel 		if (kcq->skc_cq == NULL)
35352305Sstevel 			/*
35362305Sstevel 			 * This action averts a potential PANIC scenario
35372305Sstevel 			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
35382305Sstevel 			 * when we let it go, to call our completion routine,
35392305Sstevel 			 * and "initialized" the response queue.  We exit our
35402305Sstevel 			 * processing loop here, thereby averting a PANIC due
35412305Sstevel 			 * to a NULL de-reference from the response queue.
35422305Sstevel 			 *
35432305Sstevel 			 * Note that this is an interim measure that needs
35442305Sstevel 			 * to be revisited when this driver is next revised
35452305Sstevel 			 * for enhanced performance.
35462305Sstevel 			 */
35472305Sstevel 			break;
35482305Sstevel 
35492305Sstevel 		/*
35502305Sstevel 		 * We need to re-read the input and output pointers in
35512305Sstevel 		 * case a polling routine should process some entries
35522305Sstevel 		 * from the response queue while we're doing a callback
35532305Sstevel 		 * routine with the response queue mutex dropped.
35542305Sstevel 		 */
35552305Sstevel 		cqe = &(kcq->skc_cq[kcqv->skc_out]);
35562305Sstevel 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
35572305Sstevel 
35582305Sstevel 		/*
35592305Sstevel 		 * Mess around with the hardware if we think we've run out
35602305Sstevel 		 * of entries in the queue, just to make sure we've read
35612305Sstevel 		 * all entries that are available.
35622305Sstevel 		 */
35632305Sstevel 
3564*7656SSherry.Moore@Sun.COM 		socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
3565*7656SSherry.Moore@Sun.COM 		    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
35662305Sstevel 
35672305Sstevel 		/* Make sure the csr write has completed */
3568*7656SSherry.Moore@Sun.COM 		i = socalreg->socal_csr.w;
3569*7656SSherry.Moore@Sun.COM 		DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
35702305Sstevel 
35712305Sstevel 		/*
35722305Sstevel 		 * Update our idea of where the host adapter has placed
35732305Sstevel 		 * the most recent entry in the response queue and resync
35742305Sstevel 		 * the response queue
35752305Sstevel 		 */
3576*7656SSherry.Moore@Sun.COM 		index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
35772305Sstevel 
35782305Sstevel 		kcqv->skc_in = index_in;
35792305Sstevel 	}
35802305Sstevel 
35812305Sstevel 	/* Drop lock for request queue. */
35822305Sstevel 	mutex_exit(&kcq->skc_mtx);
35832305Sstevel }
35842305Sstevel 
35852305Sstevel /*
35862305Sstevel  * Function name : socal_intr_unsolicited()
35872305Sstevel  *
35882305Sstevel  * Return Values : none
35892305Sstevel  *
35902305Sstevel  * Description	 : Processes entries in the unsolicited response
35912305Sstevel  *		   queue
35922305Sstevel  *
35932305Sstevel  *	The SOC+ will give us an unsolicited response
35942305Sstevel  *	whenever its status changes: OFFLINE, ONLINE,
35952305Sstevel  *	or in response to a packet arriving from an originator.
35962305Sstevel  *
35972305Sstevel  *	When message requests come in they will be placed in our
35982305Sstevel  *	buffer queue or in the next "inline" packet by the SOC hardware.
35992305Sstevel  *
36002305Sstevel  * Context	: Unsolicited interrupts must be masked
36012305Sstevel  */
36022305Sstevel 
36032305Sstevel static void
socal_intr_unsolicited(socal_state_t * socalp,uint32_t urq)36042305Sstevel socal_intr_unsolicited(socal_state_t *socalp, uint32_t urq)
36052305Sstevel {
36062305Sstevel 	socal_kcq_t		*kcq;
36072305Sstevel 	volatile socal_kcq_t	*kcqv;
36082305Sstevel 	soc_response_t		*srp;
36092305Sstevel 	volatile cqe_t		*cqe;
36102305Sstevel 	int			port;
36112305Sstevel 	register uchar_t		t_index, t_seqno;
36122305Sstevel 	register volatile socal_reg_t *socalreg = socalp->socal_rp;
36132305Sstevel 	volatile cqe_t		*cqe_cont = NULL;
36142305Sstevel 	uint_t			i;
36152305Sstevel 	int			hdr_count;
36162305Sstevel 	int			status;
36172305Sstevel 	ushort_t		flags;
36182305Sstevel 	auto char		buf[256];
36192305Sstevel 	socal_port_t		*port_statep;
36202305Sstevel #if defined(DEBUG) && !defined(lint)
36212305Sstevel 	int			instance = ddi_get_instance(socalp->dip);
36222305Sstevel #endif
36232305Sstevel 	uchar_t			index_in;
36242305Sstevel 	socal_unsol_cb_t	*cblist;
36252305Sstevel 
36262305Sstevel 	kcq = &socalp->response[urq];
36272305Sstevel 	kcqv = (volatile socal_kcq_t *)kcq;
36282305Sstevel 
36292305Sstevel 	/*
36302305Sstevel 	 * Grab lock for response queue.
36312305Sstevel 	 */
36322305Sstevel 	mutex_enter(&kcq->skc_mtx);
36332305Sstevel 
36342305Sstevel 	cqe = (volatile cqe_t *)&(kcq->skc_cq[kcqv->skc_out]);
36352305Sstevel 
36362305Sstevel 	index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
36372305Sstevel 
36382305Sstevel 	kcqv->skc_in = index_in;
36392305Sstevel 
36402305Sstevel 	while (kcqv->skc_out != index_in) {
36412305Sstevel 		(void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
3642*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
36432305Sstevel 
36442305Sstevel 		/* Check for continuation entries */
36452305Sstevel 		if ((hdr_count = cqe->cqe_hdr.cq_hdr_count) != 1) {
36462305Sstevel 
3647*7656SSherry.Moore@Sun.COM 			t_seqno = kcqv->skc_seqno;
3648*7656SSherry.Moore@Sun.COM 			t_index = kcqv->skc_out + hdr_count;
3649*7656SSherry.Moore@Sun.COM 
3650*7656SSherry.Moore@Sun.COM 			i = index_in;
3651*7656SSherry.Moore@Sun.COM 			if (kcqv->skc_out > index_in)
36522305Sstevel 			i += kcq->skc_last_index + 1;
36532305Sstevel 
36542305Sstevel 		/*
36552305Sstevel 		 * If we think the continuation entries haven't yet
36562305Sstevel 		 * arrived, try once more before giving up
36572305Sstevel 		 */
3658*7656SSherry.Moore@Sun.COM 			if (i < t_index) {
36592305Sstevel 
36602305Sstevel 			socalreg->socal_csr.w =
36612305Sstevel 			    ((kcqv->skc_out << 24) |
36622305Sstevel 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
36632305Sstevel 
36642305Sstevel 			/* Make sure the csr write has completed */
36652305Sstevel 			i = socalreg->socal_csr.w;
36662305Sstevel 
36672305Sstevel 			/*
36682305Sstevel 			 * Update our idea of where the host adapter has placed
36692305Sstevel 			 * the most recent entry in the response queue
36702305Sstevel 			 */
36712305Sstevel 			i = index_in = SOCAL_RESPONSEQ_INDEX(urq,
3672*7656SSherry.Moore@Sun.COM 			    socalreg->socal_rspp.w);
36732305Sstevel 			if (kcqv->skc_out > index_in)
3674*7656SSherry.Moore@Sun.COM 				i += kcq->skc_last_index + 1;
36752305Sstevel 
36762305Sstevel 			/*
36772305Sstevel 			 * Exit if the continuation entries haven't yet
36782305Sstevel 			 * arrived
36792305Sstevel 			 */
36802305Sstevel 			if (i < t_index)
3681*7656SSherry.Moore@Sun.COM 				break;
3682*7656SSherry.Moore@Sun.COM 			}
3683*7656SSherry.Moore@Sun.COM 
3684*7656SSherry.Moore@Sun.COM 			if (t_index > kcq->skc_last_index) {
36852305Sstevel 			t_seqno++;
36862305Sstevel 			t_index &= kcq->skc_last_index;
3687*7656SSherry.Moore@Sun.COM 			}
3688*7656SSherry.Moore@Sun.COM 
3689*7656SSherry.Moore@Sun.COM 			cqe_cont = (volatile cqe_t *)
3690*7656SSherry.Moore@Sun.COM 			    &(kcq->skc_cq[t_index ? t_index - 1 :
3691*7656SSherry.Moore@Sun.COM 			    kcq->skc_last_index]);
36922305Sstevel 
36932305Sstevel 
36942305Sstevel 		    /* A cq_hdr_count > 2 is illegal; throw away the response */
36952305Sstevel 
36962305Sstevel 		/*
36972305Sstevel 		 * XXX - should probably throw out as many entries as the
36982305Sstevel 		 * hdr_cout tells us there are
36992305Sstevel 		 */
3700*7656SSherry.Moore@Sun.COM 			if (hdr_count != 2) {
37012305Sstevel 			socal_disp_err(socalp, CE_WARN, "driver.4030",
37022305Sstevel 			    "!too many continuation entries");
37032305Sstevel 			DEBUGF(4, (CE_CONT,
3704*7656SSherry.Moore@Sun.COM 			    "socal%d: soc+ unsolicited entry count = %d\n",
3705*7656SSherry.Moore@Sun.COM 			    instance, cqe->cqe_hdr.cq_hdr_count));
37062305Sstevel 
37072305Sstevel 			if ((++t_index & kcq->skc_last_index) == 0) {
3708*7656SSherry.Moore@Sun.COM 				t_index = 0;
3709*7656SSherry.Moore@Sun.COM 				t_seqno++;
37102305Sstevel 			}
37112305Sstevel 			kcqv->skc_out = t_index;
37122305Sstevel 			kcqv->skc_seqno = t_seqno;
37132305Sstevel 
37142305Sstevel 			cqe = &(kcq->skc_cq[kcqv->skc_out]);
37152305Sstevel 			cqe_cont = NULL;
37162305Sstevel 			continue;
3717*7656SSherry.Moore@Sun.COM 			}
37182305Sstevel 		}
37192305Sstevel 
37202305Sstevel 		/*
37212305Sstevel 		 * Update unsolicited response queue ptrs
37222305Sstevel 		 */
37232305Sstevel 		kcqv->skc_out++;
37242305Sstevel 		if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
37252305Sstevel 			kcqv->skc_out = 0;
37262305Sstevel 			kcqv->skc_seqno++;
37272305Sstevel 		}
37282305Sstevel 
37292305Sstevel 		if (cqe_cont != NULL) {
3730*7656SSherry.Moore@Sun.COM 			kcqv->skc_out++;
3731*7656SSherry.Moore@Sun.COM 			if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3732*7656SSherry.Moore@Sun.COM 				kcqv->skc_out = 0;
3733*7656SSherry.Moore@Sun.COM 				kcqv->skc_seqno++;
3734*7656SSherry.Moore@Sun.COM 			}
37352305Sstevel 		}
37362305Sstevel 
37372305Sstevel 		if (index_in == kcqv->skc_out) {
3738*7656SSherry.Moore@Sun.COM 			socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
3739*7656SSherry.Moore@Sun.COM 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
37402305Sstevel 
37412305Sstevel 		/* Make sure the csr write has completed */
3742*7656SSherry.Moore@Sun.COM 			i = socalreg->socal_csr.w;
37432305Sstevel 		}
37442305Sstevel 
37452305Sstevel 		srp = (soc_response_t *)cqe;
37462305Sstevel 		flags = srp->sr_soc_hdr.sh_flags;
37472305Sstevel 		port = flags & SOC_PORT_B;
37482305Sstevel 		port_statep = &socalp->port_state[port];
37492305Sstevel 
37502305Sstevel 		/*
37512305Sstevel 		 * XXX need to deal buffer pool entries here
37522305Sstevel 		 */
37532305Sstevel 		switch (flags & ~SOC_PORT_B) {
37542305Sstevel 		case SOC_UNSOLICITED | SOC_FC_HEADER:
37552305Sstevel 
3756*7656SSherry.Moore@Sun.COM 			srp = (soc_response_t *)cqe;
3757*7656SSherry.Moore@Sun.COM 
3758*7656SSherry.Moore@Sun.COM 			switch (srp->sr_fc_frame_hdr.r_ctl & R_CTL_ROUTING) {
3759*7656SSherry.Moore@Sun.COM 			case R_CTL_EXTENDED_SVC:
37602305Sstevel 			/*
37612305Sstevel 			 * Extended Link Services frame received
37622305Sstevel 			 */
37632305Sstevel 			socalp->socal_stats.pstats[port].els_rcvd++;
37642305Sstevel 			socal_us_els(socalp, (cqe_t *)cqe, (caddr_t)cqe_cont);
37652305Sstevel 
37662305Sstevel 			/* do callbacks to any interested ULPs */
37672305Sstevel 			mutex_enter(&port_statep->sp_mtx);
37682305Sstevel 			for (cblist = port_statep->sp_unsol_cb; cblist;
3769*7656SSherry.Moore@Sun.COM 			    cblist = cblist->next) {
37702305Sstevel 				if (cblist->els_cb) {
3771*7656SSherry.Moore@Sun.COM 					mutex_exit(&port_statep->sp_mtx);
3772*7656SSherry.Moore@Sun.COM 					mutex_exit(&kcq->skc_mtx);
3773*7656SSherry.Moore@Sun.COM 					cblist->els_cb(cblist->arg,
3774*7656SSherry.Moore@Sun.COM 					    (cqe_t *)cqe,
3775*7656SSherry.Moore@Sun.COM 					    (caddr_t)cqe_cont);
3776*7656SSherry.Moore@Sun.COM 					mutex_enter(&kcq->skc_mtx);
3777*7656SSherry.Moore@Sun.COM 					mutex_enter(&port_statep->sp_mtx);
37782305Sstevel 				}
37792305Sstevel 			}
37802305Sstevel 			mutex_exit(&port_statep->sp_mtx);
37812305Sstevel 			break;
3782*7656SSherry.Moore@Sun.COM 			case R_CTL_BASIC_SVC:
37832305Sstevel 			(void) sprintf(buf,
37842305Sstevel 			    "!unsupported Link Service command: 0x%x",
3785*7656SSherry.Moore@Sun.COM 			    srp->sr_fc_frame_hdr.type);
37862305Sstevel 			socal_disp_err(socalp, CE_WARN, "link.4020", buf);
37872305Sstevel 			break;
3788*7656SSherry.Moore@Sun.COM 			case R_CTL_DEVICE_DATA:
37892305Sstevel 			switch (srp->sr_fc_frame_hdr.type) {
37902305Sstevel 			default:
3791*7656SSherry.Moore@Sun.COM 				mutex_enter(&port_statep->sp_mtx);
3792*7656SSherry.Moore@Sun.COM 				status = 1;
3793*7656SSherry.Moore@Sun.COM 				for (cblist = port_statep->sp_unsol_cb; cblist;
3794*7656SSherry.Moore@Sun.COM 				    cblist = cblist->next) {
37952305Sstevel 				if (cblist->data_cb &&
37962305Sstevel 				    (cblist->type ==
37972305Sstevel 				    srp->sr_fc_frame_hdr.type)) {
37982305Sstevel 					mutex_exit(&port_statep->sp_mtx);
37992305Sstevel 					mutex_exit(&kcq->skc_mtx);
38002305Sstevel 					cblist->data_cb(cblist->arg,
38012305Sstevel 					    (cqe_t *)cqe, (caddr_t)cqe_cont);
38022305Sstevel 					mutex_enter(&kcq->skc_mtx);
38032305Sstevel 					mutex_enter(&port_statep->sp_mtx);
38042305Sstevel 					status = 0;
38052305Sstevel 				}
3806*7656SSherry.Moore@Sun.COM 				}
3807*7656SSherry.Moore@Sun.COM 				mutex_exit(&port_statep->sp_mtx);
3808*7656SSherry.Moore@Sun.COM 
3809*7656SSherry.Moore@Sun.COM 				if (status == 0)
38102305Sstevel 				break;
38112305Sstevel 
3812*7656SSherry.Moore@Sun.COM 				(void) sprintf(buf,
3813*7656SSherry.Moore@Sun.COM 				    "!unknown FC-4 command: 0x%x",
3814*7656SSherry.Moore@Sun.COM 				    srp->sr_fc_frame_hdr.type);
3815*7656SSherry.Moore@Sun.COM 				socal_disp_err(socalp, CE_WARN,
3816*7656SSherry.Moore@Sun.COM 				    "link.4030", buf);
3817*7656SSherry.Moore@Sun.COM 				break;
38182305Sstevel 			}
38192305Sstevel 			break;
3820*7656SSherry.Moore@Sun.COM 			default:
38212305Sstevel 			(void) sprintf(buf, "!unsupported FC frame R_CTL: 0x%x",
38222305Sstevel 			    srp->sr_fc_frame_hdr.r_ctl);
38232305Sstevel 			socal_disp_err(socalp, CE_WARN, "link.4040", buf);
38242305Sstevel 			break;
3825*7656SSherry.Moore@Sun.COM 			}
3826*7656SSherry.Moore@Sun.COM 			break;
38272305Sstevel 
38282305Sstevel 		case SOC_STATUS: {
38292305Sstevel 
38302305Sstevel 			/*
38312305Sstevel 			 * Note that only the lsbyte of the status has
38322305Sstevel 			 * interesting information...
38332305Sstevel 			 */
38342305Sstevel 			status = srp->sr_soc_status;
38352305Sstevel 
38362305Sstevel 			switch (status) {
38372305Sstevel 
38382305Sstevel 			case FCAL_STATUS_ONLINE:
38392305Sstevel 				(void) sprintf(buf,
38402305Sstevel 				"!port %d: Fibre Channel is ONLINE\n", port);
38412305Sstevel 				socal_disp_err(socalp, CE_CONT, "link.6010",
3842*7656SSherry.Moore@Sun.COM 				    buf);
38432305Sstevel 				mutex_enter(&port_statep->sp_mtx);
38442305Sstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38452305Sstevel 				port_statep->sp_status |= PORT_ONLINE;
38462305Sstevel 				mutex_exit(&port_statep->sp_mtx);
38472305Sstevel 				socalp->socal_stats.pstats[port].onlines++;
38482305Sstevel 				DEBUGF(4, (CE_CONT,
3849*7656SSherry.Moore@Sun.COM 				    "socal%d intr_unsol: ONLINE intr\n",
3850*7656SSherry.Moore@Sun.COM 				    instance));
38512305Sstevel 				break;
38522305Sstevel 
38532305Sstevel 			case FCAL_STATUS_LOOP_ONLINE:
38542305Sstevel 				(void) sprintf(buf,
38552305Sstevel 				"!port %d: Fibre Channel Loop is ONLINE\n",
3856*7656SSherry.Moore@Sun.COM 				    port);
38572305Sstevel 				socal_disp_err(socalp, CE_CONT, "link.6010",
3858*7656SSherry.Moore@Sun.COM 				    buf);
38592305Sstevel 				mutex_enter(&port_statep->sp_mtx);
38602305Sstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38612305Sstevel 				port_statep->sp_status |= PORT_ONLINE_LOOP;
38622305Sstevel 				mutex_exit(&port_statep->sp_mtx);
38632305Sstevel 				socalp->socal_stats.pstats[port].online_loops++;
38642305Sstevel 				DEBUGF(4, (CE_CONT,
38652305Sstevel 				    "socal%d intr_unsol: ONLINE-LOOP intr\n",
38662305Sstevel 				    instance));
38672305Sstevel 				break;
38682305Sstevel 
38692305Sstevel 			case FCAL_STATUS_ERR_OFFLINE:
38702305Sstevel 				/*
38712305Sstevel 				 * SOC and Responder will both flush
38722305Sstevel 				 * all active commands.
38732305Sstevel 				 * So I don't have to do anything
38742305Sstevel 				 * until it comes back online.
38752305Sstevel 				 */
38762305Sstevel 				(void) sprintf(buf,
38772305Sstevel 				"!port %d: Fibre Channel is OFFLINE\n", port);
38782305Sstevel 				socal_disp_err(socalp, CE_CONT, "link.5010",
3879*7656SSherry.Moore@Sun.COM 				    buf);
38802305Sstevel 
38812305Sstevel 				mutex_enter(&port_statep->sp_mtx);
38822305Sstevel 				port_statep->sp_status &= ~PORT_STATUS_MASK;
38832305Sstevel 				port_statep->sp_status |= PORT_OFFLINE;
38842305Sstevel 				port_statep->sp_lilpmap_valid = 0;
38852305Sstevel 				mutex_exit(&port_statep->sp_mtx);
38862305Sstevel 				socalp->socal_stats.pstats[port].offlines++;
38872305Sstevel 				DEBUGF(4, (CE_CONT,
38882305Sstevel 				    "socal%d intr_unsol: OFFLINE intr\n",
38892305Sstevel 				    instance));
38902305Sstevel 
38912305Sstevel 				break;
38922305Sstevel 			default:
38932305Sstevel 				(void) sprintf(buf, "!unknown status: 0x%x\n",
3894*7656SSherry.Moore@Sun.COM 				    status);
38952305Sstevel 				socal_disp_err(socalp, CE_WARN, "link.3020",
3896*7656SSherry.Moore@Sun.COM 				    buf);
38972305Sstevel 			}
38982305Sstevel 			mutex_exit(&kcq->skc_mtx);
38992305Sstevel 			mutex_enter(&port_statep->sp_mtx);
39002305Sstevel 			for (cblist = port_statep->sp_unsol_cb; cblist;
3901*7656SSherry.Moore@Sun.COM 			    cblist = cblist->next) {
39022305Sstevel 				if (cblist->statec_cb) {
3903*7656SSherry.Moore@Sun.COM 					mutex_exit(&port_statep->sp_mtx);
3904*7656SSherry.Moore@Sun.COM 					(*cblist->statec_cb)(cblist->arg,
3905*7656SSherry.Moore@Sun.COM 					    status);
3906*7656SSherry.Moore@Sun.COM 					mutex_enter(&port_statep->sp_mtx);
39072305Sstevel 				}
39082305Sstevel 			}
39092305Sstevel 			mutex_exit(&port_statep->sp_mtx);
39102305Sstevel 			if (status == FCAL_STATUS_ERR_OFFLINE) {
39112305Sstevel 				socal_flush_overflowq(socalp, port,
39122305Sstevel 				    CQ_REQUEST_0);
39132305Sstevel 				socal_flush_overflowq(socalp, port,
39142305Sstevel 				    CQ_REQUEST_1);
39152305Sstevel 			}
39162305Sstevel 			mutex_enter(&kcq->skc_mtx);
39172305Sstevel 			break;
39182305Sstevel 		}
39192305Sstevel 		default:
39202305Sstevel 			(void) sprintf(buf, "!unexpected state: flags: 0x%x\n",
3921*7656SSherry.Moore@Sun.COM 			    flags);
39222305Sstevel 			socal_disp_err(socalp, CE_WARN, "link.4050", buf);
39232305Sstevel 			DEBUGF(4, (CE_CONT,
3924*7656SSherry.Moore@Sun.COM 			    "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3925*7656SSherry.Moore@Sun.COM 			    socalp->socal_rp->socal_cr.w,
3926*7656SSherry.Moore@Sun.COM 			    socalp->socal_rp->socal_sae.w,
3927*7656SSherry.Moore@Sun.COM 			    socalp->socal_rp->socal_csr.w,
3928*7656SSherry.Moore@Sun.COM 			    socalp->socal_rp->socal_imr));
39292305Sstevel 		}
39302305Sstevel 
39312305Sstevel 
39322305Sstevel 		if (kcq->skc_cq == NULL)
39332305Sstevel 			/*
39342305Sstevel 			 * This action averts a potential PANIC scenario
39352305Sstevel 			 * where the SUSPEND code flow grabbed the kcq->skc_mtx
39362305Sstevel 			 * when we let it go, to call our completion routine,
39372305Sstevel 			 * and "initialized" the response queue.  We exit our
39382305Sstevel 			 * processing loop here, thereby averting a PANIC due
39392305Sstevel 			 * to a NULL de-reference from the response queue.
39402305Sstevel 			 *
39412305Sstevel 			 * Note that this is an interim measure that needs
39422305Sstevel 			 * to be revisited when this driver is next revised
39432305Sstevel 			 * for enhanced performance.
39442305Sstevel 			 */
39452305Sstevel 			break;
39462305Sstevel 
39472305Sstevel 		/*
39482305Sstevel 		 * We need to re-read the input and output pointers in
39492305Sstevel 		 * case a polling routine should process some entries
39502305Sstevel 		 * from the response queue while we're doing a callback
39512305Sstevel 		 * routine with the response queue mutex dropped.
39522305Sstevel 		 */
39532305Sstevel 		cqe = &(kcq->skc_cq[kcqv->skc_out]);
39542305Sstevel 		index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
39552305Sstevel 		cqe_cont = NULL;
39562305Sstevel 
39572305Sstevel 		/*
39582305Sstevel 		 * Mess around with the hardware if we think we've run out
39592305Sstevel 		 * of entries in the queue, just to make sure we've read
39602305Sstevel 		 * all entries that are available.
39612305Sstevel 		 */
39622305Sstevel 		if (index_in == kcqv->skc_out) {
39632305Sstevel 
3964*7656SSherry.Moore@Sun.COM 			socalreg->socal_csr.w =
3965*7656SSherry.Moore@Sun.COM 			    ((kcqv->skc_out << 24) |
3966*7656SSherry.Moore@Sun.COM 			    (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
39672305Sstevel 
39682305Sstevel 		/* Make sure the csr write has completed */
3969*7656SSherry.Moore@Sun.COM 			i = socalreg->socal_csr.w;
39702305Sstevel 
39712305Sstevel 		/*
39722305Sstevel 		 * Update our idea of where the host adapter has placed
39732305Sstevel 		 * the most recent entry in the response queue
39742305Sstevel 		 */
3975*7656SSherry.Moore@Sun.COM 			index_in =
3976*7656SSherry.Moore@Sun.COM 			    SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
39772305Sstevel 		}
39782305Sstevel 
39792305Sstevel 		socalp->socal_stats.pstats[port].unsol_resps++;
39802305Sstevel 
39812305Sstevel 		kcqv->skc_in = index_in;
39822305Sstevel 
39832305Sstevel 	}
39842305Sstevel 
39852305Sstevel 	/* Release lock for response queue. */
39862305Sstevel 	mutex_exit(&kcq->skc_mtx);
39872305Sstevel }
39882305Sstevel 
39892305Sstevel /*
39902305Sstevel  * socal_us_els() - This function handles unsolicited extended link
39912305Sstevel  *	service responses received from the soc.
39922305Sstevel  */
39932305Sstevel static void
socal_us_els(socal_state_t * socalp,cqe_t * cqe,caddr_t payload)39942305Sstevel socal_us_els(socal_state_t *socalp, cqe_t *cqe, caddr_t payload)
39952305Sstevel {
39962305Sstevel 	soc_response_t	*srp = (soc_response_t *)cqe;
39972305Sstevel 	els_payload_t	*els = (els_payload_t *)payload;
39982305Sstevel 	int	i;
39992305Sstevel 	char   *bp;
40002305Sstevel 	auto	char buf[256];
40012305Sstevel 
40022305Sstevel 	/*
40032305Sstevel 	 * There should be a CQE continuation entry for all
40042305Sstevel 	 * extended link services
40052305Sstevel 	 */
40062305Sstevel 	if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
4007*7656SSherry.Moore@Sun.COM 		socal_disp_err(socalp, CE_WARN, "link.4010",
40082305Sstevel 		"!incomplete continuation entry");
4009*7656SSherry.Moore@Sun.COM 		return;
40102305Sstevel 	}
40112305Sstevel 
40122305Sstevel 	/* Quietly impose a maximum byte count */
40132305Sstevel 	if (i > SOC_CQE_PAYLOAD)
40142305Sstevel 		i = SOC_CQE_PAYLOAD;
40152305Sstevel 	i -= sizeof (union els_cmd_u);
40162305Sstevel 
40172305Sstevel 	/*
40182305Sstevel 	 * Decode the LS_Command code
40192305Sstevel 	 */
40202305Sstevel 	switch (els->els_cmd.c.ls_command) {
4021*7656SSherry.Moore@Sun.COM 		case LA_ELS_DISPLAY:
40222305Sstevel 		els->els_data[i] = '\0';	/* terminate the string */
40232305Sstevel 		for (bp = (char *)&(els->els_data[0]); *bp; bp++) {
40242305Sstevel 			/* squash newlines */
40252305Sstevel 			if (*bp == '\n') *bp = ' ';
40262305Sstevel 		}
40272305Sstevel 		(void) sprintf(buf, "!message: %s\n", els->els_data);
40282305Sstevel 		socal_disp_err(socalp, CE_CONT, "link.1010", buf);
40292305Sstevel 		break;
40302305Sstevel 
4031*7656SSherry.Moore@Sun.COM 		default:
40322305Sstevel 		DEBUGF(3, (CE_CONT, "!unknown LS_Command, %x\n",
4033*7656SSherry.Moore@Sun.COM 		    els->els_cmd.i));
40342305Sstevel 		break;
40352305Sstevel 	}
40362305Sstevel 
40372305Sstevel }
40382305Sstevel 
40392305Sstevel /*ARGSUSED*/
40402305Sstevel static fcal_packet_t *
socal_packet_alloc(socal_state_t * socalp,fcal_sleep_t sleep)40412305Sstevel socal_packet_alloc(socal_state_t *socalp, fcal_sleep_t sleep)
40422305Sstevel {
40432305Sstevel 	int flag;
40442305Sstevel 	fcal_packet_t *pkt;
40452305Sstevel 
40462305Sstevel 	if (sleep == FCAL_SLEEP)
40472305Sstevel 		flag = KM_SLEEP;
40482305Sstevel 	else
40492305Sstevel 		flag = KM_NOSLEEP;
40502305Sstevel 
40512305Sstevel 	pkt = (fcal_packet_t *)kmem_zalloc(sizeof (fcal_packet_t), flag);
40522305Sstevel 
40532305Sstevel 	if (pkt != (fcal_packet_t *)NULL)
40542305Sstevel 		pkt->fcal_magic = FCALP_MAGIC;
40552305Sstevel 
40562305Sstevel 	return (pkt);
40572305Sstevel }
40582305Sstevel 
40592305Sstevel static void
socal_packet_free(fcal_packet_t * fcalpkt)40602305Sstevel socal_packet_free(fcal_packet_t *fcalpkt)
40612305Sstevel {
40622305Sstevel 	kmem_free((void *)fcalpkt, sizeof (fcal_packet_t));
40632305Sstevel }
40642305Sstevel 
40652305Sstevel static void
socal_lilp_map_done(fcal_packet_t * fcalpkt)40662305Sstevel socal_lilp_map_done(fcal_packet_t *fcalpkt)
40672305Sstevel {
40682305Sstevel 	uint32_t	port;
40692305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
40702305Sstevel 
40712305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
40722305Sstevel 		port = 1;
40732305Sstevel 	else
40742305Sstevel 		port = 0;
40752305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
40762305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_LILP_PENDING;
40772305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
40782305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
40792305Sstevel }
40802305Sstevel 
40812305Sstevel static void
socal_force_lip_done(fcal_packet_t * fcalpkt)40822305Sstevel socal_force_lip_done(fcal_packet_t *fcalpkt)
40832305Sstevel {
40842305Sstevel 	uint32_t	port;
40852305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
40862305Sstevel 
40872305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
40882305Sstevel 		port = 1;
40892305Sstevel 	else
40902305Sstevel 		port = 0;
40912305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
40922305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_LIP_PENDING;
40932305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
40942305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
40952305Sstevel }
40962305Sstevel 
40972305Sstevel static void
socal_adisc_done(fcal_packet_t * fcalpkt)40982305Sstevel socal_adisc_done(fcal_packet_t *fcalpkt)
40992305Sstevel {
41002305Sstevel 	uint32_t	port;
41012305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41022305Sstevel 
41032305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41042305Sstevel 		port = 1;
41052305Sstevel 	else
41062305Sstevel 		port = 0;
41072305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41082305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_ADISC_PENDING;
41092305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41102305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41112305Sstevel }
41122305Sstevel 
41132305Sstevel static void
socal_lbf_done(fcal_packet_t * fcalpkt)41142305Sstevel socal_lbf_done(fcal_packet_t *fcalpkt)
41152305Sstevel {
41162305Sstevel 	uint32_t	port;
41172305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41182305Sstevel 
41192305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41202305Sstevel 		port = 1;
41212305Sstevel 	else
41222305Sstevel 		port = 0;
41232305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41242305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_LBF_PENDING;
41252305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41262305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41272305Sstevel }
41282305Sstevel 
41292305Sstevel static void
socal_rls_done(fcal_packet_t * fcalpkt)41302305Sstevel socal_rls_done(fcal_packet_t *fcalpkt)
41312305Sstevel {
41322305Sstevel 	uint32_t	port;
41332305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41342305Sstevel 
41352305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41362305Sstevel 		port = 1;
41372305Sstevel 	else
41382305Sstevel 		port = 0;
41392305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41402305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_RLS_PENDING;
41412305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41422305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41432305Sstevel }
41442305Sstevel 
41452305Sstevel static void
socal_force_offline_done(fcal_packet_t * fcalpkt)41462305Sstevel socal_force_offline_done(fcal_packet_t *fcalpkt)
41472305Sstevel {
41482305Sstevel 	uint32_t	port;
41492305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41502305Sstevel 
41512305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41522305Sstevel 		port = 1;
41532305Sstevel 	else
41542305Sstevel 		port = 0;
41552305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41562305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_OFFLINE_PENDING;
41572305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41582305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41592305Sstevel }
41602305Sstevel 
41612305Sstevel static void
socal_abort_done(fcal_packet_t * fcalpkt)41622305Sstevel socal_abort_done(fcal_packet_t *fcalpkt)
41632305Sstevel {
41642305Sstevel 	uint32_t	port;
41652305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41662305Sstevel 	soc_header_t	*shp =
4167*7656SSherry.Moore@Sun.COM 	    (soc_header_t *)&fcalpkt->fcal_socal_request.sr_soc_hdr;
41682305Sstevel 	fcal_packet_t	*target = (fcal_packet_t *)
4169*7656SSherry.Moore@Sun.COM 	    SOCAL_ID_LOOKUP(shp->sh_request_token);
41702305Sstevel 
41712305Sstevel 	mutex_enter(&socalp->abort_mtx);
41722305Sstevel 	ASSERT(target->fcal_pkt_flags & FCFLAG_ABORTING);
41732305Sstevel 	if (!(target->fcal_pkt_flags & FCFLAG_COMPLETE)) {
41742305Sstevel 		SOCAL_ID_FREE(shp->sh_request_token);
41752305Sstevel 	}
41762305Sstevel 	mutex_exit(&socalp->abort_mtx);
41772305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41782305Sstevel 		port = 1;
41792305Sstevel 	else
41802305Sstevel 		port = 0;
41812305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41822305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_ABORT_PENDING;
41832305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41842305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
41852305Sstevel }
41862305Sstevel 
41872305Sstevel static void
socal_bypass_dev_done(fcal_packet_t * fcalpkt)41882305Sstevel socal_bypass_dev_done(fcal_packet_t *fcalpkt)
41892305Sstevel {
41902305Sstevel 	uint32_t	port;
41912305Sstevel 	socal_state_t	*socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
41922305Sstevel 	if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
41932305Sstevel 		port = 1;
41942305Sstevel 	else
41952305Sstevel 		port = 0;
41962305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
41972305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_BYPASS_PENDING;
41982305Sstevel 	cv_broadcast(&socalp->port_state[port].sp_cv);
41992305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
42002305Sstevel }
42012305Sstevel 
42022305Sstevel /*ARGSUSED*/
42032305Sstevel static unsigned int
socal_dummy_intr(caddr_t arg)42042305Sstevel socal_dummy_intr(caddr_t arg)
42052305Sstevel {
42062305Sstevel 	return (DDI_INTR_UNCLAIMED);
42072305Sstevel }
42082305Sstevel 
42092305Sstevel static int
socal_diag_request(socal_state_t * socalp,uint32_t port,uint_t * diagcode,uint32_t cmd)42102305Sstevel socal_diag_request(socal_state_t *socalp, uint32_t port, uint_t *diagcode,
42112305Sstevel     uint32_t cmd)
42122305Sstevel {
42132305Sstevel 	fcal_packet_t		*fcalpkt;
42142305Sstevel 	soc_diag_request_t	*sdr;
42152305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
42162305Sstevel 	struct fcal_lilp_map	map;
42172305Sstevel 
42182305Sstevel 	/* Grabbing the state mutex is totally unnecessary.... */
42192305Sstevel 	if (!(port_statep->sp_status & PORT_DISABLED)) {
42202305Sstevel 		if (socal_getmap(socalp, port, (caddr_t)&map, 0, FKIOCTL)
4221*7656SSherry.Moore@Sun.COM 		    != -1) {
42222305Sstevel 			if (map.lilp_length != 1 && ((port_statep->sp_status &
4223*7656SSherry.Moore@Sun.COM 			    PORT_ONLINE_LOOP) && cmd != SOC_DIAG_REM_LOOP))
42242305Sstevel 				return (FCAL_TRANSPORT_UNAVAIL);
42252305Sstevel 		}
42262305Sstevel 	}
42272305Sstevel 	if ((fcalpkt = socal_packet_alloc(socalp, FCAL_SLEEP))
42282305Sstevel 	    == (fcal_packet_t *)NULL)
42292305Sstevel 		return (FCAL_ALLOC_FAILED);
42302305Sstevel 	sdr = (soc_diag_request_t *)&fcalpkt->fcal_socal_request;
42312305Sstevel 	if (port)
4232*7656SSherry.Moore@Sun.COM 		sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
42332305Sstevel 	sdr->sdr_diag_cmd = cmd;
42342305Sstevel 	sdr->sdr_cqhdr.cq_hdr_count = 1;
42352305Sstevel 	sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_DIAGNOSTIC;
42362305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
42372305Sstevel 	return (socal_doit(fcalpkt, port_statep, 1, NULL,
42382305Sstevel 	    SOCAL_DIAG_TIMEOUT, 0, diagcode));
42392305Sstevel }
42402305Sstevel 
42412305Sstevel static uint_t
socal_force_offline(void * ssp,uint_t port,uint_t polled)42422305Sstevel socal_force_offline(void *ssp, uint_t port, uint_t polled)
42432305Sstevel {
42442305Sstevel 	fcal_packet_t		*fcalpkt;
42452305Sstevel 	soc_cmdonly_request_t	*scr;
42462305Sstevel 	socal_state_t		*socalp = (socal_state_t *)ssp;
42472305Sstevel 	socal_port_t		*port_statep = &socalp->port_state[port];
42482305Sstevel 
42492305Sstevel 	if ((fcalpkt =
42502305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
42512305Sstevel 	    == (fcal_packet_t *)NULL)
42522305Sstevel 		return (FCAL_ALLOC_FAILED);
42532305Sstevel 
42542305Sstevel 	scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
42552305Sstevel 	if (port)
4256*7656SSherry.Moore@Sun.COM 		scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
42572305Sstevel 	scr->scr_cqhdr.cq_hdr_count = 1;
42582305Sstevel 	scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_OFFLINE;
42592305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
42602305Sstevel 	return (socal_doit(fcalpkt, port_statep, 0, socal_force_offline_done,
42612305Sstevel 	    SOCAL_OFFLINE_TIMEOUT, PORT_OFFLINE_PENDING, NULL));
42622305Sstevel }
42632305Sstevel 
42642305Sstevel static int
socal_issue_adisc(socal_state_t * socalp,uint32_t port,uint32_t dest,la_els_adisc_t * payload,uint32_t polled)42652305Sstevel socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t dest,
42662305Sstevel 	la_els_adisc_t *payload, uint32_t polled)
42672305Sstevel {
42682305Sstevel 	int			retval;
42692305Sstevel 	la_els_adisc_t		*buf;
42702305Sstevel 	fcal_packet_t		*fcalpkt;
42712305Sstevel 	socal_port_t		*port_statep;
42722305Sstevel 	socal_priv_cmd_t 	*privp;
42732305Sstevel 
42742305Sstevel 	port_statep = &socalp->port_state[port];
42752305Sstevel 
42762305Sstevel 	if ((fcalpkt =
42772305Sstevel 	    socal_els_alloc(socalp, port, dest, sizeof (la_els_adisc_t),
42782305Sstevel 	    sizeof (la_els_adisc_t), (caddr_t *)&privp, polled))
42792305Sstevel 	    == (fcal_packet_t *)NULL)
42802305Sstevel 		return (FCAL_ALLOC_FAILED);
42812305Sstevel 
42822305Sstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
42832305Sstevel 	buf = (la_els_adisc_t *)privp->cmd;
42842305Sstevel 	buf->ls_code = LA_ELS_ADISC;
42852305Sstevel 	buf->mbz[0] = 0;
42862305Sstevel 	buf->mbz[1] = 0;
42872305Sstevel 	buf->mbz[2] = 0;
42882305Sstevel 	buf->hard_address = 0;
42892305Sstevel 	bcopy((caddr_t)&port_statep->sp_p_wwn,
42902305Sstevel 	    (caddr_t)&buf->port_wwn, sizeof (buf->port_wwn));
42912305Sstevel 	bcopy((caddr_t)&socalp->socal_n_wwn,
42922305Sstevel 	    (caddr_t)&buf->node_wwn, sizeof (buf->node_wwn));
42932305Sstevel 	buf->nport_id = fcalpkt->fcal_socal_request.sr_fc_frame_hdr.s_id;
42942305Sstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
42952305Sstevel 
42962305Sstevel 	retval = socal_doit(fcalpkt, port_statep, 0, socal_adisc_done,
42972305Sstevel 	    SOCAL_ADISC_TIMEOUT, PORT_ADISC_PENDING, NULL);
42982305Sstevel 	if (retval == FCAL_SUCCESS) {
42992305Sstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4300*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
43012305Sstevel 		bcopy(privp->rsp, (caddr_t)payload, sizeof (la_els_adisc_t));
43022305Sstevel 	}
43032305Sstevel 	privp->fapktp = NULL;
43042305Sstevel 	socal_els_free(privp);
43052305Sstevel 	return (retval);
43062305Sstevel }
43072305Sstevel 
43082305Sstevel static int
socal_issue_lbf(socal_state_t * socalp,uint32_t port,uchar_t * payload,size_t length,uint32_t polled)43092305Sstevel socal_issue_lbf(socal_state_t *socalp, uint32_t port,
43102305Sstevel     uchar_t *payload, size_t length, uint32_t polled)
43112305Sstevel {
43122305Sstevel 	int			retval;
43132305Sstevel 	fcal_packet_t		*fcalpkt;
43142305Sstevel 	socal_port_t		*port_statep;
43152305Sstevel 	socal_priv_cmd_t 	*privp;
43162305Sstevel 
43172305Sstevel 	port_statep = &socalp->port_state[port];
43182305Sstevel 
43192305Sstevel 	if ((fcalpkt = socal_lbf_alloc(socalp, port, length, length,
4320*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&privp, polled)) == (fcal_packet_t *)NULL)
43212305Sstevel 		return (FCAL_ALLOC_FAILED);
43222305Sstevel 
43232305Sstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
43242305Sstevel 	bcopy((caddr_t)payload, privp->cmd, length);
43252305Sstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
43262305Sstevel 
43272305Sstevel 	retval = socal_doit(fcalpkt, port_statep, polled, socal_lbf_done,
43282305Sstevel 	    SOCAL_LBF_TIMEOUT, PORT_LBF_PENDING, NULL);
43292305Sstevel 
43302305Sstevel 	if (retval == FCAL_SUCCESS) {
43312305Sstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4332*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
43332305Sstevel 		bcopy(privp->rsp, (caddr_t)payload, length);
43342305Sstevel 	}
43352305Sstevel 	privp->fapktp = NULL;
43362305Sstevel 	socal_lbf_free(privp);
43372305Sstevel 	return (retval);
43382305Sstevel }
43392305Sstevel 
43402305Sstevel static int
socal_issue_rls(socal_state_t * socalp,uint32_t port,uint32_t dest,la_els_rls_reply_t * payload,uint32_t polled)43412305Sstevel socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t dest,
43422305Sstevel 	la_els_rls_reply_t *payload, uint32_t polled)
43432305Sstevel {
43442305Sstevel 	int	retval;
43452305Sstevel 	la_els_rls_t		*buf;
43462305Sstevel 	fcal_packet_t		*fcalpkt;
43472305Sstevel 	socal_port_t		*port_statep;
43482305Sstevel 	socal_priv_cmd_t 	*privp;
43492305Sstevel 	uint32_t		arg;
43502305Sstevel 
43512305Sstevel 	port_statep = &socalp->port_state[port];
43522305Sstevel 
43532305Sstevel 	if (dest == socal_getmap(socalp, port, NULL, 0, 0)) {
43542305Sstevel 		/* load up the the struct with the local lesb */
43552305Sstevel 		struct la_els_rjt *rsp = (struct la_els_rjt *)payload;
43562305Sstevel 
43572305Sstevel 		rsp->ls_code = LA_ELS_RJT;
43582305Sstevel 		rsp->mbz[0] = 0;
43592305Sstevel 		rsp->mbz[1] = 0;
43602305Sstevel 		rsp->mbz[2] = 0;
43612305Sstevel 		rsp->reason_code = RJT_UNSUPPORTED;
43622305Sstevel 		rsp->reserved = 0;
43632305Sstevel 		rsp->explanation = 0;
43642305Sstevel 		rsp->vendor = 0;
43652305Sstevel 		return (FCAL_SUCCESS);
43662305Sstevel 	}
43672305Sstevel 
43682305Sstevel 	if ((fcalpkt =
43692305Sstevel 	    socal_els_alloc(socalp, port, dest, sizeof (la_els_rls_t),
43702305Sstevel 	    sizeof (la_els_rls_reply_t), (caddr_t *)&privp, polled))
43712305Sstevel 	    == (fcal_packet_t *)NULL)
43722305Sstevel 		return (FCAL_ALLOC_FAILED);
43732305Sstevel 
43742305Sstevel 	privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
43752305Sstevel 
43762305Sstevel 	if (payload->link_failure & 0xff000000)
43772305Sstevel 		arg = payload->link_failure;
43782305Sstevel 	else
43792305Sstevel 		arg = dest;
43802305Sstevel 
43812305Sstevel 	buf = (la_els_rls_t *)privp->cmd;
43822305Sstevel 	buf->ls_code = LA_ELS_RLS;
43832305Sstevel 	buf->mbz[0] = 0;
43842305Sstevel 	buf->mbz[1] = 0;
43852305Sstevel 	buf->mbz[2] = 0;
43862305Sstevel 	buf->reserved = 0;
43872305Sstevel 	buf->nport_id[0] = (arg >> 16) & 0xff;
43882305Sstevel 	buf->nport_id[1] = (arg >> 8) & 0xff;
43892305Sstevel 	buf->nport_id[2] = arg & 0xff;
43902305Sstevel 	(void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
43912305Sstevel 
43922305Sstevel 	retval = socal_doit(fcalpkt, port_statep, 0, socal_rls_done,
43932305Sstevel 	    SOCAL_RLS_TIMEOUT, PORT_RLS_PENDING, NULL);
43942305Sstevel 	if (retval == FCAL_SUCCESS) {
43952305Sstevel 		(void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4396*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
43972305Sstevel 		bcopy(privp->rsp, (caddr_t)payload,
43982305Sstevel 		    sizeof (la_els_rls_reply_t));
43992305Sstevel 	}
44002305Sstevel 	privp->fapktp = NULL;
44012305Sstevel 	socal_els_free(privp);
44022305Sstevel 	return (retval);
44032305Sstevel }
44042305Sstevel 
44052305Sstevel fcal_packet_t *
socal_els_alloc(socal_state_t * socalp,uint32_t port,uint32_t dest,uint32_t cmd_size,uint32_t rsp_size,caddr_t * rprivp,uint32_t polled)44062305Sstevel socal_els_alloc(socal_state_t *socalp, uint32_t port, uint32_t dest,
44072305Sstevel 	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp, uint32_t polled)
44082305Sstevel {
44092305Sstevel 	struct fcal_packet	*fcalpkt;
44102305Sstevel 	ddi_dma_cookie_t	ccookie;
44112305Sstevel 	ddi_dma_cookie_t	rcookie;
44122305Sstevel 	socal_priv_cmd_t	*privp;
44132305Sstevel 	ddi_dma_handle_t	chandle = NULL;
44142305Sstevel 	ddi_dma_handle_t	rhandle = NULL;
44152305Sstevel 	ddi_acc_handle_t	cacchandle;
44162305Sstevel 	ddi_acc_handle_t	racchandle;
44172305Sstevel 	soc_request_t		*srp;
44182305Sstevel 	fc_frame_header_t	*fhp;
44192305Sstevel 	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
44202305Sstevel 	size_t			real_len;
44212305Sstevel 	caddr_t			cmd;
44222305Sstevel 	caddr_t			rsp;
44232305Sstevel 	uint32_t		ouralpa;
44242305Sstevel 
44252305Sstevel 	if ((fcalpkt =
44262305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
44272305Sstevel 	    == (fcal_packet_t *)NULL)
44282305Sstevel 		return (NULL);
44292305Sstevel 
44302305Sstevel 	if ((privp =
44312305Sstevel 	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
44322305Sstevel 	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
44332305Sstevel 		goto fail;
44342305Sstevel 	}
44352305Sstevel 
44362305Sstevel 	rprivp = (caddr_t *)&privp;
44372305Sstevel 
44382305Sstevel 	fcalpkt->fcal_pkt_private = (caddr_t)privp;
44392305Sstevel 	privp->fapktp = (void *)fcalpkt;
44402305Sstevel 
44412305Sstevel 	if ((ouralpa = socal_getmap(socalp, port, NULL, 0, 0)) == -1)
44422305Sstevel 		goto fail;
44432305Sstevel 
44442305Sstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4445*7656SSherry.Moore@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
44462305Sstevel 		goto fail;
44472305Sstevel 	privp->cmd_handle = chandle;
44482305Sstevel 
44492305Sstevel 	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
4450*7656SSherry.Moore@Sun.COM 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4451*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
44522305Sstevel 		goto fail;
44532305Sstevel 	privp->cmd = cmd;
44542305Sstevel 	privp->cmd_acchandle = cacchandle;
44552305Sstevel 
44562305Sstevel 	if (real_len < cmd_size)
44572305Sstevel 		goto fail;
44582305Sstevel 
44592305Sstevel 	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
4460*7656SSherry.Moore@Sun.COM 	    (caddr_t)cmd, cmd_size,
4461*7656SSherry.Moore@Sun.COM 	    DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
4462*7656SSherry.Moore@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
4463*7656SSherry.Moore@Sun.COM 	    != DDI_DMA_MAPPED)
44642305Sstevel 		goto fail;
44652305Sstevel 	cmd_bound = 1;
44662305Sstevel 	if (ccount != 1)
44672305Sstevel 		goto fail;
44682305Sstevel 
44692305Sstevel 	if (rsp_size) {
4470*7656SSherry.Moore@Sun.COM 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4471*7656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
44722305Sstevel 		goto fail;
4473*7656SSherry.Moore@Sun.COM 
4474*7656SSherry.Moore@Sun.COM 		privp->rsp_handle = rhandle;
4475*7656SSherry.Moore@Sun.COM 		if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
4476*7656SSherry.Moore@Sun.COM 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4477*7656SSherry.Moore@Sun.COM 		    &rsp, &real_len, &racchandle) != DDI_SUCCESS)
4478*7656SSherry.Moore@Sun.COM 			goto fail;
4479*7656SSherry.Moore@Sun.COM 		privp->rsp = rsp;
4480*7656SSherry.Moore@Sun.COM 		privp->rsp_acchandle = racchandle;
4481*7656SSherry.Moore@Sun.COM 		if (real_len < rsp_size)
44822305Sstevel 		goto fail;
44832305Sstevel 
4484*7656SSherry.Moore@Sun.COM 		if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
4485*7656SSherry.Moore@Sun.COM 		    rsp, rsp_size,
4486*7656SSherry.Moore@Sun.COM 		    DDI_DMA_READ | DDI_DMA_CONSISTENT,
4487*7656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4488*7656SSherry.Moore@Sun.COM 		    != DDI_DMA_MAPPED)
44892305Sstevel 		goto fail;
44902305Sstevel 
4491*7656SSherry.Moore@Sun.COM 		rsp_bound = 1;
4492*7656SSherry.Moore@Sun.COM 		if (ccount != 1)
44932305Sstevel 		goto fail;
44942305Sstevel 	}
44952305Sstevel 
44962305Sstevel 	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
44972305Sstevel 	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
44982305Sstevel 	if (port)
4499*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
45002305Sstevel 	srp->sr_soc_hdr.sh_class = 3;
45012305Sstevel 	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
45022305Sstevel 	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
45032305Sstevel 	srp->sr_dataseg[0].fc_count = cmd_size;
45042305Sstevel 	if (rsp_size == 0) {
4505*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_seg_cnt = 1;
45062305Sstevel 	} else {
4507*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_seg_cnt = 2;
4508*7656SSherry.Moore@Sun.COM 		srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
4509*7656SSherry.Moore@Sun.COM 		srp->sr_dataseg[1].fc_count = rsp_size;
45102305Sstevel 	}
45112305Sstevel 	srp->sr_cqhdr.cq_hdr_count = 1;
45122305Sstevel 	/* this will potentially be overwritten by the calling function */
45132305Sstevel 	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
45142305Sstevel 
45152305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
45162305Sstevel 
45172305Sstevel 	/* Fill in the Fabric Channel Header */
45182305Sstevel 	fhp = &srp->sr_fc_frame_hdr;
45192305Sstevel 	fhp->r_ctl = R_CTL_ELS_REQ;
45202305Sstevel 	fhp->d_id = dest;
45212305Sstevel 	fhp->s_id = ouralpa;
45222305Sstevel 	fhp->type = TYPE_EXTENDED_LS;
45232305Sstevel 	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
45242305Sstevel 	fhp->seq_id = 0;
45252305Sstevel 	fhp->df_ctl  = 0;
45262305Sstevel 	fhp->seq_cnt = 0;
45272305Sstevel 	fhp->ox_id = 0xffff;
45282305Sstevel 	fhp->rx_id = 0xffff;
45292305Sstevel 	fhp->ro = 0;
45302305Sstevel 	return (fcalpkt);
45312305Sstevel fail:
45322305Sstevel 	socal_packet_free(fcalpkt);
45332305Sstevel 	if (privp) {
45342305Sstevel 		if (privp->cmd_handle) {
45352305Sstevel 			if (cmd_bound)
45362305Sstevel 				(void) ddi_dma_unbind_handle(privp->cmd_handle);
45372305Sstevel 			ddi_dma_free_handle(&privp->cmd_handle);
45382305Sstevel 		}
45392305Sstevel 		if (privp->cmd)
45402305Sstevel 			ddi_dma_mem_free(&privp->cmd_acchandle);
45412305Sstevel 		if (privp->rsp_handle) {
45422305Sstevel 			if (rsp_bound)
45432305Sstevel 				(void) ddi_dma_unbind_handle(privp->rsp_handle);
45442305Sstevel 			ddi_dma_free_handle(&privp->rsp_handle);
45452305Sstevel 		}
45462305Sstevel 		if (privp->rsp)
45472305Sstevel 			ddi_dma_mem_free(&privp->rsp_acchandle);
45482305Sstevel 
45492305Sstevel 		kmem_free(privp, sizeof (*privp));
45502305Sstevel 	}
45512305Sstevel 	return (NULL);
45522305Sstevel }
45532305Sstevel 
45542305Sstevel fcal_packet_t *
socal_lbf_alloc(socal_state_t * socalp,uint32_t port,uint32_t cmd_size,uint32_t rsp_size,caddr_t * rprivp,uint32_t polled)45552305Sstevel socal_lbf_alloc(socal_state_t *socalp, uint32_t port,
45562305Sstevel 	uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp,
45572305Sstevel 	uint32_t polled)
45582305Sstevel {
45592305Sstevel 	struct fcal_packet	*fcalpkt;
45602305Sstevel 	ddi_dma_cookie_t	ccookie;
45612305Sstevel 	ddi_dma_cookie_t	rcookie;
45622305Sstevel 	socal_priv_cmd_t	*privp;
45632305Sstevel 	ddi_dma_handle_t	chandle = NULL;
45642305Sstevel 	ddi_dma_handle_t	rhandle = NULL;
45652305Sstevel 	ddi_acc_handle_t	cacchandle;
45662305Sstevel 	ddi_acc_handle_t	racchandle;
45672305Sstevel 	soc_request_t		*srp;
45682305Sstevel 	fc_frame_header_t	*fhp;
45692305Sstevel 	uint_t			ccount, cmd_bound = 0, rsp_bound = 0;
45702305Sstevel 	size_t			real_len;
45712305Sstevel 	caddr_t			cmd;
45722305Sstevel 	caddr_t			rsp;
45732305Sstevel 
45742305Sstevel 	if ((fcalpkt =
45752305Sstevel 	    socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
45762305Sstevel 	    == (fcal_packet_t *)NULL)
45772305Sstevel 		return (NULL);
45782305Sstevel 
45792305Sstevel 	if ((privp =
45802305Sstevel 	    (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
45812305Sstevel 	    polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
45822305Sstevel 		goto fail;
45832305Sstevel 	}
45842305Sstevel 
45852305Sstevel 	rprivp = (caddr_t *)&privp;
45862305Sstevel 
45872305Sstevel 	fcalpkt->fcal_pkt_private = (caddr_t)privp;
45882305Sstevel 	privp->fapktp = (void *)fcalpkt;
45892305Sstevel 
45902305Sstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4591*7656SSherry.Moore@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
45922305Sstevel 		goto fail;
45932305Sstevel 	privp->cmd_handle = chandle;
45942305Sstevel 
45952305Sstevel 	if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
4596*7656SSherry.Moore@Sun.COM 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4597*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
45982305Sstevel 		goto fail;
45992305Sstevel 	privp->cmd = cmd;
46002305Sstevel 	privp->cmd_acchandle = cacchandle;
46012305Sstevel 
46022305Sstevel 	if (real_len < cmd_size)
46032305Sstevel 		goto fail;
46042305Sstevel 
46052305Sstevel 	if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
4606*7656SSherry.Moore@Sun.COM 	    (caddr_t)cmd, cmd_size,
4607*7656SSherry.Moore@Sun.COM 	    DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
4608*7656SSherry.Moore@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
4609*7656SSherry.Moore@Sun.COM 	    != DDI_DMA_MAPPED)
46102305Sstevel 		goto fail;
46112305Sstevel 	cmd_bound = 1;
46122305Sstevel 	if (ccount != 1)
46132305Sstevel 		goto fail;
46142305Sstevel 
46152305Sstevel 	if (rsp_size) {
4616*7656SSherry.Moore@Sun.COM 		if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4617*7656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
46182305Sstevel 		goto fail;
46192305Sstevel 
4620*7656SSherry.Moore@Sun.COM 		privp->rsp_handle = rhandle;
4621*7656SSherry.Moore@Sun.COM 		if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
4622*7656SSherry.Moore@Sun.COM 		    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4623*7656SSherry.Moore@Sun.COM 		    &rsp, &real_len, &racchandle) != DDI_SUCCESS)
46242305Sstevel 			goto fail;
46252305Sstevel 
4626*7656SSherry.Moore@Sun.COM 		privp->rsp = rsp;
4627*7656SSherry.Moore@Sun.COM 		privp->rsp_acchandle = racchandle;
4628*7656SSherry.Moore@Sun.COM 		if (real_len < rsp_size)
46292305Sstevel 		goto fail;
46302305Sstevel 
4631*7656SSherry.Moore@Sun.COM 		if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
4632*7656SSherry.Moore@Sun.COM 		    rsp, rsp_size,
4633*7656SSherry.Moore@Sun.COM 		    DDI_DMA_READ | DDI_DMA_CONSISTENT,
4634*7656SSherry.Moore@Sun.COM 		    DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4635*7656SSherry.Moore@Sun.COM 		    != DDI_DMA_MAPPED)
46362305Sstevel 			goto fail;
46372305Sstevel 
4638*7656SSherry.Moore@Sun.COM 		rsp_bound = 1;
4639*7656SSherry.Moore@Sun.COM 		if (ccount != 1)
46402305Sstevel 		goto fail;
46412305Sstevel 	}
46422305Sstevel 
46432305Sstevel 	srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
46442305Sstevel 	srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
46452305Sstevel 	if (port)
4646*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
46472305Sstevel 	srp->sr_soc_hdr.sh_class = 3;
46482305Sstevel 	srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
46492305Sstevel 	srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
46502305Sstevel 	srp->sr_dataseg[0].fc_count = cmd_size;
46512305Sstevel 	if (rsp_size == 0) {
4652*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_seg_cnt = 1;
46532305Sstevel 	} else {
4654*7656SSherry.Moore@Sun.COM 		srp->sr_soc_hdr.sh_seg_cnt = 2;
4655*7656SSherry.Moore@Sun.COM 		srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
4656*7656SSherry.Moore@Sun.COM 		srp->sr_dataseg[1].fc_count = rsp_size;
46572305Sstevel 	}
46582305Sstevel 	srp->sr_cqhdr.cq_hdr_count = 1;
46592305Sstevel 	/* this will potentially be overwritten by the calling function */
46602305Sstevel 	srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
46612305Sstevel 
46622305Sstevel 	fcalpkt->fcal_pkt_cookie = (void *)socalp;
46632305Sstevel 
46642305Sstevel 	/* Fill in the Fabric Channel Header */
46652305Sstevel 	fhp = &srp->sr_fc_frame_hdr;
46662305Sstevel 	fhp->r_ctl = R_CTL_SOLICITED_DATA;
46672305Sstevel 	fhp->d_id = socalp->port_state[port].sp_src_id;
46682305Sstevel 	fhp->s_id = socalp->port_state[port].sp_src_id;
46692305Sstevel 	fhp->type = TYPE_SCSI_FCP;
46702305Sstevel 	fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ;
46712305Sstevel 	fhp->seq_id = 0;
46722305Sstevel 	fhp->df_ctl  = 0;
46732305Sstevel 	fhp->seq_cnt = 0;
46742305Sstevel 	fhp->ox_id = 0xffff;
46752305Sstevel 	fhp->rx_id = 0xffff;
46762305Sstevel 	fhp->ro = 0;
46772305Sstevel 	return (fcalpkt);
46782305Sstevel fail:
46792305Sstevel 	socal_packet_free(fcalpkt);
46802305Sstevel 	if (privp) {
46812305Sstevel 		if (privp->cmd_handle) {
46822305Sstevel 			if (cmd_bound)
46832305Sstevel 				(void) ddi_dma_unbind_handle(privp->cmd_handle);
46842305Sstevel 			ddi_dma_free_handle(&privp->cmd_handle);
46852305Sstevel 		}
46862305Sstevel 		if (privp->cmd)
46872305Sstevel 			ddi_dma_mem_free(&privp->cmd_acchandle);
46882305Sstevel 		if (privp->rsp_handle) {
46892305Sstevel 			if (rsp_bound)
46902305Sstevel 				(void) ddi_dma_unbind_handle(privp->rsp_handle);
46912305Sstevel 			ddi_dma_free_handle(&privp->rsp_handle);
46922305Sstevel 		}
46932305Sstevel 		if (privp->rsp)
46942305Sstevel 			ddi_dma_mem_free(&privp->rsp_acchandle);
46952305Sstevel 
46962305Sstevel 		kmem_free(privp, sizeof (*privp));
46972305Sstevel 	}
46982305Sstevel 	return (NULL);
46992305Sstevel }
47002305Sstevel 
47012305Sstevel void
socal_els_free(socal_priv_cmd_t * privp)47022305Sstevel socal_els_free(socal_priv_cmd_t *privp)
47032305Sstevel {
47042305Sstevel 	fcal_packet_t		*fcalpkt;
47052305Sstevel 
47062305Sstevel 	if (privp)
47072305Sstevel 		fcalpkt = (fcal_packet_t *)privp->fapktp;
47082305Sstevel 	else
47092305Sstevel 		return;
47102305Sstevel 
47112305Sstevel 	(void) ddi_dma_unbind_handle(privp->cmd_handle);
47122305Sstevel 	ddi_dma_free_handle(&privp->cmd_handle);
47132305Sstevel 	ddi_dma_mem_free(&privp->cmd_acchandle);
47142305Sstevel 
47152305Sstevel 	if (privp->rsp_handle) {
47162305Sstevel 		(void) ddi_dma_unbind_handle(privp->rsp_handle);
47172305Sstevel 		ddi_dma_free_handle(&privp->rsp_handle);
47182305Sstevel 	}
47192305Sstevel 	if (privp->rsp)
47202305Sstevel 		ddi_dma_mem_free(&privp->rsp_acchandle);
47212305Sstevel 
47222305Sstevel 	kmem_free(privp, sizeof (*privp));
47232305Sstevel 	if (fcalpkt != NULL)
47242305Sstevel 		socal_packet_free(fcalpkt);
47252305Sstevel }
47262305Sstevel 
47272305Sstevel void
socal_lbf_free(socal_priv_cmd_t * privp)47282305Sstevel socal_lbf_free(socal_priv_cmd_t *privp)
47292305Sstevel {
47302305Sstevel 	fcal_packet_t		*fcalpkt;
47312305Sstevel 
47322305Sstevel 	if (privp)
47332305Sstevel 		fcalpkt = (fcal_packet_t *)privp->fapktp;
47342305Sstevel 	else
47352305Sstevel 		return;
47362305Sstevel 
47372305Sstevel 	(void) ddi_dma_unbind_handle(privp->cmd_handle);
47382305Sstevel 	ddi_dma_free_handle(&privp->cmd_handle);
47392305Sstevel 	ddi_dma_mem_free(&privp->cmd_acchandle);
47402305Sstevel 
47412305Sstevel 	if (privp->rsp_handle) {
47422305Sstevel 		(void) ddi_dma_unbind_handle(privp->rsp_handle);
47432305Sstevel 		ddi_dma_free_handle(&privp->rsp_handle);
47442305Sstevel 	}
47452305Sstevel 
47462305Sstevel 	if (privp->rsp)
47472305Sstevel 		ddi_dma_mem_free(&privp->rsp_acchandle);
47482305Sstevel 
47492305Sstevel 	kmem_free(privp, sizeof (*privp));
47502305Sstevel 	if (fcalpkt != NULL)
47512305Sstevel 		socal_packet_free(fcalpkt);
47522305Sstevel }
47532305Sstevel 
47542305Sstevel static int
socal_getmap(socal_state_t * socalp,uint32_t port,caddr_t arg,uint32_t polled,int flags)47552305Sstevel socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
47562305Sstevel 	uint32_t polled, int flags)
47572305Sstevel {
47582305Sstevel 	ddi_dma_cookie_t	dcookie;
47592305Sstevel 	ddi_dma_handle_t	dhandle = NULL;
47602305Sstevel 	ddi_acc_handle_t	acchandle;
47612305Sstevel 	size_t			real_len, i;
47622305Sstevel 	uint_t			ccount;
47632305Sstevel 	fcal_lilp_map_t		*buf = NULL;
47642305Sstevel 	int			retval, bound = 0;
47652305Sstevel 	socal_port_t		*port_statep;
47662305Sstevel 
47672305Sstevel 	port_statep = &socalp->port_state[port];
47682305Sstevel 
47692305Sstevel 	if (port_statep->sp_lilpmap_valid) {
47702305Sstevel 
4771*7656SSherry.Moore@Sun.COM 		buf = &port_statep->sp_lilpmap; /* give from cache */
4772*7656SSherry.Moore@Sun.COM 
4773*7656SSherry.Moore@Sun.COM 		if (arg) {
47742305Sstevel 		if (ddi_copyout(buf, (caddr_t)arg,
47752305Sstevel 		    sizeof (struct lilpmap), flags) == -1)
47762305Sstevel 			return (-1);
4777*7656SSherry.Moore@Sun.COM 		}
4778*7656SSherry.Moore@Sun.COM 
4779*7656SSherry.Moore@Sun.COM 		return (buf->lilp_myalpa);
47802305Sstevel 	}
47812305Sstevel 
47822305Sstevel 	if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4783*7656SSherry.Moore@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &dhandle) != DDI_SUCCESS)
47842305Sstevel 		goto getmap_fail;
47852305Sstevel 
47862305Sstevel 	i = sizeof (struct fcal_lilp_map);
47872305Sstevel 
47882305Sstevel 	if (ddi_dma_mem_alloc(dhandle, i, &socal_acc_attr,
47892305Sstevel 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
47902305Sstevel 	    (caddr_t *)&buf, &real_len, &acchandle) != DDI_SUCCESS)
47912305Sstevel 		goto getmap_fail;
47922305Sstevel 
47932305Sstevel 	if (real_len < i)
47942305Sstevel 		goto getmap_fail;
47952305Sstevel 
47962305Sstevel 	if (ddi_dma_addr_bind_handle(dhandle, (struct as *)NULL,
47972305Sstevel 	    (caddr_t)buf, i, DDI_DMA_READ | DDI_DMA_CONSISTENT,
47982305Sstevel 	    DDI_DMA_DONTWAIT, NULL, &dcookie, &ccount) != DDI_DMA_MAPPED)
47992305Sstevel 		goto getmap_fail;
48002305Sstevel 
48012305Sstevel 	bound = 1;
48022305Sstevel 	if (ccount != 1)
48032305Sstevel 		goto getmap_fail;
48042305Sstevel 
48052305Sstevel 	retval = socal_lilp_map((void *)socalp, port,
48062305Sstevel 	    (uint32_t)dcookie.dmac_address, polled);
48072305Sstevel 
48082305Sstevel 	(void) ddi_dma_sync(dhandle, 0, 0, DDI_DMA_SYNC_FORKERNEL);
48092305Sstevel 
48102305Sstevel 	if (retval == FCAL_SUCCESS) {
4811*7656SSherry.Moore@Sun.COM 		bcopy(buf, &port_statep->sp_lilpmap, sizeof (fcal_lilp_map_t));
4812*7656SSherry.Moore@Sun.COM 
4813*7656SSherry.Moore@Sun.COM 		mutex_enter(&port_statep->sp_mtx);
4814*7656SSherry.Moore@Sun.COM 		port_statep->sp_src_id = buf->lilp_myalpa;
4815*7656SSherry.Moore@Sun.COM 		port_statep->sp_lilpmap_valid = 1; /* cached */
4816*7656SSherry.Moore@Sun.COM 		mutex_exit(&port_statep->sp_mtx);
4817*7656SSherry.Moore@Sun.COM 
4818*7656SSherry.Moore@Sun.COM 		if (arg) {
48192305Sstevel 		if (ddi_copyout(buf, (caddr_t)arg,
48202305Sstevel 		    sizeof (struct lilpmap), flags) == -1)
48212305Sstevel 			goto getmap_fail;
4822*7656SSherry.Moore@Sun.COM 		}
4823*7656SSherry.Moore@Sun.COM 
4824*7656SSherry.Moore@Sun.COM 		retval = buf->lilp_myalpa;
48252305Sstevel 	}
48262305Sstevel 	else
48272305Sstevel 		retval = -1;
48282305Sstevel 
48292305Sstevel 	(void) ddi_dma_unbind_handle(dhandle);
48302305Sstevel 	ddi_dma_mem_free(&acchandle);
48312305Sstevel 	ddi_dma_free_handle(&dhandle);
48322305Sstevel 	return (retval);
48332305Sstevel 
48342305Sstevel getmap_fail:
48352305Sstevel 	if (dhandle) {
48362305Sstevel 		if (bound)
48372305Sstevel 			(void) ddi_dma_unbind_handle(dhandle);
48382305Sstevel 		ddi_dma_free_handle(&dhandle);
48392305Sstevel 	}
48402305Sstevel 	if (buf)
48412305Sstevel 		ddi_dma_mem_free(&acchandle);
48422305Sstevel 	return (-1);
48432305Sstevel }
48442305Sstevel 
48452305Sstevel static	void
socal_wcopy(uint_t * h_src,uint_t * h_dest,int len)48462305Sstevel socal_wcopy(uint_t *h_src, uint_t *h_dest, int len)
48472305Sstevel {
48482305Sstevel 	int	i;
48492305Sstevel 	for (i = 0; i < len/4; i++) {
48502305Sstevel 		*h_dest++ = *h_src++;
48512305Sstevel 	}
48522305Sstevel }
48532305Sstevel 
48542305Sstevel static void
socal_flush_overflowq(socal_state_t * socalp,int port,int q_no)48552305Sstevel socal_flush_overflowq(socal_state_t *socalp, int port, int q_no)
48562305Sstevel {
48572305Sstevel 	socal_kcq_t	*kcq;
48582305Sstevel 	fcal_packet_t	*fpkt1, *fpkt2, *head = NULL, *tmp;
48592305Sstevel 
48602305Sstevel 	kcq = &socalp->request[q_no];
48612305Sstevel 	mutex_enter(&kcq->skc_mtx);
48622305Sstevel 	fpkt2 = kcq->skc_overflowh;
48632305Sstevel 	fpkt1 = NULL;
48642305Sstevel 	while (fpkt2 != NULL) {
48652305Sstevel 		if ((((soc_request_t *)&fpkt2->fcal_socal_request)
48662305Sstevel 		    ->sr_soc_hdr.sh_flags & SOC_PORT_B) == port) {
48672305Sstevel 			if (fpkt1 == NULL)
48682305Sstevel 				kcq->skc_overflowh = fpkt2->fcal_pkt_next;
48692305Sstevel 			else {
48702305Sstevel 				fpkt1->fcal_pkt_next = fpkt2->fcal_pkt_next;
48712305Sstevel 				if (kcq->skc_overflowt == fpkt2)
48722305Sstevel 					kcq->skc_overflowt = fpkt1;
48732305Sstevel 			}
48742305Sstevel 			tmp = fpkt2->fcal_pkt_next;
48752305Sstevel 			fpkt2->fcal_pkt_next = head;
48762305Sstevel 			head = fpkt2;
48772305Sstevel 			fpkt2 = tmp;
48782305Sstevel 			SOCAL_ID_FREE(head->fcal_socal_request.
4879*7656SSherry.Moore@Sun.COM 			    sr_soc_hdr.sh_request_token);
48802305Sstevel 		} else {
48812305Sstevel 			fpkt1 = fpkt2;
48822305Sstevel 			fpkt2 = fpkt2->fcal_pkt_next;
48832305Sstevel 		}
48842305Sstevel 	}
48852305Sstevel 	mutex_exit(&kcq->skc_mtx);
48862305Sstevel 	fpkt2 = head;
48872305Sstevel 	while (fpkt2 != NULL) {
48882305Sstevel 		fpkt2->fcal_pkt_status = FCAL_STATUS_ERR_OFFLINE;
48892305Sstevel 		fpkt2->fcal_cmd_state |= FCAL_CMD_COMPLETE;
48902305Sstevel 		fpkt2->fcal_pkt_flags |= FCFLAG_COMPLETE;
48912305Sstevel 		tmp = fpkt2->fcal_pkt_next;
48922305Sstevel 		if (fpkt2->fcal_pkt_comp != NULL)
48932305Sstevel 			(*fpkt2->fcal_pkt_comp)(fpkt2);
48942305Sstevel 		fpkt2 = tmp;
48952305Sstevel 	}
48962305Sstevel }
48972305Sstevel 
48982305Sstevel static void
socal_deferred_intr(void * arg)48992305Sstevel socal_deferred_intr(void *arg)
49002305Sstevel {
49012305Sstevel 	socal_kcq_t	*kcq = (socal_kcq_t *)arg;
49022305Sstevel 	socal_state_t	*socalp = kcq->skc_socalp;
49032305Sstevel 
49042305Sstevel 	ASSERT((socalp != NULL));
49052305Sstevel 
49062305Sstevel 	mutex_enter(&kcq->skc_mtx);
49072305Sstevel 
49082305Sstevel 	if ((kcq->skc_out != kcq->skc_saved_out) ||
49092305Sstevel 	    (kcq->skc_seqno != kcq->skc_saved_seqno)) {
49102305Sstevel 		kcq->deferred_intr_timeoutid = 0;
49112305Sstevel 		mutex_exit(&kcq->skc_mtx);
49122305Sstevel 		return;
49132305Sstevel 	}
49142305Sstevel 
49152305Sstevel 	if (socalp->socal_on_intr) {
49162305Sstevel 		mutex_exit(&kcq->skc_mtx);
49172305Sstevel 		kcq->deferred_intr_timeoutid = timeout(socal_deferred_intr,
4918*7656SSherry.Moore@Sun.COM 		    (caddr_t)kcq, drv_usectohz(10000));
49192305Sstevel 		return;
49202305Sstevel 	}
49212305Sstevel 
49222305Sstevel 	kcq->deferred_intr_timeoutid = 0;
49232305Sstevel 	mutex_exit(&kcq->skc_mtx);
49242305Sstevel 	socal_intr_solicited(socalp, 0);
49252305Sstevel }
49262305Sstevel 
49272305Sstevel static void
socal_take_core(void * arg)49282305Sstevel socal_take_core(void *arg)
49292305Sstevel {
49302305Sstevel 	socal_state_t	*socalp = (socal_state_t *)arg;
49312305Sstevel 	int i, instance;
49322305Sstevel 
49332305Sstevel 	socal_disable(socalp);
49342305Sstevel 	for (i = 0; i < SOCAL_N_CQS; i++) {
49352305Sstevel 		mutex_enter(&socalp->request[i].skc_mtx);
49362305Sstevel 		mutex_enter(&socalp->response[i].skc_mtx);
49372305Sstevel 	}
49382305Sstevel 	for (i = 0; i < 4; i++) {
49392305Sstevel 		socalp->socal_rp->socal_cr.w &=
4940*7656SSherry.Moore@Sun.COM 		    ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
49412305Sstevel 		socalp->socal_rp->socal_cr.w |= i<<24;
49422305Sstevel 		(void) bcopy((caddr_t)socalp->socal_xrp,
4943*7656SSherry.Moore@Sun.COM 		    (caddr_t)&socal_xrambuf[i*0x10000], 0x10000);
49442305Sstevel 	}
49452305Sstevel 	for (i = 3; i >= 0; i--) {
49462305Sstevel 		mutex_exit(&socalp->request[i].skc_mtx);
49472305Sstevel 		mutex_exit(&socalp->response[i].skc_mtx);
49482305Sstevel 	}
49492305Sstevel 	instance = ddi_get_instance(socalp->dip);
49502305Sstevel 	cmn_err(CE_PANIC,
4951*7656SSherry.Moore@Sun.COM 	    "socal take core (socal instance %d)", instance);
49522305Sstevel }
49532305Sstevel 
49542305Sstevel /*
49552305Sstevel  * Preset AL_PA in hardware, if is told.
49562305Sstevel  */
49572305Sstevel static void
socal_fix_harda(socal_state_t * socalp,int port)49582305Sstevel socal_fix_harda(socal_state_t *socalp, int port)
49592305Sstevel {
49602305Sstevel 	socal_port_t	*portp = &socalp->port_state[port];
49612305Sstevel 	uint_t		*xrp = (uint_t *)socalp->socal_xrp;
49622305Sstevel 	uint_t		accum, harda;
49632305Sstevel 
49642305Sstevel 	harda = portp->sp_hard_alpa;
49652305Sstevel 	accum = xrp[SOCAL_XRAM_PORTA_HRDA/4];
49662305Sstevel 	if (port == 0) {
49672305Sstevel 		accum &= 0x00FFFFFF;
49682305Sstevel 		accum |= ((harda & 0xFF) << 24);
49692305Sstevel 	} else {
49702305Sstevel 		accum &= 0xFF00FFFF;
49712305Sstevel 		accum |= ((harda & 0xFF) << 16);
49722305Sstevel 	}
49732305Sstevel 	xrp[SOCAL_XRAM_PORTA_HRDA/4] = accum;
49742305Sstevel }
49752305Sstevel 
49762305Sstevel /*
49772305Sstevel  * Target-Mode attach function
49782305Sstevel  */
49792305Sstevel fcal_transport_t *
socal_sftm_attach(dev_t dev,int loop_id)49802305Sstevel socal_sftm_attach(dev_t dev, int loop_id)
49812305Sstevel {
49822305Sstevel 	int 		instance = getminor(dev) / 2;
49832305Sstevel 	int		port = getminor(dev) % 2;
49842305Sstevel 	int		hard_alpa;
49852305Sstevel 	char		*name;
49862305Sstevel 	socal_state_t	*socalp;
49872305Sstevel 
49882305Sstevel 	/*
49892305Sstevel 	 * If the device is not a "socal" device, return
49902305Sstevel 	 */
49912305Sstevel 	if ((name = ddi_major_to_name(getmajor(dev))) == NULL ||
49922305Sstevel 	    strcmp(name, "socal") != 0)
49932305Sstevel 		return (NULL);
49942305Sstevel 
49952305Sstevel 	/*
49962305Sstevel 	 * If no soft state structure, return
49972305Sstevel 	 */
49982305Sstevel 	socalp = ddi_get_soft_state(socal_soft_state_p, instance);
49992305Sstevel 	if (socalp == NULL)
50002305Sstevel 		return (NULL);
50012305Sstevel 
50022305Sstevel 	/*
50032305Sstevel 	 * If the port is already attached, return
50042305Sstevel 	 */
50052305Sstevel 	if (socalp->port_state[port].sp_status & PORT_CHILD_INIT)
50062305Sstevel 		return (NULL);
50072305Sstevel 
50082305Sstevel 	if (loop_id < 0 || loop_id > 126)
50092305Sstevel 		return (NULL);
50102305Sstevel 
50112305Sstevel 	/* if this instance is detaching, don't attach */
50122305Sstevel 	mutex_enter(&socalp->board_mtx);
50132305Sstevel 	mutex_enter(&socalp->port_state[port].sp_mtx);
50142305Sstevel 	if (socalp->socal_busy < 0) {
50152305Sstevel 		mutex_exit(&socalp->port_state[port].sp_mtx);
50162305Sstevel 		mutex_exit(&socalp->board_mtx);
50172305Sstevel 		return (NULL);
50182305Sstevel 	}
50192305Sstevel 	socalp->socal_busy++;
50202305Sstevel 	socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
50212305Sstevel 	mutex_exit(&socalp->port_state[port].sp_mtx);
50222305Sstevel 	mutex_exit(&socalp->board_mtx);
50232305Sstevel 
50242305Sstevel 	/*
50252305Sstevel 	 * Since we keep the Hard Loop-id in two config files, warn the
50262305Sstevel 	 * user if they don't match.
50272305Sstevel 	 */
50282305Sstevel 	hard_alpa = socal_switch_to_alpa[loop_id];
50292305Sstevel 	if (hard_alpa != socalp->port_state[port].sp_hard_alpa) {
50302305Sstevel 		socalp->port_state[port].sp_hard_alpa = hard_alpa;
50312305Sstevel 		cmn_err(CE_WARN, "socal%d: Hard Loop-id mismatch - "
50322305Sstevel 		    "using Loop-id %d",
50332305Sstevel 		    instance, loop_id);
50342305Sstevel 	}
50352305Sstevel 
50362305Sstevel 	return (socalp->port_state[port].sp_transport);
50372305Sstevel }
50382305Sstevel 
50392305Sstevel 
50402305Sstevel /*
50412305Sstevel  * Target-Mode detach function
50422305Sstevel  */
50432305Sstevel int
socal_sftm_detach(socal_state_t * socalp,int port)50442305Sstevel socal_sftm_detach(socal_state_t *socalp, int port)
50452305Sstevel {
50462305Sstevel 	mutex_enter(&socalp->board_mtx);
50472305Sstevel 	socalp->socal_busy--;
50482305Sstevel 	socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
50492305Sstevel 	mutex_exit(&socalp->board_mtx);
50502305Sstevel 
50512305Sstevel 	return (0);
50522305Sstevel }
5053