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