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