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