4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
31 * socal - Serial Optical Channel Arbitrated Loop host adapter driver.
34 #include <sys/types.h>
36 #include <sys/devops.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
41 #include <sys/ioctl.h>
43 #include <sys/fcntl.h>
45 #include <sys/cmn_err.h>
46 #include <sys/stropts.h>
49 #include <sys/errno.h>
51 #include <sys/varargs.h>
53 #include <sys/thread.h>
54 #include <sys/debug.h>
56 #include <sys/autoconf.h>
61 #include <sys/syslog.h>
64 #include <sys/sunddi.h>
65 #include <sys/ddi_impldefs.h>
66 #include <sys/ksynch.h>
67 #include <sys/ddidmareq.h>
68 #include <sys/dditypes.h>
69 #include <sys/ethernet.h>
70 #include <sys/socalreg.h>
71 #include <sys/socalmap.h>
72 #include <sys/fc4/fcal.h>
73 #include <sys/socal_cq_defs.h>
74 #include <sys/fc4/fcal_linkapp.h>
75 #include <sys/fc4/fcal_transport.h>
76 #include <sys/socalio.h>
77 #include <sys/socalvar.h>
88 static uchar_t socal_xrambuf
[0x40000];
89 static int socal_core
= SOCAL_TAKE_CORE
;
90 #if SOCAL_DEBUG > 0 && !defined(lint)
91 static int soc_debug
= SOCAL_DEBUG
;
92 static int socal_read_stale_data
= 0;
93 #define DEBUGF(level, args) \
94 if (soc_debug >= (level)) cmn_err args;
95 #define SOCALDEBUG(level, args) \
96 if (soc_debug >= level) args;
98 #define DEBUGF(level, args) /* Nothing */
99 #define SOCALDEBUG(level, args) /* Nothing */
103 /* defines for properties */
104 #define SOCAL_PORT_NO_PROP "socal_port"
105 #define SOCAL_ALT_PORT_NO_PROP "port#"
107 /* for socal_force_reset() */
109 #define DONT_RESET_PORT 0
112 * Driver Entry points.
114 static int socal_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
115 static int socal_bus_ctl(dev_info_t
*dip
, dev_info_t
*rip
,
116 ddi_ctl_enum_t op
, void *a
, void *v
);
117 static int socal_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
118 static int socal_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
,
119 void *arg
, void **result
);
120 static unsigned int socal_intr(caddr_t arg
);
121 static unsigned int socal_dummy_intr(caddr_t arg
);
122 static int socal_open(dev_t
*devp
, int flag
, int otyp
,
124 static int socal_close(dev_t dev
, int flag
, int otyp
,
126 static int socal_ioctl(dev_t dev
, int cmd
, intptr_t arg
,
127 int mode
, cred_t
*cred_p
, int *rval_p
);
130 * FC_AL transport functions.
132 static uint_t
socal_transport(fcal_packet_t
*, fcal_sleep_t
, int);
133 static uint_t
socal_transport_poll(fcal_packet_t
*, uint_t
, int);
134 static uint_t
socal_lilp_map(void *, uint_t
, uint32_t, uint_t
);
135 static uint_t
socal_force_lip(void *, uint_t
, uint_t
, uint_t
);
136 static uint_t
socal_force_offline(void *, uint_t
, uint_t
);
137 static uint_t
socal_abort_cmd(void *, uint_t
, fcal_packet_t
*, uint_t
);
138 static uint_t
socal_doit(fcal_packet_t
*, socal_port_t
*, int,
139 void (*)(), int, int, uint_t
*);
140 static uint_t
socal_els(void *, uint_t
, uint_t
, uint_t
,
141 void (*callback
)(), void *, caddr_t
, caddr_t
*, uint_t
);
142 static uint_t
socal_bypass_dev(void *, uint_t
, uint_t
);
143 static void socal_force_reset(void *, uint_t
, uint_t
);
144 static void socal_add_ulp(void *, uint_t
, uchar_t
, void (*)(),
145 void (*)(), void (*)(), void *);
146 static void socal_remove_ulp(void *, uint_t
, uchar_t
, void *);
147 static void socal_take_core(void *);
150 * Driver internal functions.
152 static void socal_intr_solicited(socal_state_t
*, uint32_t srq
);
153 static void socal_intr_unsolicited(socal_state_t
*, uint32_t urq
);
154 static void socal_lilp_map_done(fcal_packet_t
*);
155 static void socal_force_lip_done(fcal_packet_t
*);
156 static void socal_force_offline_done(fcal_packet_t
*);
157 static void socal_abort_done(fcal_packet_t
*);
158 static void socal_bypass_dev_done(fcal_packet_t
*);
159 static fcal_packet_t
*socal_packet_alloc(socal_state_t
*, fcal_sleep_t
);
160 static void socal_packet_free(fcal_packet_t
*);
161 static void socal_disable(socal_state_t
*socalp
);
162 static void socal_init_transport_interface(socal_state_t
*socalp
);
163 static int socal_cqalloc_init(socal_state_t
*socalp
, uint32_t index
);
164 static void socal_cqinit(socal_state_t
*socalp
, uint32_t index
);
165 static int socal_start(socal_state_t
*socalp
);
166 static void socal_doreset(socal_state_t
*socalp
);
167 static int socal_dodetach(dev_info_t
*dip
);
168 static int socal_diag_request(socal_state_t
*socalp
, uint32_t port
,
169 uint_t
*diagcode
, uint32_t cmd
);
170 static void socal_download_ucode(socal_state_t
*socalp
);
171 static void socal_init_cq_desc(socal_state_t
*socalp
);
172 static void socal_init_wwn(socal_state_t
*socalp
);
173 static void socal_enable(socal_state_t
*socalp
);
174 static int socal_establish_pool(socal_state_t
*socalp
, uint32_t poolid
);
175 static int socal_add_pool_buffer(socal_state_t
*socalp
, uint32_t poolid
);
176 static int socal_issue_adisc(socal_state_t
*socalp
, uint32_t port
, uint32_t
177 dest
, la_els_adisc_t
*adisc_pl
, uint32_t polled
);
178 static int socal_issue_lbf(socal_state_t
*socalp
, uint32_t port
,
179 uchar_t
*flb_pl
, size_t length
, uint32_t polled
);
180 static int socal_issue_rls(socal_state_t
*socalp
, uint32_t port
, uint32_t
181 dest
, la_els_rls_reply_t
*rls_pl
, uint32_t polled
);
182 static void socal_us_els(socal_state_t
*, cqe_t
*, caddr_t
);
183 static fcal_packet_t
*socal_els_alloc(socal_state_t
*, uint32_t, uint32_t,
184 uint32_t, uint32_t, caddr_t
*, uint32_t);
185 static fcal_packet_t
*socal_lbf_alloc(socal_state_t
*, uint32_t,
186 uint32_t, uint32_t, caddr_t
*, uint32_t);
187 static void socal_els_free(socal_priv_cmd_t
*);
188 static void socal_lbf_free(socal_priv_cmd_t
*);
189 static int socal_getmap(socal_state_t
*socalp
, uint32_t port
, caddr_t arg
,
190 uint32_t polled
, int);
191 static void socal_flush_overflowq(socal_state_t
*, int, int);
192 static void socal_deferred_intr(void *);
193 static void socal_fix_harda(socal_state_t
*socalp
, int port
);
196 * SOC+ Circular Queue Management routines.
198 static int socal_cq_enque(socal_state_t
*, socal_port_t
*, cqe_t
*, int,
199 fcal_sleep_t
, fcal_packet_t
*, int);
204 static void socal_disp_err(socal_state_t
*, uint_t level
, char *mid
, char *msg
);
205 static void socal_wcopy(uint_t
*, uint_t
*, int);
208 * Set this bit to enable 64-bit sus mode
210 static int socal_64bitsbus
= 1;
213 * Default soc dma limits
216 static ddi_dma_lim_t default_socallim
= {
217 (ulong_t
)0, (ulong_t
)0xffffffff, (uint_t
)0xffffffff,
218 DEFAULT_BURSTSIZE
| BURST32
| BURST64
, 1, (25*1024)
221 static struct ddi_dma_attr socal_dma_attr
= {
222 DMA_ATTR_V0
, /* version */
223 (unsigned long long)0, /* addr_lo */
224 (unsigned long long)0xffffffff, /* addr_hi */
225 (unsigned long long)0xffffffff, /* count max */
226 (unsigned long long)4, /* align */
227 DEFAULT_BURSTSIZE
| BURST32
| BURST64
, /* burst size */
229 (unsigned long long)0xffffffff, /* maxxfer */
230 (unsigned long long)0xffffffff, /* seg */
236 static struct ddi_device_acc_attr socal_acc_attr
= {
237 (ushort_t
)DDI_DEVICE_ATTR_V0
, /* version */
238 (uchar_t
)DDI_STRUCTURE_BE_ACC
, /* endian flags */
239 (uchar_t
)DDI_STRICTORDER_ACC
/* data order */
242 static struct fcal_transport_ops socal_transport_ops
= {
244 socal_transport_poll
,
257 * Table used for setting the burst size in the soc+ config register
259 static int socal_burst32_table
[] = {
270 * Table for setting the burst size for 64-bit sbus mode in soc+'s CR
272 static int socal_burst64_table
[] = {
273 (SOCAL_CR_BURST_8
<< 8),
274 (SOCAL_CR_BURST_8
<< 8),
275 (SOCAL_CR_BURST_8
<< 8),
276 (SOCAL_CR_BURST_8
<< 8),
277 (SOCAL_CR_BURST_8
<< 8),
278 (SOCAL_CR_BURST_32
<< 8),
279 (SOCAL_CR_BURST_64
<< 8),
280 (SOCAL_CR_BURST_128
<< 8)
284 * Tables used to define the sizes of the Circular Queues
286 * To conserve DVMA/IOPB space, we make some of these queues small...
288 static int socal_req_entries
[] = {
289 SOCAL_SMALL_CQ_ENTRIES
, /* Error (reset, lip) requests */
290 SOCAL_MAX_CQ_ENTRIES
, /* Most commands */
291 0, /* Not currently used */
292 0 /* Not currently used */
295 static int socal_rsp_entries
[] = {
296 SOCAL_MAX_CQ_ENTRIES
, /* Solicited "SOC_OK" responses */
297 SOCAL_SMALL_CQ_ENTRIES
, /* Solicited error responses */
298 0, /* Unsolicited responses */
299 0 /* Not currently used */
306 static struct bus_ops socal_bus_ops
= {
308 nullbusmap
, /* int (*bus_map)() */
309 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */
310 0, /* int (*bus_add_intrspec)(); */
311 0, /* void (*bus_remove_intrspec)(); */
312 i_ddi_map_fault
, /* int (*bus_map_fault)() */
313 0, /* int (*bus_dma_map)() */
320 ddi_dma_mctl
, /* int (*bus_dma_ctl)() */
321 socal_bus_ctl
, /* int (*bus_ctl)() */
322 ddi_bus_prop_op
, /* int (*bus_prop_op*)() */
325 static struct cb_ops socal_cb_ops
= {
326 socal_open
, /* int (*cb_open)() */
327 socal_close
, /* int (*cb_close)() */
328 nodev
, /* int (*cb_strategy)() */
329 nodev
, /* int (*cb_print)() */
330 nodev
, /* int (*cb_dump)() */
331 nodev
, /* int (*cb_read)() */
332 nodev
, /* int (*cb_write)() */
333 socal_ioctl
, /* int (*cb_ioctl)() */
334 nodev
, /* int (*cb_devmap)() */
335 nodev
, /* int (*cb_mmap)() */
336 nodev
, /* int (*cb_segmap)() */
337 nochpoll
, /* int (*cb_chpoll)() */
338 ddi_prop_op
, /* int (*cb_prop_op)() */
339 0, /* struct streamtab *cb_str */
340 D_MP
|D_NEW
|D_HOTPLUG
, /* cb_flag */
342 nodev
, /* int (*cb_aread)() */
343 nodev
/* int (*cb_awrite)() */
347 * Soc driver ops structure.
350 static struct dev_ops socal_ops
= {
351 DEVO_REV
, /* devo_rev, */
353 socal_getinfo
, /* get_dev_info */
354 nulldev
, /* identify */
356 socal_attach
, /* attach */
357 socal_detach
, /* detach */
359 &socal_cb_ops
, /* driver operations */
360 &socal_bus_ops
, /* bus operations */
362 ddi_quiesce_not_supported
, /* quiesce */
366 * Driver private variables.
369 static void *socal_soft_state_p
= NULL
;
370 static ddi_dma_lim_t
*socallim
= NULL
;
372 static uchar_t socal_switch_to_alpa
[] = {
373 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
374 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
375 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
376 0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
377 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
378 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
379 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
380 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
381 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
382 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
383 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
384 0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
385 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
389 * Firmware related externs
391 extern uint32_t socal_ucode
[];
392 extern size_t socal_ucode_size
;
395 * This is the loadable module wrapper: "module configuration section".
398 #include <sys/modctl.h>
399 extern struct mod_ops mod_driverops
;
402 * Module linkage information for the kernel.
404 #define SOCAL_NAME "SOC+ FC-AL Host Adapter Driver"
405 static char socal_version
[] = "1.62 08/19/2008";
406 static struct modldrv modldrv
= {
407 &mod_driverops
, /* Type of module. This one is a driver */
409 &socal_ops
, /* driver ops */
412 static struct modlinkage modlinkage
= {
413 MODREV_1
, (void *)&modldrv
, NULL
417 * This is the module initialization/completion routines
421 static char socal_initmsg
[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
429 DEBUGF(4, (CE_CONT
, socal_initmsg
));
431 /* Allocate soft state. */
432 stat
= ddi_soft_state_init(&socal_soft_state_p
,
433 sizeof (socal_state_t
), SOCAL_INIT_ITEMS
);
437 /* Install the module */
438 stat
= mod_install(&modlinkage
);
440 ddi_soft_state_fini(&socal_soft_state_p
);
442 DEBUGF(4, (CE_CONT
, "socal: _init: return=%d\n", stat
));
451 if ((stat
= mod_remove(&modlinkage
)) != 0)
454 DEBUGF(4, (CE_CONT
, "socal: _fini: \n"));
456 ddi_soft_state_fini(&socal_soft_state_p
);
458 DEBUGF(4, (CE_CONT
, "socal: _fini: return=%d\n", stat
));
463 _info(struct modinfo
*modinfop
)
465 return (mod_info(&modlinkage
, modinfop
));
470 socal_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
473 socal_state_t
*socalp
;
474 struct ether_addr ourmacaddr
;
475 socal_port_t
*porta
, *portb
;
476 char buf
[MAXPATHLEN
];
487 instance
= ddi_get_instance(dip
);
489 DEBUGF(4, (CE_CONT
, "socal%d entering attach: cmd=%x\n", instance
,
492 if (cmd
== DDI_RESUME
) {
493 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
494 return (DDI_FAILURE
);
496 if (!socalp
->socal_shutdown
) {
497 /* our work is already done */
498 return (DDI_SUCCESS
);
500 if (socal_start(socalp
) != FCAL_SUCCESS
) {
501 return (DDI_FAILURE
);
503 DEBUGF(4, (CE_CONT
, "socal%d resumed\n", instance
));
504 return (DDI_SUCCESS
);
507 if (cmd
!= DDI_ATTACH
) {
508 return (DDI_FAILURE
);
511 if (ddi_dev_is_sid(dip
) != DDI_SUCCESS
) {
512 cmn_err(CE_WARN
, "socal%d probe: Not self-identifying",
514 return (DDI_FAILURE
);
517 /* If we are in a slave-slot, then we can't be used. */
518 if (ddi_slaveonly(dip
) == DDI_SUCCESS
) {
520 "socal%d attach failed: device in slave-only slot",
522 return (DDI_FAILURE
);
525 if (ddi_intr_hilevel(dip
, 0)) {
527 * Interrupt number '0' is a high-level interrupt.
528 * At this point you either add a special interrupt
529 * handler that triggers a soft interrupt at a lower level,
530 * or - more simply and appropriately here - you just
534 "socal%d attach failed: hilevel interrupt unsupported",
536 return (DDI_FAILURE
);
539 /* Allocate soft state. */
540 if (ddi_soft_state_zalloc(socal_soft_state_p
, instance
)
542 cmn_err(CE_WARN
, "socal%d attach failed: alloc soft state",
544 return (DDI_FAILURE
);
546 DEBUGF(4, (CE_CONT
, "socal%d attach: allocated soft state\n",
550 * Initialize the state structure.
552 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
553 if (socalp
== (socal_state_t
*)NULL
) {
554 cmn_err(CE_WARN
, "socal%d attach failed: bad soft state",
556 return (DDI_FAILURE
);
558 DEBUGF(4, (CE_CONT
, "socal%d: attach: soc soft state ptr=0x%p\n",
562 socallim
= &default_socallim
;
563 porta
= &socalp
->port_state
[0];
564 portb
= &socalp
->port_state
[1];
566 /* Get the full path name for displaying error messages */
567 cptr
= ddi_pathname(dip
, buf
);
568 (void) strcpy(socalp
->socal_name
, cptr
);
570 porta
->sp_unsol_cb
= NULL
;
571 portb
->sp_unsol_cb
= NULL
;
574 porta
->sp_board
= socalp
;
575 portb
->sp_board
= socalp
;
577 porta
->sp_lilpmap_valid
= 0;
578 portb
->sp_lilpmap_valid
= 0;
581 * If an hard loop-id property is present, then the port is going
582 * to be used in target-mode so set the target-mode flag.
584 loop_id
= ddi_getprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
585 "port0-loop-id", 127);
586 if (loop_id
>= 0 && loop_id
<= 126) {
587 porta
->sp_status
|= PORT_TARGET_MODE
;
588 porta
->sp_hard_alpa
= socal_switch_to_alpa
[loop_id
];
589 } else porta
->sp_hard_alpa
= 0xfe;
591 loop_id
= ddi_getprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
592 "port1-loop-id", 127);
593 if (loop_id
>= 0 && loop_id
<= 126) {
594 portb
->sp_status
|= PORT_TARGET_MODE
;
595 portb
->sp_hard_alpa
= socal_switch_to_alpa
[loop_id
];
596 } else portb
->sp_hard_alpa
= 0xfe;
598 /* Get out Node wwn and calculate port wwns */
599 rval
= ddi_prop_op(DDI_DEV_T_ANY
, dip
,
600 PROP_LEN_AND_VAL_ALLOC
, DDI_PROP_DONTPASS
|
601 DDI_PROP_CANSLEEP
, "wwn", (caddr_t
)&wwn
, &i
);
603 if ((rval
!= DDI_PROP_SUCCESS
) || (i
< FC_WWN_SIZE
) ||
604 (bcmp(wwn
, "00000000", FC_WWN_SIZE
) == 0)) {
605 (void) localetheraddr((struct ether_addr
*)NULL
, &ourmacaddr
);
607 bcopy((caddr_t
)&ourmacaddr
, (caddr_t
)&s
, sizeof (short));
608 socalp
->socal_n_wwn
.w
.wwn_hi
= s
;
609 bcopy((caddr_t
)&ourmacaddr
+2,
610 (caddr_t
)&socalp
->socal_n_wwn
.w
.wwn_lo
,
612 socalp
->socal_n_wwn
.w
.naa_id
= NAA_ID_IEEE
;
613 socalp
->socal_n_wwn
.w
.nport_id
= 0;
615 bcopy((caddr_t
)wwn
, (caddr_t
)&socalp
->socal_n_wwn
, FC_WWN_SIZE
);
618 if (rval
== DDI_SUCCESS
)
619 kmem_free((void *)wwn
, i
);
621 for (i
= 0; i
< FC_WWN_SIZE
; i
++) {
622 (void) sprintf(&socalp
->socal_stats
.node_wwn
[i
<< 1],
623 "%02x", socalp
->socal_n_wwn
.raw_wwn
[i
]);
625 DEBUGF(4, (CE_CONT
, "socal%d attach: node wwn: %s\n",
626 instance
, socalp
->socal_stats
.node_wwn
));
628 bcopy((caddr_t
)&socalp
->socal_n_wwn
, (caddr_t
)&porta
->sp_p_wwn
,
630 bcopy((caddr_t
)&socalp
->socal_n_wwn
, (caddr_t
)&portb
->sp_p_wwn
,
632 porta
->sp_p_wwn
.w
.naa_id
= NAA_ID_IEEE_EXTENDED
;
633 portb
->sp_p_wwn
.w
.naa_id
= NAA_ID_IEEE_EXTENDED
;
634 porta
->sp_p_wwn
.w
.nport_id
= instance
*2;
635 portb
->sp_p_wwn
.w
.nport_id
= instance
*2+1;
637 for (i
= 0; i
< FC_WWN_SIZE
; i
++) {
638 (void) sprintf(&socalp
->socal_stats
.port_wwn
[0][i
<< 1],
639 "%02x", porta
->sp_p_wwn
.raw_wwn
[i
]);
640 (void) sprintf(&socalp
->socal_stats
.port_wwn
[1][i
<< 1],
641 "%02x", portb
->sp_p_wwn
.raw_wwn
[i
]);
643 DEBUGF(4, (CE_CONT
, "socal%d attach: porta wwn: %s\n",
644 instance
, socalp
->socal_stats
.port_wwn
[0]));
645 DEBUGF(4, (CE_CONT
, "socal%d attach: portb wwn: %s\n",
646 instance
, socalp
->socal_stats
.port_wwn
[1]));
648 if ((porta
->sp_transport
= (fcal_transport_t
*)
649 kmem_zalloc(sizeof (fcal_transport_t
), KM_SLEEP
)) == NULL
) {
650 socal_disp_err(socalp
, CE_WARN
, "attach.4011",
651 "attach failed: unable to alloc xport struct");
655 if ((portb
->sp_transport
= (fcal_transport_t
*)
656 kmem_zalloc(sizeof (fcal_transport_t
), KM_SLEEP
)) == NULL
) {
657 socal_disp_err(socalp
, CE_WARN
, "attach.4012",
658 "attach failed: unable to alloc xport struct");
661 DEBUGF(4, (CE_CONT
, "socal%d attach: allocated transport structs\n",
665 * Map the external ram and registers for SOC+.
666 * Note: Soc+ sbus host adapter provides 3 register definition
667 * but on-board Soc+'s may have only one register definition.
669 if ((ddi_dev_nregs(dip
, &i
) == DDI_SUCCESS
) && (i
== 1)) {
671 if (ddi_map_regs(dip
, 0, &socalp
->socal_xrp
, 0, 0)
673 socalp
->socal_xrp
= NULL
;
674 socal_disp_err(socalp
, CE_WARN
, "attach.4020",
675 "attach failed: unable to map XRAM");
679 socalp
->socal_rp
= (socal_reg_t
*)(socalp
->socal_xrp
+
683 if (ddi_map_regs(dip
, 0, &socalp
->socal_eeprom
, 0, 0) !=
685 socalp
->socal_eeprom
= NULL
;
686 socal_disp_err(socalp
, CE_WARN
, "attach.4010",
687 "attach failed: unable to map eeprom");
690 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped eeprom 0x%p\n",
691 instance
, socalp
->socal_eeprom
));
693 if (ddi_map_regs(dip
, 1, &socalp
->socal_xrp
, 0, 0) !=
695 socalp
->socal_xrp
= NULL
;
696 socal_disp_err(socalp
, CE_WARN
, "attach.4020",
697 "attach failed: unable to map XRAM");
700 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped xram 0x%p\n",
701 instance
, socalp
->socal_xrp
));
703 if (ddi_map_regs(dip
, 2, (caddr_t
*)&socalp
->socal_rp
, 0, 0) !=
705 socalp
->socal_rp
= NULL
;
706 socal_disp_err(socalp
, CE_WARN
, "attach.4030",
707 "attach failed: unable to map registers");
710 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped regs 0x%p\n",
711 instance
, socalp
->socal_rp
));
714 * Check to see we really have a SOC+ Host Adapter card installed
716 if (ddi_peek32(dip
, (int32_t *)&socalp
->socal_rp
->socal_csr
.w
,
717 (int32_t *)NULL
) != DDI_SUCCESS
) {
718 socal_disp_err(socalp
, CE_WARN
, "attach.4040",
719 "attach failed: unable to access status register");
722 /* now that we have our registers mapped make sure soc+ reset */
723 socal_disable(socalp
);
725 /* try defacing a spot in XRAM */
726 if (ddi_poke32(dip
, (int32_t *)(socalp
->socal_xrp
+ SOCAL_XRAM_UCODE
),
727 0xdefaced) != DDI_SUCCESS
) {
728 socal_disp_err(socalp
, CE_WARN
, "attach.4050",
729 "attach failed: unable to write host adapter XRAM");
733 /* see if it stayed defaced */
734 if (ddi_peek32(dip
, (int32_t *)(socalp
->socal_xrp
+ SOCAL_XRAM_UCODE
),
737 socal_disp_err(socalp
, CE_WARN
, "attach.4051",
738 "attach failed: unable to access host adapter XRAM");
743 for (i
= 0; i
< 4; i
++) {
744 socalp
->socal_rp
->socal_cr
.w
&=
745 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
746 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
747 cptr
= (char *)(socal_xrambuf
+ (i
*0x10000));
748 bcopy((caddr_t
)socalp
->socal_xrp
, (caddr_t
)cptr
, 0x10000);
750 socalp
->socal_rp
->socal_cr
.w
&= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
753 DEBUGF(4, (CE_CONT
, "socal%d attach: read xram\n", instance
));
755 if (y
!= 0xdefaced) {
756 socal_disp_err(socalp
, CE_WARN
, "attach.4052",
757 "attach failed: read/write mismatch in XRAM");
761 /* Point to the SOC XRAM CQ Descriptor locations. */
762 socalp
->xram_reqp
= (soc_cq_t
*)(socalp
->socal_xrp
+
763 SOCAL_XRAM_REQ_DESC
);
764 socalp
->xram_rspp
= (soc_cq_t
*)(socalp
->socal_xrp
+
765 SOCAL_XRAM_RSP_DESC
);
767 if ((socalp
->socal_ksp
= kstat_create("socal", instance
, "statistics",
768 "controller", KSTAT_TYPE_RAW
, sizeof (struct socal_stats
),
769 KSTAT_FLAG_VIRTUAL
)) == NULL
) {
770 socal_disp_err(socalp
, CE_WARN
, "attach.4053",
771 "unable to create kstats");
773 socalp
->socal_stats
.version
= 2;
774 (void) sprintf(socalp
->socal_stats
.drvr_name
,
775 "%s: %s", SOCAL_NAME
, socal_version
);
776 socalp
->socal_stats
.pstats
[0].port
= 0;
777 socalp
->socal_stats
.pstats
[1].port
= 1;
778 socalp
->socal_ksp
->ks_data
= (void *)&socalp
->socal_stats
;
779 kstat_install(socalp
->socal_ksp
);
783 * Install a dummy interrupt routine.
785 if (ddi_add_intr(dip
,
790 (caddr_t
)socalp
) != DDI_SUCCESS
) {
791 socal_disp_err(socalp
, CE_WARN
, "attach.4060",
792 "attach failed: unable to install interrupt handler");
796 ddi_set_driver_private(dip
, socalp
);
798 /* initialize the interrupt mutex */
799 mutex_init(&socalp
->k_imr_mtx
, NULL
, MUTEX_DRIVER
,
800 (void *)socalp
->iblkc
);
802 mutex_init(&socalp
->board_mtx
, NULL
, MUTEX_DRIVER
,
803 (void *)socalp
->iblkc
);
804 mutex_init(&socalp
->ioctl_mtx
, NULL
, MUTEX_DRIVER
,
805 (void *)socalp
->iblkc
);
807 /* initialize the abort mutex */
808 mutex_init(&socalp
->abort_mtx
, NULL
, MUTEX_DRIVER
,
809 (void *)socalp
->iblkc
);
811 cv_init(&socalp
->board_cv
, NULL
, CV_DRIVER
, NULL
);
813 "socal%d: attach: inited imr mutex, board mutex, board cv\n",
816 /* init the port mutexes */
817 mutex_init(&porta
->sp_mtx
, NULL
, MUTEX_DRIVER
, socalp
->iblkc
);
818 cv_init(&porta
->sp_cv
, NULL
, CV_DRIVER
, NULL
);
819 mutex_init(&portb
->sp_mtx
, NULL
, MUTEX_DRIVER
, socalp
->iblkc
);
820 cv_init(&portb
->sp_cv
, NULL
, CV_DRIVER
, NULL
);
821 DEBUGF(4, (CE_CONT
, "socal%d: attach: inited port mutexes and cvs\n",
824 /* get local copy of service params */
825 socal_wcopy((uint_t
*)socalp
->socal_xrp
+ SOCAL_XRAM_SERV_PARAMS
,
826 (uint_t
*)socalp
->socal_service_params
, SOCAL_SVC_LENGTH
);
827 DEBUGF(4, (CE_CONT
, "socal%d: attach: got service params\n", instance
));
829 * Initailize the FCAL transport interface.
831 socal_init_transport_interface(socalp
);
832 DEBUGF(4, (CE_CONT
, "socal%d: attach: initalized transport interface\n",
836 * Allocate request and response queues and init their mutexs.
838 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
839 if (socal_cqalloc_init(socalp
, i
) != FCAL_SUCCESS
) {
843 DEBUGF(4, (CE_CONT
, "socal%d: attach: allocated cqs\n", instance
));
846 * Adjust the burst size we'll use.
848 burstsize
= ddi_dma_burstsizes(socalp
->request
[0].skc_dhandle
);
849 DEBUGF(4, (CE_CONT
, "socal%d: attach: burstsize = 0x%x\n",
850 instance
, burstsize
));
851 j
= burstsize
& BURSTSIZE_MASK
;
852 for (i
= 0; socal_burst32_table
[i
] != SOCAL_CR_BURST_64
; i
++)
853 if (!(j
>>= 1)) break;
855 socalp
->socal_cfg
= (socalp
->socal_cfg
& ~SOCAL_CR_SBUS_BURST_SIZE_MASK
)
856 | socal_burst32_table
[i
];
858 if (socal_64bitsbus
) {
859 if (ddi_dma_set_sbus64(socalp
->request
[0].skc_dhandle
,
860 socal_dma_attr
.dma_attr_burstsizes
| BURST128
) ==
862 DEBUGF(4, (CE_CONT
, "socal%d: enabled 64 bit sbus\n",
864 socalp
->socal_cfg
|= SOCAL_CR_SBUS_ENHANCED
;
865 burstsize
= ddi_dma_burstsizes(socalp
->request
[0].
867 DEBUGF(4, (CE_CONT
, "socal%d: attach: 64bit burstsize = 0x%x\n",
868 instance
, burstsize
));
869 j
= burstsize
& BURSTSIZE_MASK
;
870 for (i
= 0; socal_burst64_table
[i
] !=
871 (SOCAL_CR_BURST_128
<< 8); i
++)
875 socalp
->socal_cfg
= (socalp
->socal_cfg
&
876 ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK
) |
877 socal_burst64_table
[i
];
881 ddi_remove_intr(dip
, 0, socalp
->iblkc
);
882 socalp
->iblkc
= (void *)NULL
;
884 * Install the interrupt routine.
886 if (ddi_add_intr(dip
,
891 (caddr_t
)socalp
) != DDI_SUCCESS
) {
892 socal_disp_err(socalp
, CE_WARN
, "attach.4060",
893 "attach failed: unable to install interrupt handler");
897 DEBUGF(4, (CE_CONT
, "socal%d: attach: set config reg %x\n",
898 instance
, socalp
->socal_cfg
));
900 if (ddi_create_minor_node(dip
, SOCAL_PORTA_NAME
, S_IFCHR
,
901 instance
*N_SOCAL_NPORTS
, SOCAL_NT_PORT
, 0) != DDI_SUCCESS
)
903 if (ddi_create_minor_node(dip
, SOCAL_PORTB_NAME
, S_IFCHR
,
904 instance
*N_SOCAL_NPORTS
+1, SOCAL_NT_PORT
, 0) != DDI_SUCCESS
)
907 if (socal_start(socalp
) != FCAL_SUCCESS
)
909 DEBUGF(4, (CE_CONT
, "socal%d: attach: soc+ started\n", instance
));
913 DEBUGF(2, (CE_CONT
, "socal%d: attach O.K.\n\n", instance
));
915 return (DDI_SUCCESS
);
918 DEBUGF(4, (CE_CONT
, "socal%d: attach: DDI_FAILURE\n", instance
));
920 /* Make sure soc reset */
921 socal_disable(socalp
);
923 /* let detach do the dirty work */
924 (void) socal_dodetach(dip
);
926 return (DDI_FAILURE
);
930 socal_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
933 socal_state_t
*socalp
;
940 DEBUGF(4, (CE_CONT
, "socal: suspend called\n"));
942 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
943 return (DDI_FAILURE
);
946 * If any of the ports are in target-mode, don't suspend
948 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
949 if (socalp
->port_state
[i
].sp_status
& PORT_TARGET_MODE
)
950 return (DDI_FAILURE
);
953 /* do not restart socal after reset */
954 socal_force_reset((void *)socalp
, 0, DONT_RESET_PORT
);
956 return (DDI_SUCCESS
);
959 DEBUGF(4, (CE_CONT
, "socal: detach called\n"));
960 resp
= socal_dodetach(dip
);
961 if (resp
== DDI_SUCCESS
)
962 ddi_set_driver_private(dip
, NULL
);
966 return (DDI_FAILURE
);
971 socal_dodetach(dev_info_t
*dip
)
974 int instance
= ddi_get_instance(dip
);
976 socal_state_t
*socalp
;
978 socal_unsol_cb_t
*cb
, *cbn
= NULL
;
980 /* Get the soft state struct. */
981 if ((socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
)) == 0) {
982 return (DDI_FAILURE
);
986 * If somebody is still attached to us from above fail
989 mutex_enter(&socalp
->board_mtx
);
990 if (socalp
->socal_busy
> 0) {
991 mutex_exit(&socalp
->board_mtx
);
992 return (DDI_FAILURE
);
994 /* mark socal_busy = -1 to disallow sftm attach */
995 socalp
->socal_busy
= -1;
996 mutex_exit(&socalp
->board_mtx
);
998 /* Make sure soc+ reset */
999 mutex_enter(&socalp
->k_imr_mtx
);
1000 socal_disable(socalp
);
1001 mutex_exit(&socalp
->k_imr_mtx
);
1003 /* remove soc+ interrupt */
1004 if (socalp
->iblkc
!= (void *)NULL
) {
1005 ddi_remove_intr(dip
, (uint_t
)0, socalp
->iblkc
);
1007 "socal%d: detach: Removed SOC+ interrupt from ddi\n",
1011 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
1012 portp
= &socalp
->port_state
[i
];
1013 mutex_destroy(&portp
->sp_mtx
);
1014 cv_destroy(&portp
->sp_cv
);
1015 mutex_destroy(&portp
->sp_transport
->fcal_mtx
);
1016 cv_destroy(&portp
->sp_transport
->fcal_cv
);
1017 kmem_free((void *)portp
->sp_transport
,
1018 sizeof (fcal_transport_t
));
1019 for (cb
= portp
->sp_unsol_cb
; cb
!= (socal_unsol_cb_t
*)NULL
;
1022 kmem_free((void *)cb
, sizeof (socal_unsol_cb_t
));
1024 portp
->sp_unsol_cb
= (socal_unsol_cb_t
*)NULL
;
1028 * Free request queues, if allocated
1030 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1031 /* Free the queues and destroy their mutexes. */
1032 mutex_destroy(&socalp
->request
[i
].skc_mtx
);
1033 mutex_destroy(&socalp
->response
[i
].skc_mtx
);
1034 cv_destroy(&socalp
->request
[i
].skc_cv
);
1035 cv_destroy(&socalp
->response
[i
].skc_cv
);
1037 if (socalp
->request
[i
].skc_dhandle
) {
1038 (void) ddi_dma_unbind_handle(socalp
->
1039 request
[i
].skc_dhandle
);
1040 ddi_dma_free_handle(&socalp
->request
[i
].skc_dhandle
);
1042 if (socalp
->request
[i
].skc_cq_raw
) {
1043 ddi_dma_mem_free(&socalp
->request
[i
].skc_acchandle
);
1044 socalp
->request
[i
].skc_cq_raw
= NULL
;
1045 socalp
->request
[i
].skc_cq
= NULL
;
1047 if (socalp
->response
[i
].skc_dhandle
) {
1048 (void) ddi_dma_unbind_handle(socalp
->
1049 response
[i
].skc_dhandle
);
1050 ddi_dma_free_handle(&socalp
->response
[i
].skc_dhandle
);
1052 if (socalp
->response
[i
].skc_cq_raw
) {
1053 ddi_dma_mem_free(&socalp
->response
[i
].skc_acchandle
);
1054 socalp
->response
[i
].skc_cq_raw
= NULL
;
1055 socalp
->response
[i
].skc_cq
= NULL
;
1057 if (socalp
->request
[i
].deferred_intr_timeoutid
) {
1058 (void) untimeout(socalp
->
1059 request
[i
].deferred_intr_timeoutid
);
1061 if (socalp
->response
[i
].deferred_intr_timeoutid
) {
1062 (void) untimeout(socalp
->
1063 response
[i
].deferred_intr_timeoutid
);
1067 mutex_destroy(&socalp
->abort_mtx
);
1068 mutex_destroy(&socalp
->board_mtx
);
1069 mutex_destroy(&socalp
->ioctl_mtx
);
1070 cv_destroy(&socalp
->board_cv
);
1073 * Free soc data buffer pool
1075 if (socalp
->pool_dhandle
) {
1076 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
1077 ddi_dma_free_handle(&socalp
->pool_dhandle
);
1080 ddi_dma_mem_free(&socalp
->pool_acchandle
);
1083 /* release register maps */
1085 if (socalp
->socal_eeprom
!= NULL
) {
1086 ddi_unmap_regs(dip
, 0, &socalp
->socal_eeprom
, 0, 0);
1090 if (socalp
->socal_xrp
!= NULL
) {
1091 ddi_unmap_regs(dip
, 1, &socalp
->socal_xrp
, 0, 0);
1094 /* Unmap registers */
1095 if (socalp
->socal_rp
!= NULL
) {
1096 ddi_unmap_regs(dip
, 2, (caddr_t
*)&socalp
->socal_rp
, 0, 0);
1099 if (socalp
->socal_ksp
!= NULL
)
1100 kstat_delete(socalp
->socal_ksp
);
1102 mutex_destroy(&socalp
->k_imr_mtx
);
1104 ddi_remove_minor_node(dip
, NULL
);
1106 ddi_soft_state_free(socal_soft_state_p
, instance
);
1108 return (DDI_SUCCESS
);
1113 socal_bus_ctl(dev_info_t
*dip
, dev_info_t
*rip
, ddi_ctl_enum_t op
,
1120 case DDI_CTLOPS_REPORTDEV
:
1121 port
= ddi_getprop(DDI_DEV_T_ANY
, rip
, DDI_PROP_DONTPASS
,
1122 SOCAL_PORT_NO_PROP
, -1);
1123 if ((port
< 0) || (port
> 1)) {
1124 port
= ddi_getprop(DDI_DEV_T_ANY
, rip
,
1125 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1127 /* log text identifying this driver (d) & its child (r) */
1128 cmn_err(CE_CONT
, "?%s%d at %s%d: socal_port %d\n",
1129 ddi_driver_name(rip
), ddi_get_instance(rip
),
1130 ddi_driver_name(dip
), ddi_get_instance(dip
),
1134 case DDI_CTLOPS_INITCHILD
: {
1135 dev_info_t
*child_dip
= (dev_info_t
*)a
;
1136 char name
[MAXNAMELEN
];
1137 socal_state_t
*socalp
;
1139 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
1140 return (DDI_FAILURE
);
1142 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1143 DDI_PROP_DONTPASS
, SOCAL_PORT_NO_PROP
, -1);
1145 if ((port
< 0) || (port
> 1)) {
1146 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1147 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1148 if ((port
< 0) || (port
> 1)) {
1149 return (DDI_NOT_WELL_FORMED
);
1152 mutex_enter(&socalp
->board_mtx
);
1153 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
1154 if (socalp
->port_state
[port
].sp_status
&
1155 (PORT_CHILD_INIT
| PORT_TARGET_MODE
)) {
1156 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1157 mutex_exit(&socalp
->board_mtx
);
1158 return (DDI_FAILURE
);
1160 socalp
->socal_busy
++;
1161 socalp
->port_state
[port
].sp_status
|= PORT_CHILD_INIT
;
1162 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1163 mutex_exit(&socalp
->board_mtx
);
1164 ddi_set_parent_data(child_dip
,
1165 socalp
->port_state
[port
].sp_transport
);
1166 (void) sprintf((char *)name
, "%x,0", port
);
1167 ddi_set_name_addr(child_dip
, name
);
1171 case DDI_CTLOPS_UNINITCHILD
: {
1172 dev_info_t
*child_dip
= (dev_info_t
*)a
;
1173 socal_state_t
*socalp
;
1175 socalp
= ddi_get_driver_private(dip
);
1176 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1177 DDI_PROP_DONTPASS
, SOCAL_PORT_NO_PROP
, -1);
1179 if ((port
< 0) || (port
> 1)) {
1180 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1181 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1182 if ((port
< 0) || (port
> 1)) {
1183 return (DDI_NOT_WELL_FORMED
);
1187 ddi_set_parent_data(child_dip
, NULL
);
1188 (void) ddi_set_name_addr(child_dip
, NULL
);
1189 mutex_enter(&socalp
->board_mtx
);
1190 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
1191 socalp
->socal_busy
--;
1192 socalp
->port_state
[port
].sp_status
&= ~PORT_CHILD_INIT
;
1193 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1194 mutex_exit(&socalp
->board_mtx
);
1199 case DDI_CTLOPS_IOMIN
: {
1203 val
= maxbit(val
, socallim
->dlim_minxfer
);
1205 * The 'arg' value of nonzero indicates 'streaming' mode.
1206 * If in streaming mode, pick the largest of our burstsizes
1207 * available and say that that is our minimum value (modulo
1210 if ((int)(uintptr_t)a
) {
1212 1<<(ddi_fls(socallim
->dlim_burstsizes
)-1));
1215 1<<(ddi_ffs(socallim
->dlim_burstsizes
)-1));
1219 return (ddi_ctlops(dip
, rip
, op
, a
, v
));
1223 * These ops are not available on this nexus.
1226 case DDI_CTLOPS_DMAPMAPC
:
1227 case DDI_CTLOPS_REGSIZE
:
1228 case DDI_CTLOPS_NREGS
:
1229 case DDI_CTLOPS_AFFINITY
:
1230 case DDI_CTLOPS_SIDDEV
:
1231 case DDI_CTLOPS_POKE
:
1232 case DDI_CTLOPS_PEEK
:
1233 return (DDI_FAILURE
);
1235 case DDI_CTLOPS_SLAVEONLY
:
1236 case DDI_CTLOPS_REPORTINT
:
1239 * Remaining requests get passed up to our parent
1241 DEBUGF(2, (CE_CONT
, "%s%d: op (%d) from %s%d\n",
1242 ddi_get_name(dip
), ddi_get_instance(dip
),
1243 op
, ddi_get_name(rip
), ddi_get_instance(rip
)));
1244 return (ddi_ctlops(dip
, rip
, op
, a
, v
));
1247 return (DDI_SUCCESS
);
1254 * socal_getinfo() - Given the device number, return the devinfo
1255 * pointer or the instance number. Note: this routine must be
1256 * successful on DDI_INFO_DEVT2INSTANCE even before attach.
1259 socal_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
,
1263 socal_state_t
*socalp
;
1265 instance
= getminor((dev_t
)arg
) / 2;
1268 case DDI_INFO_DEVT2DEVINFO
:
1269 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
1271 *result
= socalp
->dip
;
1276 case DDI_INFO_DEVT2INSTANCE
:
1277 *result
= (void *)(uintptr_t)instance
;
1281 return (DDI_FAILURE
);
1284 return (DDI_SUCCESS
);
1289 socal_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
1291 int instance
= getminor(*devp
)/2;
1292 socal_state_t
*socalp
=
1293 ddi_get_soft_state(socal_soft_state_p
, instance
);
1294 socal_port_t
*port_statep
;
1300 port
= getminor(*devp
)%2;
1301 port_statep
= &socalp
->port_state
[port
];
1303 mutex_enter(&port_statep
->sp_mtx
);
1304 port_statep
->sp_status
|= PORT_OPEN
;
1305 mutex_exit(&port_statep
->sp_mtx
);
1307 "socal%d: open of port %d\n", instance
, port
));
1313 socal_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred_p
)
1315 int instance
= getminor(dev
)/2;
1316 socal_state_t
*socalp
=
1317 ddi_get_soft_state(socal_soft_state_p
, instance
);
1318 socal_port_t
*port_statep
;
1321 port
= getminor(dev
)%2;
1322 port_statep
= &socalp
->port_state
[port
];
1324 mutex_enter(&port_statep
->sp_mtx
);
1325 port_statep
->sp_status
&= ~PORT_OPEN
;
1326 mutex_exit(&port_statep
->sp_mtx
);
1328 "socal%d: clsoe of port %d\n", instance
, port
));
1334 socal_ioctl(dev_t dev
,
1335 int cmd
, intptr_t arg
, int mode
, cred_t
*cred_p
, int *rval_p
)
1337 int instance
= getminor(dev
)/2;
1338 socal_state_t
*socalp
=
1339 ddi_get_soft_state(socal_soft_state_p
, instance
);
1341 socal_port_t
*port_statep
;
1345 int retval
= FCAL_SUCCESS
;
1346 la_els_adisc_t
*adisc_pl
;
1347 la_els_rls_reply_t
*rls_pl
;
1349 char *buffer
, tmp
[10];
1350 struct socal_fm_version ver
;
1351 #ifdef _MULTI_DATAMODEL
1352 struct socal_fm_version32
{
1353 uint_t fcode_ver_len
;
1354 uint_t mcode_ver_len
;
1355 uint_t prom_ver_len
;
1356 caddr32_t fcode_ver
;
1357 caddr32_t mcode_ver
;
1370 DEBUGF(4, (CE_CONT
, "socal%d ioctl: got command %x\n", instance
, cmd
));
1371 port
= getminor(dev
)%2;
1374 case FCIO_FCODE_MCODE_VERSION
:
1375 #ifdef _MULTI_DATAMODEL
1376 switch (ddi_model_convert_from(mode
& FMODELS
)) {
1377 case DDI_MODEL_ILP32
:
1379 if (ddi_copyin((caddr_t
)arg
,
1380 (caddr_t
)&ver32
, sizeof (ver32
),
1384 ver32
.fcode_ver_len
;
1386 ver32
.mcode_ver_len
;
1390 (caddr_t
)(uintptr_t)ver32
.fcode_ver
;
1392 (caddr_t
)(uintptr_t)ver32
.mcode_ver
;
1394 (caddr_t
)(uintptr_t)ver32
.prom_ver
;
1396 case DDI_MODEL_NONE
:
1397 if (ddi_copyin((caddr_t
)arg
,
1398 (caddr_t
)&ver
, sizeof (ver
),
1402 #else /* _MULTI_DATAMODEL */
1403 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ver
,
1404 sizeof (ver
), mode
) == -1)
1406 #endif /* _MULTI_DATAMODEL */
1408 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
1409 PROP_LEN_AND_VAL_ALLOC
, DDI_PROP_DONTPASS
|
1410 DDI_PROP_CANSLEEP
, "version", (caddr_t
)&buffer
,
1411 &i
) != DDI_PROP_SUCCESS
)
1413 if (i
< ver
.fcode_ver_len
)
1414 ver
.fcode_ver_len
= i
;
1415 if (ddi_copyout((caddr_t
)buffer
,
1416 (caddr_t
)ver
.fcode_ver
, ver
.fcode_ver_len
,
1418 kmem_free((caddr_t
)buffer
, i
);
1421 kmem_free((caddr_t
)buffer
, i
);
1422 if (socalp
->socal_eeprom
) {
1423 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1425 &socalp
->request
[i
].skc_mtx
);
1427 &socalp
->response
[i
].skc_mtx
);
1429 i
= socalp
->socal_rp
->socal_cr
.w
;
1430 socalp
->socal_rp
->socal_cr
.w
&=
1431 ~SOCAL_CR_EEPROM_BANK_MASK
;
1432 socalp
->socal_rp
->socal_cr
.w
|= 3 << 16;
1433 if (ver
.prom_ver_len
> 10)
1434 ver
.prom_ver_len
= 10;
1435 bcopy((caddr_t
)socalp
->socal_eeprom
+ (unsigned)
1437 socalp
->socal_rp
->socal_cr
.w
= i
;
1438 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
1439 mutex_exit(&socalp
->request
[i
].skc_mtx
);
1441 &socalp
->response
[i
].skc_mtx
);
1443 if (ddi_copyout((caddr_t
)tmp
,
1444 (caddr_t
)ver
.prom_ver
,
1445 ver
.prom_ver_len
, mode
) == -1)
1448 ver
.prom_ver_len
= 0;
1450 ver
.mcode_ver_len
= 0;
1451 #ifdef _MULTI_DATAMODEL
1453 ver32
.fcode_ver_len
= ver
.fcode_ver_len
;
1454 ver32
.mcode_ver_len
= ver
.mcode_ver_len
;
1455 ver32
.prom_ver_len
= ver
.prom_ver_len
;
1456 ver32
.fcode_ver
= (caddr32_t
)(uintptr_t)
1458 ver32
.mcode_ver
= (caddr32_t
)(uintptr_t)
1460 ver32
.prom_ver
= (caddr32_t
)(uintptr_t)
1462 if (ddi_copyout((caddr_t
)&ver32
,
1463 (caddr_t
)arg
, sizeof (ver32
),
1467 #endif /* _MULTI_DATAMODEL */
1468 if (ddi_copyout((caddr_t
)&ver
, (caddr_t
)arg
,
1469 sizeof (struct socal_fm_version
), mode
) == -1)
1472 case FCIO_LOADUCODE
:
1473 mutex_enter(&socalp
->k_imr_mtx
);
1474 socal_disable(socalp
);
1475 mutex_exit(&socalp
->k_imr_mtx
);
1476 if (copyin((caddr_t
)arg
, (caddr_t
)socal_ucode
, 0x10000)
1479 /* restart socal after resetting */
1480 (void) socal_force_reset((void *)socalp
, 0,
1484 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1485 mutex_enter(&socalp
->request
[i
].skc_mtx
);
1486 mutex_enter(&socalp
->response
[i
].skc_mtx
);
1488 for (i
= 0; i
< 4; i
++) {
1489 offset
= arg
+(0x10000 * i
);
1490 socalp
->socal_rp
->socal_cr
.w
&=
1491 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
1492 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
1493 (void) copyout((caddr_t
)socalp
->socal_xrp
,
1494 (caddr_t
)(uintptr_t)offset
, 0x10000);
1496 socalp
->socal_rp
->socal_cr
.w
&=
1497 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
1498 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
1499 mutex_exit(&socalp
->request
[i
].skc_mtx
);
1500 mutex_exit(&socalp
->response
[i
].skc_mtx
);
1504 case FCIO_DUMPXRAMBUF
:
1505 (void) copyout((caddr_t
)socal_xrambuf
, (caddr_t
)arg
,
1510 mutex_enter(&socalp
->ioctl_mtx
);
1511 if (socal_getmap(socalp
, port
, (caddr_t
)arg
, 0, 0) ==
1513 retval
= FCAL_ALLOC_FAILED
;
1514 mutex_exit(&socalp
->ioctl_mtx
);
1516 case FCIO_BYPASS_DEV
:
1517 mutex_enter(&socalp
->ioctl_mtx
);
1518 retval
= socal_bypass_dev((void *)socalp
, port
, arg
);
1519 mutex_exit(&socalp
->ioctl_mtx
);
1521 case FCIO_FORCE_LIP
:
1522 mutex_enter(&socalp
->ioctl_mtx
);
1523 retval
= socal_force_lip((void *)socalp
, port
, 0,
1525 mutex_exit(&socalp
->ioctl_mtx
);
1527 case FCIO_FORCE_OFFLINE
:
1528 mutex_enter(&socalp
->ioctl_mtx
);
1529 retval
= socal_force_offline((void *)socalp
, port
, 0);
1530 mutex_exit(&socalp
->ioctl_mtx
);
1532 case FCIO_ADISC_ELS
:
1535 (la_els_adisc_t
*)kmem_zalloc(
1536 sizeof (la_els_adisc_t
),
1537 KM_NOSLEEP
)) == NULL
)
1540 if (copyin((caddr_t
)arg
, (caddr_t
)adisc_pl
,
1541 sizeof (la_els_adisc_t
)) == -1) {
1542 kmem_free((void *)adisc_pl
,
1543 sizeof (la_els_adisc_t
));
1546 mutex_enter(&socalp
->ioctl_mtx
);
1547 retval
= socal_issue_adisc(socalp
, port
,
1550 mutex_exit(&socalp
->ioctl_mtx
);
1552 if (retval
== FCAL_SUCCESS
) {
1553 if (copyout((caddr_t
)adisc_pl
, (caddr_t
)arg
,
1554 sizeof (la_els_adisc_t
)) == -1) {
1555 kmem_free((void *)adisc_pl
,
1556 sizeof (la_els_adisc_t
));
1561 kmem_free((void *)adisc_pl
, sizeof (la_els_adisc_t
));
1564 case FCIO_LINKSTATUS
:
1568 (la_els_rls_reply_t
*)
1569 kmem_zalloc(sizeof (la_els_rls_reply_t
),
1570 KM_NOSLEEP
)) == NULL
)
1573 if (copyin((caddr_t
)arg
, (caddr_t
)rls_pl
,
1574 sizeof (la_els_rls_reply_t
)) == -1) {
1575 kmem_free((void *)rls_pl
,
1576 sizeof (la_els_rls_reply_t
));
1579 dest
= (rls_pl
->mbz
[0] << 16) + (rls_pl
->mbz
[1] << 8) +
1581 mutex_enter(&socalp
->ioctl_mtx
);
1582 retval
= socal_issue_rls(socalp
, port
, dest
,
1584 mutex_exit(&socalp
->ioctl_mtx
);
1586 if (retval
== FCAL_SUCCESS
) {
1587 if (copyout((caddr_t
)rls_pl
, (caddr_t
)arg
,
1588 sizeof (la_els_rls_reply_t
)) == -1) {
1589 kmem_free((void *)rls_pl
,
1590 sizeof (la_els_rls_reply_t
));
1594 kmem_free((void *)rls_pl
, sizeof (la_els_rls_reply_t
));
1597 case FCIO_LOOPBACK_INTERNAL
:
1599 * If userland doesn't provide a location for a return
1600 * value the driver will permanently offline the port,
1601 * ignoring any checks for devices on the loop.
1603 mutex_enter(&socalp
->ioctl_mtx
);
1605 port_statep
= &socalp
->port_state
[port
];
1606 mutex_enter(&port_statep
->sp_mtx
);
1607 if (port_statep
->sp_status
& PORT_DISABLED
) {
1608 /* Already disabled */
1609 mutex_exit(&port_statep
->sp_mtx
);
1610 mutex_exit(&socalp
->ioctl_mtx
);
1613 port_statep
->sp_status
|= PORT_DISABLED
;
1614 mutex_exit(&port_statep
->sp_mtx
);
1616 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1618 mutex_exit(&socalp
->ioctl_mtx
);
1619 if (arg
== 0) break;
1620 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1624 case FCIO_LOOPBACK_MANUAL
:
1625 mutex_enter(&socalp
->ioctl_mtx
);
1626 port_statep
= &socalp
->port_state
[port
];
1627 mutex_enter(&port_statep
->sp_mtx
);
1628 if (port_statep
->sp_status
& PORT_DISABLED
) {
1629 mutex_exit(&port_statep
->sp_mtx
);
1630 mutex_exit(&socalp
->ioctl_mtx
);
1633 mutex_exit(&port_statep
->sp_mtx
);
1634 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1636 mutex_exit(&socalp
->ioctl_mtx
);
1637 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1641 case FCIO_NO_LOOPBACK
:
1642 mutex_enter(&socalp
->ioctl_mtx
);
1643 port_statep
= &socalp
->port_state
[port
];
1644 mutex_enter(&port_statep
->sp_mtx
);
1645 /* Do not allow online if we're disabled */
1646 if (port_statep
->sp_status
& PORT_DISABLED
) {
1648 mutex_exit(&port_statep
->sp_mtx
);
1649 mutex_exit(&socalp
->ioctl_mtx
);
1651 * It's permanently disabled -- Need to
1656 /* This was a request to online. */
1657 port_statep
->sp_status
&= ~PORT_DISABLED
;
1659 mutex_exit(&port_statep
->sp_mtx
);
1660 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1662 mutex_exit(&socalp
->ioctl_mtx
);
1663 if (arg
== 0) break;
1664 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1669 mutex_enter(&socalp
->ioctl_mtx
);
1670 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1672 mutex_exit(&socalp
->ioctl_mtx
);
1673 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1677 case FCIO_DIAG_XRAM
:
1678 mutex_enter(&socalp
->ioctl_mtx
);
1679 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1680 SOC_DIAG_XRAM_TEST
);
1681 mutex_exit(&socalp
->ioctl_mtx
);
1682 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1687 mutex_enter(&socalp
->ioctl_mtx
);
1688 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1690 mutex_exit(&socalp
->ioctl_mtx
);
1691 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1696 mutex_enter(&socalp
->ioctl_mtx
);
1697 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1699 mutex_exit(&socalp
->ioctl_mtx
);
1700 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1704 case FCIO_DIAG_SOCLB
:
1705 mutex_enter(&socalp
->ioctl_mtx
);
1706 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1707 SOC_DIAG_SOCLB_TEST
);
1708 mutex_exit(&socalp
->ioctl_mtx
);
1709 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1713 case FCIO_DIAG_SRDSLB
:
1714 mutex_enter(&socalp
->ioctl_mtx
);
1715 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1716 SOC_DIAG_SRDSLB_TEST
);
1717 mutex_exit(&socalp
->ioctl_mtx
);
1718 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1722 case FCIO_DIAG_EXTLB
:
1723 mutex_enter(&socalp
->ioctl_mtx
);
1724 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1725 SOC_DIAG_EXTOE_TEST
);
1726 mutex_exit(&socalp
->ioctl_mtx
);
1727 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1732 if (copyin((caddr_t
)arg
, (caddr_t
)&i
, sizeof (uint_t
))
1735 mutex_enter(&socalp
->ioctl_mtx
);
1736 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1738 mutex_exit(&socalp
->ioctl_mtx
);
1739 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1743 case FCIO_LOOPBACK_FRAME
:
1744 if ((flb_hdr
= (flb_hdr_t
*)kmem_zalloc(sizeof (flb_hdr_t
),
1745 KM_NOSLEEP
)) == NULL
)
1748 if (copyin((caddr_t
)arg
,
1749 (caddr_t
)flb_hdr
, sizeof (flb_hdr_t
)) == -1) {
1750 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1754 flb_size
= flb_hdr
->length
;
1757 (uchar_t
*)kmem_zalloc(flb_size
, KM_NOSLEEP
)) == NULL
)
1760 if (copyin((caddr_t
)(arg
+ sizeof (flb_hdr_t
)),
1761 (caddr_t
)flb_pl
, flb_size
) == -1) {
1762 kmem_free((void *)flb_pl
, flb_size
);
1765 mutex_enter(&socalp
->ioctl_mtx
);
1766 retval
= socal_issue_lbf(socalp
, port
, flb_pl
,
1768 mutex_exit(&socalp
->ioctl_mtx
);
1770 if (retval
== FCAL_SUCCESS
) {
1771 if (copyout((caddr_t
)flb_pl
,
1772 (caddr_t
)(arg
+ sizeof (flb_hdr_t
) +
1773 flb_hdr
->max_length
), flb_size
) == -1) {
1774 kmem_free((void *)flb_pl
, flb_size
);
1775 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1780 kmem_free((void *)flb_pl
, flb_size
);
1781 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1790 case FCAL_ALLOC_FAILED
:
1792 case FCAL_STATUS_DIAG_BUSY
:
1794 case FCAL_STATUS_DIAG_INVALID
:
1803 * Function name : socal_disable()
1805 * Return Values : none
1807 * Description : Reset the soc+
1809 * Context : Can be called from different kernel process threads.
1810 * Can be called by interrupt thread.
1812 * Note: before calling this, the interface should be locked down
1813 * so that it is guaranteed that no other threads are accessing
1817 socal_disable(socal_state_t
*socalp
)
1822 /* Don't touch the hardware if the registers aren't mapped */
1823 if (!socalp
->socal_rp
)
1826 socalp
->socal_rp
->socal_imr
= socalp
->socal_k_imr
= 0;
1827 socalp
->socal_rp
->socal_csr
.w
= SOCAL_CSR_SOFT_RESET
;
1829 i
= socalp
->socal_rp
->socal_csr
.w
;
1831 DEBUGF(9, (CE_CONT
, "csr.w = %x\n", i
));
1835 * Function name : socal_init_transport_interface()
1837 * Return Values : none
1839 * Description : Fill up the fcal_tranpsort struct for ULPs
1842 * Note: Only called during attach, so no protection
1845 socal_init_transport_interface(socal_state_t
*socalp
)
1848 fcal_transport_t
*xport
;
1850 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
1851 xport
= socalp
->port_state
[i
].sp_transport
;
1852 mutex_init(&xport
->fcal_mtx
, NULL
, MUTEX_DRIVER
,
1853 (void *)(socalp
->iblkc
));
1855 cv_init(&xport
->fcal_cv
, NULL
, CV_DRIVER
, NULL
);
1857 xport
->fcal_handle
= (void *)socalp
;
1858 xport
->fcal_dmalimp
= socallim
;
1859 xport
->fcal_iblock
= socalp
->iblkc
;
1860 xport
->fcal_dmaattr
= &socal_dma_attr
;
1861 xport
->fcal_accattr
= &socal_acc_attr
;
1862 xport
->fcal_loginparms
= socalp
->socal_service_params
;
1863 bcopy((caddr_t
)&socalp
->socal_n_wwn
,
1864 (caddr_t
)&xport
->fcal_n_wwn
, sizeof (la_wwn_t
));
1865 bcopy((caddr_t
)&socalp
->port_state
[i
].sp_p_wwn
,
1866 (caddr_t
)&xport
->fcal_p_wwn
, sizeof (la_wwn_t
));
1867 xport
->fcal_portno
= i
;
1868 xport
->fcal_cmdmax
= SOCAL_MAX_XCHG
;
1869 xport
->fcal_ops
= &socal_transport_ops
;
1875 * socal_cqalloc_init() - Inialize the circular queue tables.
1876 * Also, init the locks that are associated with the tables.
1878 * Returns: FCAL_SUCCESS, if able to init properly.
1879 * FCAL_FAILURE, if unable to init properly.
1883 socal_cqalloc_init(socal_state_t
*socalp
, uint32_t index
)
1889 int req_bound
= 0, rsp_bound
= 0;
1892 * Initialize the Request and Response Queue locks.
1895 mutex_init(&socalp
->request
[index
].skc_mtx
, NULL
, MUTEX_DRIVER
,
1896 (void *)socalp
->iblkc
);
1897 mutex_init(&socalp
->response
[index
].skc_mtx
, NULL
, MUTEX_DRIVER
,
1898 (void *)socalp
->iblkc
);
1899 cv_init(&socalp
->request
[index
].skc_cv
, NULL
, CV_DRIVER
, NULL
);
1900 cv_init(&socalp
->response
[index
].skc_cv
, NULL
, CV_DRIVER
, NULL
);
1902 /* Allocate DVMA resources for the Request Queue. */
1903 cq_size
= socal_req_entries
[index
] * sizeof (cqe_t
);
1905 cqp
= &socalp
->request
[index
];
1907 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
1908 DDI_DMA_DONTWAIT
, NULL
,
1909 &cqp
->skc_dhandle
) != DDI_SUCCESS
) {
1910 socal_disp_err(socalp
, CE_WARN
, "driver.4020",
1911 "!alloc of dma handle failed");
1915 if (ddi_dma_mem_alloc(cqp
->skc_dhandle
,
1916 cq_size
+ SOCAL_CQ_ALIGN
, &socal_acc_attr
,
1917 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
1918 (caddr_t
*)&cqp
->skc_cq_raw
, &real_len
,
1919 &cqp
->skc_acchandle
) != DDI_SUCCESS
) {
1920 socal_disp_err(socalp
, CE_WARN
, "driver.4030",
1921 "!alloc of dma space failed");
1925 if (real_len
< (cq_size
+ SOCAL_CQ_ALIGN
)) {
1926 socal_disp_err(socalp
, CE_WARN
, "driver.4035",
1927 "!alloc of dma space failed");
1930 cqp
->skc_cq
= (cqe_t
*)(((uintptr_t)cqp
->skc_cq_raw
+
1931 (uintptr_t)SOCAL_CQ_ALIGN
- 1) &
1932 ((uintptr_t)(~(SOCAL_CQ_ALIGN
-1))));
1934 if (ddi_dma_addr_bind_handle(cqp
->skc_dhandle
,
1935 (struct as
*)NULL
, (caddr_t
)cqp
->skc_cq
, cq_size
,
1936 DDI_DMA_RDWR
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
1937 NULL
, &cqp
->skc_dcookie
, &ccount
) != DDI_DMA_MAPPED
) {
1938 socal_disp_err(socalp
, CE_WARN
, "driver.4040",
1939 "!bind of dma handle failed");
1945 socal_disp_err(socalp
, CE_WARN
, "driver.4045",
1946 "!bind of dma handle failed");
1951 socalp
->request
[index
].skc_cq_raw
= NULL
;
1952 socalp
->request
[index
].skc_cq
= (cqe_t
*)NULL
;
1953 socalp
->request
[index
].skc_dhandle
= 0;
1956 /* Allocate DVMA resources for the response Queue. */
1957 cq_size
= socal_rsp_entries
[index
] * sizeof (cqe_t
);
1959 cqp
= &socalp
->response
[index
];
1961 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
1962 DDI_DMA_DONTWAIT
, NULL
,
1963 &cqp
->skc_dhandle
) != DDI_SUCCESS
) {
1964 socal_disp_err(socalp
, CE_WARN
, "driver.4050",
1965 "!alloc of dma handle failed");
1969 if (ddi_dma_mem_alloc(cqp
->skc_dhandle
,
1970 cq_size
+ SOCAL_CQ_ALIGN
, &socal_acc_attr
,
1971 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
1972 (caddr_t
*)&cqp
->skc_cq_raw
, &real_len
,
1973 &cqp
->skc_acchandle
) != DDI_SUCCESS
) {
1974 socal_disp_err(socalp
, CE_WARN
, "driver.4060",
1975 "!alloc of dma space failed");
1979 if (real_len
< (cq_size
+ SOCAL_CQ_ALIGN
)) {
1980 socal_disp_err(socalp
, CE_WARN
, "driver.4065",
1981 "!alloc of dma space failed");
1985 cqp
->skc_cq
= (cqe_t
*)(((uintptr_t)cqp
->skc_cq_raw
+
1986 (uintptr_t)SOCAL_CQ_ALIGN
- 1) &
1987 ((uintptr_t)(~(SOCAL_CQ_ALIGN
-1))));
1989 if (ddi_dma_addr_bind_handle(cqp
->skc_dhandle
,
1990 (struct as
*)NULL
, (caddr_t
)cqp
->skc_cq
, cq_size
,
1991 DDI_DMA_RDWR
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
1992 NULL
, &cqp
->skc_dcookie
, &ccount
) != DDI_DMA_MAPPED
) {
1993 socal_disp_err(socalp
, CE_WARN
, "driver.4070",
1994 "!bind of dma handle failed");
2000 socal_disp_err(socalp
, CE_WARN
, "driver.4075",
2001 "!bind of dma handle failed");
2006 socalp
->response
[index
].skc_cq_raw
= NULL
;
2007 socalp
->response
[index
].skc_cq
= (cqe_t
*)NULL
;
2008 socalp
->response
[index
].skc_dhandle
= 0;
2012 * Initialize the queue pointers
2014 socal_cqinit(socalp
, index
);
2016 return (FCAL_SUCCESS
);
2018 if (socalp
->request
[index
].skc_dhandle
) {
2020 (void) ddi_dma_unbind_handle(socalp
->
2021 request
[index
].skc_dhandle
);
2022 ddi_dma_free_handle(&socalp
->request
[index
].skc_dhandle
);
2024 if (socalp
->request
[index
].skc_cq_raw
)
2025 ddi_dma_mem_free(&socalp
->request
[index
].skc_acchandle
);
2027 if (socalp
->response
[index
].skc_dhandle
) {
2029 (void) ddi_dma_unbind_handle(socalp
->
2030 response
[index
].skc_dhandle
);
2031 ddi_dma_free_handle(&socalp
->response
[index
].skc_dhandle
);
2033 if (socalp
->response
[index
].skc_cq_raw
)
2034 ddi_dma_mem_free(&socalp
->response
[index
].skc_acchandle
);
2036 socalp
->request
[index
].skc_dhandle
= NULL
;
2037 socalp
->response
[index
].skc_dhandle
= NULL
;
2038 socalp
->request
[index
].skc_cq_raw
= NULL
;
2039 socalp
->request
[index
].skc_cq
= NULL
;
2040 socalp
->response
[index
].skc_cq_raw
= NULL
;
2041 socalp
->response
[index
].skc_cq
= NULL
;
2042 mutex_destroy(&socalp
->request
[index
].skc_mtx
);
2043 mutex_destroy(&socalp
->response
[index
].skc_mtx
);
2044 cv_destroy(&socalp
->request
[index
].skc_cv
);
2045 cv_destroy(&socalp
->response
[index
].skc_cv
);
2046 return (FCAL_FAILURE
);
2051 * socal_cqinit() - initializes the driver's circular queue pointers, etc.
2055 socal_cqinit(socal_state_t
*socalp
, uint32_t index
)
2057 socal_kcq_t
*kcq_req
= &socalp
->request
[index
];
2058 socal_kcq_t
*kcq_rsp
= &socalp
->response
[index
];
2061 * Initialize the Request and Response Queue pointers
2063 kcq_req
->skc_seqno
= 1;
2064 kcq_rsp
->skc_seqno
= 1;
2065 kcq_req
->skc_in
= 0;
2066 kcq_rsp
->skc_in
= 0;
2067 kcq_req
->skc_out
= 0;
2068 kcq_rsp
->skc_out
= 0;
2069 kcq_req
->skc_last_index
= socal_req_entries
[index
] - 1;
2070 kcq_rsp
->skc_last_index
= socal_rsp_entries
[index
] - 1;
2071 kcq_req
->skc_full
= 0;
2072 kcq_rsp
->deferred_intr_timeoutid
= 0;
2073 kcq_req
->skc_socalp
= socalp
;
2074 kcq_rsp
->skc_socalp
= socalp
;
2076 kcq_req
->skc_xram_cqdesc
=
2077 (socalp
->xram_reqp
+ (index
* sizeof (struct cq
))/8);
2078 kcq_rsp
->skc_xram_cqdesc
=
2079 (socalp
->xram_rspp
+ (index
* sizeof (struct cq
))/8);
2081 /* Clear out memory we have allocated */
2082 if (kcq_req
->skc_cq
!= NULL
)
2083 bzero((caddr_t
)kcq_req
->skc_cq
,
2084 socal_req_entries
[index
] * sizeof (cqe_t
));
2085 if (kcq_rsp
->skc_cq
!= NULL
)
2086 bzero((caddr_t
)kcq_rsp
->skc_cq
,
2087 socal_rsp_entries
[index
] * sizeof (cqe_t
));
2092 socal_start(socal_state_t
*socalp
)
2097 return (FCAL_FAILURE
);
2099 socal_download_ucode(socalp
);
2100 socal_init_cq_desc(socalp
);
2101 socal_init_wwn(socalp
);
2103 mutex_enter(&socalp
->port_state
[0].sp_mtx
);
2104 socalp
->port_state
[0].sp_status
2105 &= (PORT_OPEN
|PORT_CHILD_INIT
|PORT_DISABLED
|PORT_TARGET_MODE
);
2106 socalp
->port_state
[0].sp_status
|= PORT_OFFLINE
;
2107 mutex_exit(&socalp
->port_state
[0].sp_mtx
);
2109 mutex_enter(&socalp
->port_state
[1].sp_mtx
);
2110 socalp
->port_state
[1].sp_status
2111 &= (PORT_OPEN
|PORT_CHILD_INIT
|PORT_DISABLED
|PORT_TARGET_MODE
);
2112 socalp
->port_state
[1].sp_status
|= PORT_OFFLINE
;
2113 mutex_exit(&socalp
->port_state
[1].sp_mtx
);
2115 socal_enable(socalp
);
2116 /* Make sure disabled ports stay disabled. */
2117 if (socalp
->port_state
[0].sp_status
& PORT_DISABLED
)
2118 (void) socal_diag_request((void *)socalp
, 0, &r
,
2120 if (socalp
->port_state
[1].sp_status
& PORT_DISABLED
)
2121 (void) socal_diag_request((void *)socalp
, 1, &r
,
2124 mutex_enter(&socalp
->k_imr_mtx
);
2125 socalp
->socal_shutdown
= 0;
2126 mutex_exit(&socalp
->k_imr_mtx
);
2128 mutex_enter(&socalp
->board_mtx
);
2129 if (socal_establish_pool(socalp
, 1) != FCAL_SUCCESS
) {
2130 mutex_exit(&socalp
->board_mtx
);
2131 return (FCAL_FAILURE
);
2133 if (socal_add_pool_buffer(socalp
, 1) != FCAL_SUCCESS
) {
2134 mutex_exit(&socalp
->board_mtx
);
2135 return (FCAL_FAILURE
);
2138 mutex_exit(&socalp
->board_mtx
);
2139 return (FCAL_SUCCESS
);
2143 socal_doreset(socal_state_t
*socalp
)
2146 socal_port_t
*port_statep
;
2147 socal_unsol_cb_t
*scbp
;
2149 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2150 mutex_enter(&socalp
->request
[i
].skc_mtx
);
2151 mutex_enter(&socalp
->response
[i
].skc_mtx
);
2154 mutex_enter(&socalp
->k_imr_mtx
);
2155 socal_disable(socalp
);
2157 if (socalp
->pool_dhandle
) {
2158 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
2159 ddi_dma_free_handle(&socalp
->pool_dhandle
);
2163 ddi_dma_mem_free(&socalp
->pool_acchandle
);
2165 socalp
->pool_dhandle
= NULL
;
2166 socalp
->pool
= NULL
;
2168 for (i
= 0; i
< SOCAL_N_CQS
; i
++)
2169 socal_cqinit(socalp
, i
);
2171 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
2172 port_statep
= &socalp
->port_state
[i
];
2174 mutex_enter(&port_statep
->sp_mtx
);
2175 port_statep
->sp_status
&= ~ (PORT_STATUS_MASK
|
2176 PORT_LILP_PENDING
| PORT_LIP_PENDING
|
2177 PORT_ABORT_PENDING
| PORT_BYPASS_PENDING
|
2179 mutex_exit(&port_statep
->sp_mtx
);
2182 mutex_exit(&socalp
->k_imr_mtx
);
2184 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
2185 mutex_exit(&socalp
->request
[i
].skc_mtx
);
2186 mutex_exit(&socalp
->response
[i
].skc_mtx
);
2189 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
2190 for (scbp
= socalp
->port_state
[i
].sp_unsol_cb
; scbp
;
2192 (scbp
->statec_cb
)(scbp
->arg
, FCAL_STATE_RESET
);
2195 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2196 mutex_enter(&socalp
->request
[i
].skc_mtx
);
2197 mutex_enter(&socalp
->response
[i
].skc_mtx
);
2201 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2202 socalp
->request
[i
].skc_overflowh
= NULL
;
2203 if (socalp
->request
[i
].skc_full
& SOCAL_SKC_SLEEP
)
2204 cv_broadcast(&socalp
->request
[i
].skc_cv
);
2207 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
2208 mutex_exit(&socalp
->request
[i
].skc_mtx
);
2209 mutex_exit(&socalp
->response
[i
].skc_mtx
);
2216 * Function name : socal_download_ucode ()
2220 * Description : Copies firmware from code that has been linked into
2221 * the socal module into the soc+'s XRAM. Prints the date
2226 socal_download_ucode(socal_state_t
*socalp
)
2229 uint_t date_str
[16];
2232 fw_len
= (uint_t
)socal_ucode_size
;
2234 /* Copy the firmware image */
2235 socal_wcopy((uint_t
*)&socal_ucode
,
2236 (uint_t
*)socalp
->socal_xrp
, fw_len
);
2238 socal_fix_harda(socalp
, 0);
2239 socal_fix_harda(socalp
, 1);
2241 /* Get the date string from the firmware image */
2242 socal_wcopy((uint_t
*)(socalp
->socal_xrp
+SOCAL_XRAM_FW_DATE_STR
),
2243 date_str
, sizeof (date_str
));
2244 date_str
[sizeof (date_str
) / sizeof (uint_t
) - 1] = 0;
2246 if (*(caddr_t
)date_str
!= '\0') {
2248 "!Downloading host adapter, fw date code: %s\n",
2250 socal_disp_err(socalp
, CE_CONT
, "driver.1010", buf
);
2251 (void) strcpy(socalp
->socal_stats
.fw_revision
,
2255 "!Downloading host adapter fw, "
2256 "date code: <not available>\n");
2257 socal_disp_err(socalp
, CE_CONT
, "driver.3010", buf
);
2258 (void) strcpy(socalp
->socal_stats
.fw_revision
,
2264 * Function name : socal_disp_err()
2266 * Return Values : none
2268 * Description : displays an error message on the system console
2269 * with the full device pathname displayed
2273 socal_state_t
*socalp
,
2281 instance
= ddi_get_instance(socalp
->dip
);
2285 if (c
== '!') /* log only */
2287 "!ID[SUNWssa.socal.%s] socal%d: %s", mid
, instance
, msg
+1);
2288 else if (c
== '?') /* boot message - log && maybe console */
2290 "?ID[SUNWssa.socal.%s] socal%d: %s", mid
, instance
, msg
+1);
2291 else if (c
== '^') /* console only */
2292 cmn_err(level
, "^socal%d: %s", instance
, msg
+1);
2293 else { /* log and console */
2294 cmn_err(level
, "^socal%d: %s", instance
, msg
);
2295 cmn_err(level
, "!ID[SUNWssa.socal.%s] socal%d: %s", mid
,
2301 * Function name : socal_init_cq_desc()
2303 * Return Values : none
2305 * Description : Initializes the request and response queue
2306 * descriptors in the SOC+'s XRAM
2308 * Context : Should only be called during initialiation when
2309 * the SOC+ is reset.
2312 socal_init_cq_desc(socal_state_t
*socalp
)
2314 soc_cq_t que_desc
[SOCAL_N_CQS
];
2318 * Finish CQ table initialization and give the descriptor
2319 * table to the soc+. Note that we don't use all of the queues
2320 * provided by the hardware, but we make sure we initialize the
2321 * quantities in the unused fields in the hardware to zeroes.
2327 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2328 if (socal_req_entries
[i
]) {
2329 que_desc
[i
].cq_address
=
2330 (uint32_t)socalp
->request
[i
].
2331 skc_dcookie
.dmac_address
;
2332 que_desc
[i
].cq_last_index
= socal_req_entries
[i
] - 1;
2334 que_desc
[i
].cq_address
= (uint32_t)0;
2335 que_desc
[i
].cq_last_index
= 0;
2337 que_desc
[i
].cq_in
= 0;
2338 que_desc
[i
].cq_out
= 0;
2339 que_desc
[i
].cq_seqno
= 1; /* required by SOC+ microcode */
2343 socal_wcopy((uint_t
*)que_desc
, /* pointer to kernel copy */
2344 (uint_t
*)socalp
->xram_reqp
, /* pointer to xram location */
2345 SOCAL_N_CQS
* sizeof (soc_cq_t
));
2348 * Do response queues
2350 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2351 if (socal_rsp_entries
[i
]) {
2352 que_desc
[i
].cq_last_index
= socal_rsp_entries
[i
] - 1;
2353 que_desc
[i
].cq_address
=
2354 (uint32_t)socalp
->response
[i
].
2355 skc_dcookie
.dmac_address
;
2358 que_desc
[i
].cq_address
= 0;
2359 que_desc
[i
].cq_last_index
= 0;
2364 socal_wcopy((uint_t
*)que_desc
, /* pointer to kernel copy */
2365 (uint_t
*)socalp
->xram_rspp
, /* pointer to xram location */
2366 SOCAL_N_CQS
* sizeof (soc_cq_t
));
2370 socal_init_wwn(socal_state_t
*socalp
)
2372 /* copy the node wwn to xram */
2373 socal_wcopy((uint_t
*)&socalp
->socal_n_wwn
,
2374 (uint_t
*)(socalp
->socal_xrp
+
2375 SOCAL_XRAM_NODE_WWN
), sizeof (la_wwn_t
));
2377 /* copy port a's wwn to xram */
2378 socal_wcopy((uint_t
*)&socalp
->port_state
[0].sp_p_wwn
,
2379 (uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_PORTA_WWN
),
2382 /* copy port b's wwn to xram */
2383 socal_wcopy((uint_t
*)&socalp
->port_state
[1].sp_p_wwn
,
2384 (uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_PORTB_WWN
),
2388 * need to avoid deadlock by assuring no other thread grabs both of
2391 mutex_enter(&socalp
->port_state
[0].sp_transport
->fcal_mtx
);
2392 mutex_enter(&socalp
->port_state
[1].sp_transport
->fcal_mtx
);
2394 socal_wcopy((uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_SERV_PARAMS
),
2395 (uint_t
*)&socalp
->socal_service_params
, SOCAL_SVC_LENGTH
);
2396 mutex_exit(&socalp
->port_state
[1].sp_transport
->fcal_mtx
);
2397 mutex_exit(&socalp
->port_state
[0].sp_transport
->fcal_mtx
);
2401 socal_enable(socal_state_t
*socalp
)
2403 DEBUGF(2, (CE_CONT
, "socal%d: enable:\n",
2404 ddi_get_instance(socalp
->dip
)));
2406 socalp
->socal_rp
->socal_cr
.w
= socalp
->socal_cfg
;
2407 socalp
->socal_rp
->socal_csr
.w
= SOCAL_CSR_SOCAL_TO_HOST
;
2409 socalp
->socal_k_imr
= (uint32_t)SOCAL_CSR_SOCAL_TO_HOST
|
2410 SOCAL_CSR_SLV_ACC_ERR
;
2411 socalp
->socal_rp
->socal_imr
= (uint32_t)socalp
->socal_k_imr
;
2416 * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
2417 * to place LINK ctl application data as it arrives.
2420 * FCAL_SUCCESS, upon establishing the pool.
2421 * FCAL_FAILURE, if unable to establish the pool.
2425 socal_establish_pool(socal_state_t
*socalp
, uint32_t poolid
)
2427 soc_pool_request_t
*prq
;
2431 (soc_pool_request_t
*)kmem_zalloc(sizeof (soc_pool_request_t
),
2432 KM_NOSLEEP
)) == NULL
)
2433 return (FCAL_FAILURE
);
2435 * Fill in the request structure.
2437 prq
->spr_soc_hdr
.sh_request_token
= 1;
2438 prq
->spr_soc_hdr
.sh_flags
= SOC_FC_HEADER
| SOC_UNSOLICITED
|
2440 prq
->spr_soc_hdr
.sh_class
= 0;
2441 prq
->spr_soc_hdr
.sh_seg_cnt
= 1;
2442 prq
->spr_soc_hdr
.sh_byte_cnt
= 0;
2444 prq
->spr_pool_id
= poolid
;
2445 prq
->spr_header_mask
= SOCPR_MASK_RCTL
;
2446 prq
->spr_buf_size
= SOCAL_POOL_SIZE
;
2447 prq
->spr_n_entries
= 0;
2449 prq
->spr_fc_frame_hdr
.r_ctl
= R_CTL_ELS_REQ
;
2450 prq
->spr_fc_frame_hdr
.d_id
= 0;
2451 prq
->spr_fc_frame_hdr
.s_id
= 0;
2452 prq
->spr_fc_frame_hdr
.type
= 0;
2453 prq
->spr_fc_frame_hdr
.f_ctl
= 0;
2454 prq
->spr_fc_frame_hdr
.seq_id
= 0;
2455 prq
->spr_fc_frame_hdr
.df_ctl
= 0;
2456 prq
->spr_fc_frame_hdr
.seq_cnt
= 0;
2457 prq
->spr_fc_frame_hdr
.ox_id
= 0;
2458 prq
->spr_fc_frame_hdr
.rx_id
= 0;
2459 prq
->spr_fc_frame_hdr
.ro
= 0;
2461 prq
->spr_cqhdr
.cq_hdr_count
= 1;
2462 prq
->spr_cqhdr
.cq_hdr_type
= CQ_TYPE_ADD_POOL
;
2463 prq
->spr_cqhdr
.cq_hdr_flags
= 0;
2464 prq
->spr_cqhdr
.cq_hdr_seqno
= 0;
2466 /* Enque the request. */
2467 result
= socal_cq_enque(socalp
, NULL
, (cqe_t
*)prq
, CQ_REQUEST_1
,
2468 FCAL_NOSLEEP
, NULL
, 0);
2469 kmem_free((void *)prq
, sizeof (soc_pool_request_t
));
2477 * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
2478 * to an established pool of buffers
2481 * DDI_SUCCESS, upon establishing the pool.
2482 * DDI_FAILURE, if unable to establish the pool.
2486 socal_add_pool_buffer(socal_state_t
*socalp
, uint32_t poolid
)
2488 soc_data_request_t
*drq
;
2495 (soc_data_request_t
*)kmem_zalloc(sizeof (soc_data_request_t
),
2496 KM_NOSLEEP
)) == NULL
)
2497 return (FCAL_FAILURE
);
2499 /* Allocate DVMA resources for the buffer pool */
2500 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
2501 DDI_DMA_DONTWAIT
, NULL
, &socalp
->pool_dhandle
) != DDI_SUCCESS
)
2504 if (ddi_dma_mem_alloc(socalp
->pool_dhandle
, SOCAL_POOL_SIZE
,
2505 &socal_acc_attr
, DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
2506 (caddr_t
*)&socalp
->pool
, &real_len
, &socalp
->pool_acchandle
)
2510 if (real_len
< SOCAL_POOL_SIZE
)
2513 if (ddi_dma_addr_bind_handle(socalp
->pool_dhandle
, (struct as
*)NULL
,
2514 (caddr_t
)socalp
->pool
, SOCAL_POOL_SIZE
,
2515 DDI_DMA_READ
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
2516 NULL
, &socalp
->pool_dcookie
, &ccount
) != DDI_DMA_MAPPED
)
2524 * Fill in the request structure.
2526 drq
->sdr_soc_hdr
.sh_request_token
= poolid
;
2527 drq
->sdr_soc_hdr
.sh_flags
= SOC_UNSOLICITED
| SOC_NO_RESPONSE
;
2528 drq
->sdr_soc_hdr
.sh_class
= 0;
2529 drq
->sdr_soc_hdr
.sh_seg_cnt
= 1;
2530 drq
->sdr_soc_hdr
.sh_byte_cnt
= 0;
2532 drq
->sdr_dataseg
[0].fc_base
=
2533 (uint32_t)socalp
->pool_dcookie
.dmac_address
;
2534 drq
->sdr_dataseg
[0].fc_count
= SOCAL_POOL_SIZE
;
2535 drq
->sdr_dataseg
[1].fc_base
= 0;
2536 drq
->sdr_dataseg
[1].fc_count
= 0;
2537 drq
->sdr_dataseg
[2].fc_base
= 0;
2538 drq
->sdr_dataseg
[2].fc_count
= 0;
2539 drq
->sdr_dataseg
[3].fc_base
= 0;
2540 drq
->sdr_dataseg
[3].fc_count
= 0;
2541 drq
->sdr_dataseg
[4].fc_base
= 0;
2542 drq
->sdr_dataseg
[4].fc_count
= 0;
2543 drq
->sdr_dataseg
[5].fc_base
= 0;
2544 drq
->sdr_dataseg
[5].fc_count
= 0;
2546 drq
->sdr_cqhdr
.cq_hdr_count
= 1;
2547 drq
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_ADD_BUFFER
;
2548 drq
->sdr_cqhdr
.cq_hdr_flags
= 0;
2549 drq
->sdr_cqhdr
.cq_hdr_seqno
= 0;
2551 /* Transport the request. */
2552 result
= socal_cq_enque(socalp
, NULL
, (cqe_t
*)drq
, CQ_REQUEST_1
,
2553 FCAL_NOSLEEP
, NULL
, 0);
2554 kmem_free((void *)drq
, sizeof (soc_data_request_t
));
2558 socal_disp_err(socalp
, CE_WARN
, "driver.4110",
2559 "!Buffer pool DVMA alloc failed");
2560 if (socalp
->pool_dhandle
) {
2562 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
2563 ddi_dma_free_handle(&socalp
->pool_dhandle
);
2566 ddi_dma_mem_free(&socalp
->pool_acchandle
);
2567 socalp
->pool_dhandle
= NULL
;
2568 return (FCAL_FAILURE
);
2572 socal_transport(fcal_packet_t
*fcalpkt
, fcal_sleep_t sleep
, int req_q_no
)
2574 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2575 socal_port_t
*port_statep
;
2576 #if defined(DEBUG) && !defined(lint)
2577 int instance
= ddi_get_instance(socalp
->dip
);
2580 soc_request_t
*sp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
2582 if (sp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
2586 port_statep
= &socalp
->port_state
[port
];
2588 DEBUGF(4, (CE_CONT
, "socal%d: transport: packet, sleep = %p, %d\n",
2589 instance
, fcalpkt
, sleep
));
2591 fcalpkt
->fcal_cmd_state
= 0;
2592 fcalpkt
->fcal_pkt_flags
&= ~(FCFLAG_COMPLETE
| FCFLAG_ABORTING
);
2594 return (socal_cq_enque(socalp
, port_statep
, (cqe_t
*)sp
,
2595 req_q_no
, sleep
, fcalpkt
, 0));
2599 * Function name : socal_cq_enque()
2602 * FCAL_TRANSPORT_SUCCESS, if able to que the entry.
2603 * FCAL_TRANSPORT_QFULL, if queue full & sleep not set
2604 * FCAL_TRANSPORT_UNAVAIL if this port down
2606 * Description : Enqueues an entry into the solicited request
2614 socal_cq_enque(socal_state_t
*socalp
, socal_port_t
*port_statep
, cqe_t
*cqe
,
2615 int rqix
, fcal_sleep_t sleep
, fcal_packet_t
*to_queue
,
2618 #if defined(DEBUG) && !defined(lint)
2619 int instance
= ddi_get_instance(socalp
->dip
);
2623 uint_t bitmask
, wmask
;
2628 kcq
= &socalp
->request
[rqix
];
2630 bitmask
= SOCAL_CSR_1ST_H_TO_S
<< rqix
;
2631 wmask
= SOCAL_CSR_SOCAL_TO_HOST
| bitmask
;
2632 p
= (longlong_t
*)cqe
;
2635 * Since we're only reading we don't need a mutex.
2637 if (socalp
->socal_shutdown
) {
2638 return (FCAL_TRANSPORT_UNAVAIL
);
2641 * Get a token early. That way we won't sleep
2642 * in id32_alloc() with a mutex held.
2645 if ((to_queue
->fcal_socal_request
.sr_soc_hdr
.sh_request_token
=
2646 SOCAL_ID_GET(to_queue
, mtxheld
? FCAL_NOSLEEP
:
2648 return (FCAL_TRANSPORT_QFULL
);
2652 * Grab lock for request queue.
2656 mutex_enter(&kcq
->skc_mtx
);
2659 * Determine if the queue is full
2664 if (kcq
->skc_full
) {
2666 * If soc's queue full, then we wait for an interrupt
2667 * telling us we are not full.
2671 to_queue
->fcal_pkt_next
= NULL
;
2672 if (!kcq
->skc_overflowh
) {
2674 "socal%d: cq_enque: request "
2677 kcq
->skc_overflowh
= to_queue
;
2678 socalp
->socal_stats
.qfulls
++;
2680 kcq
->skc_overflowt
->fcal_pkt_next
= to_queue
;
2681 kcq
->skc_overflowt
= to_queue
;
2683 mutex_enter(&socalp
->k_imr_mtx
);
2684 socalp
->socal_rp
->socal_imr
=
2685 (socalp
->socal_k_imr
|= bitmask
);
2686 mutex_exit(&socalp
->k_imr_mtx
);
2687 to_queue
->fcal_cmd_state
|= FCAL_CMD_IN_TRANSPORT
;
2689 mutex_exit(&kcq
->skc_mtx
);
2690 return (FCAL_TRANSPORT_SUCCESS
);
2694 mutex_exit(&kcq
->skc_mtx
);
2695 return (FCAL_TRANSPORT_QFULL
);
2698 if (((kcq
->skc_in
+ 1) & kcq
->skc_last_index
)
2699 == (out
= kcq
->skc_out
)) {
2701 * get SOC+'s copy of out to update our copy of out
2704 SOCAL_REQUESTQ_INDEX(rqix
, socalp
->socal_rp
->socal_reqp
.w
);
2706 "socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
2707 instance
, &kcq
->skc_xram_cqdesc
->cq_in
, s_out
));
2709 kcq
->skc_out
= out
= s_out
;
2710 /* if soc+'s que still full set flag */
2711 kcq
->skc_full
= ((((kcq
->skc_in
+ 1) &
2712 kcq
->skc_last_index
) == out
)) ? SOCAL_SKC_FULL
: 0;
2715 } while (kcq
->skc_full
);
2717 /* Now enque the entry. */
2718 sp
= &(kcq
->skc_cq
[kcq
->skc_in
]);
2719 cqe
->cqe_hdr
.cq_hdr_seqno
= kcq
->skc_seqno
;
2721 /* Give the entry to the SOC. */
2722 q
= (longlong_t
*)sp
;
2731 (void) ddi_dma_sync(kcq
->skc_dhandle
, (int)((caddr_t
)sp
-
2732 (caddr_t
)kcq
->skc_cq
), sizeof (cqe_t
), DDI_DMA_SYNC_FORDEV
);
2734 to_queue
->fcal_cmd_state
|= FCAL_CMD_IN_TRANSPORT
;
2737 * Update circular queue and ring SOC's doorbell.
2740 if ((kcq
->skc_in
& kcq
->skc_last_index
) == 0) {
2745 socalp
->socal_rp
->socal_csr
.w
= wmask
| (kcq
->skc_in
<< 24);
2746 /* Let lock go for request queue. */
2748 mutex_exit(&kcq
->skc_mtx
);
2750 return (FCAL_TRANSPORT_SUCCESS
);
2754 socal_transport_poll(fcal_packet_t
*fcalpkt
, uint_t timeout
, int req_q_no
)
2756 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2757 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
2759 socal_port_t
*port_statep
;
2761 soc_request_t
*sp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
2765 /* make the timeout meaningful */
2766 timeout
= drv_usectohz(timeout
);
2767 if (sp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
2771 port_statep
= &socalp
->port_state
[port
];
2773 fcalpkt
->fcal_cmd_state
= 0;
2774 fcalpkt
->fcal_pkt_flags
&= ~(FCFLAG_COMPLETE
| FCFLAG_ABORTING
);
2776 ticker
= ddi_get_lbolt();
2778 if ((retval
= socal_cq_enque(socalp
, port_statep
, (cqe_t
*)sp
,
2779 req_q_no
, FCAL_NOSLEEP
, fcalpkt
, 0)) != FCAL_TRANSPORT_SUCCESS
) {
2782 while (!(fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)) {
2783 drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME
);
2784 t
= ddi_get_lbolt();
2785 if ((ticker
+ timeout
) < t
)
2786 return (FCAL_TRANSPORT_TIMEOUT
);
2787 csr
= socalreg
->socal_csr
.w
;
2788 if ((SOCAL_INTR_CAUSE(socalp
, csr
)) &
2789 SOCAL_CSR_RSP_QUE_0
) {
2790 socal_intr_solicited(socalp
, 0);
2794 return (FCAL_TRANSPORT_SUCCESS
);
2798 socal_doit(fcal_packet_t
*fcalpkt
, socal_port_t
*port_statep
, int polled
,
2799 void (*func
)(), int timo
, int flag
, uint_t
*diagcode
)
2802 uint32_t retval
, status
;
2803 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2806 fcalpkt
->fcal_pkt_comp
= NULL
;
2807 status
= socal_transport_poll(fcalpkt
, timo
, CQ_REQUEST_0
);
2809 fcalpkt
->fcal_pkt_comp
= func
;
2810 mutex_enter(&port_statep
->sp_mtx
);
2811 port_statep
->sp_status
|= flag
;
2812 if ((status
= socal_transport(fcalpkt
, FCAL_NOSLEEP
,
2813 CQ_REQUEST_0
)) == FCAL_TRANSPORT_SUCCESS
) {
2814 lb
= ddi_get_lbolt();
2815 while (!(fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)) {
2816 if ((retval
= cv_timedwait(&port_statep
->sp_cv
,
2817 &port_statep
->sp_mtx
,
2818 lb
+drv_usectohz(timo
))) == -1) {
2819 status
= FCAL_TRANSPORT_TIMEOUT
;
2824 port_statep
->sp_status
&= ~flag
;
2825 mutex_exit(&port_statep
->sp_mtx
);
2829 case FCAL_TRANSPORT_SUCCESS
:
2830 status
= fcalpkt
->fcal_pkt_status
;
2832 *diagcode
= fcalpkt
->fcal_diag_status
;
2834 case FCAL_STATUS_ABORT_FAILED
:
2835 if (flag
== PORT_ABORT_PENDING
)
2836 retval
= FCAL_ABORT_FAILED
;
2838 case FCAL_STATUS_OK
:
2839 if (flag
== PORT_ABORT_PENDING
)
2840 retval
= FCAL_ABORT_FAILED
;
2842 retval
= FCAL_SUCCESS
;
2844 case FCAL_STATUS_OLD_PORT
:
2845 retval
= FCAL_OLD_PORT
;
2847 case FCAL_STATUS_ERR_OFFLINE
:
2848 retval
= FCAL_OFFLINE
;
2850 case FCAL_STATUS_ABORTED
:
2851 retval
= FCAL_ABORTED
;
2852 port_statep
->sp_board
->
2853 socal_stats
.pstats
[port_statep
2854 ->sp_port
].abts_ok
++;
2856 case FCAL_STATUS_BAD_XID
:
2857 retval
= FCAL_BAD_ABORT
;
2859 case FCAL_STATUS_BAD_DID
:
2860 retval
= FCAL_BAD_PARAMS
;
2862 case FCAL_STATUS_DIAG_BUSY
:
2863 case FCAL_STATUS_DIAG_INVALID
:
2867 retval
= FCAL_LINK_ERROR
;
2870 case FCAL_TRANSPORT_TIMEOUT
:
2871 if (flag
== PORT_LIP_PENDING
||
2872 flag
== PORT_LILP_PENDING
) {
2874 (socal_core
& SOCAL_FAILED_LIP
)) {
2876 socal_take_core(socalp
);
2878 socal_disp_err(socalp
, CE_WARN
, "link.6040",
2879 "SOCAL:Forcing SOC+ reset as LIP timed out\n");
2880 /* restart socal after resetting */
2881 (void) socal_force_reset(port_statep
->sp_board
,
2882 polled
, RESET_PORT
);
2885 (void) socal_force_lip(port_statep
->sp_board
,
2886 port_statep
->sp_port
, polled
,
2888 retval
= FCAL_TIMEOUT
;
2890 case FCAL_TRANSPORT_FAILURE
:
2891 case FCAL_BAD_PACKET
:
2892 case FCAL_TRANSPORT_UNAVAIL
:
2893 case FCAL_TRANSPORT_QFULL
:
2897 retval
= FCAL_LINK_ERROR
;
2899 socal_packet_free(fcalpkt
);
2904 socal_lilp_map(void *ssp
, uint_t port
, uint32_t bufid
, uint_t polled
)
2906 fcal_packet_t
*fcalpkt
;
2907 soc_data_request_t
*sdr
;
2908 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2909 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2912 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
2913 == (fcal_packet_t
*)NULL
)
2914 return (FCAL_ALLOC_FAILED
);
2916 sdr
= (soc_data_request_t
*)&fcalpkt
->fcal_socal_request
;
2918 sdr
->sdr_soc_hdr
.sh_flags
= SOC_PORT_B
;
2919 sdr
->sdr_soc_hdr
.sh_seg_cnt
= 1;
2920 sdr
->sdr_soc_hdr
.sh_byte_cnt
= 132;
2921 sdr
->sdr_dataseg
[0].fc_base
= bufid
;
2922 sdr
->sdr_dataseg
[0].fc_count
= 132;
2923 sdr
->sdr_cqhdr
.cq_hdr_count
= 1;
2924 sdr
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_REPORT_MAP
;
2925 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
2927 return (socal_doit(fcalpkt
, port_statep
, polled
, socal_lilp_map_done
,
2928 SOCAL_LILP_TIMEOUT
, PORT_LILP_PENDING
, NULL
));
2932 socal_force_lip(void *ssp
, uint_t port
, uint_t polled
, uint_t lip_req
)
2934 fcal_packet_t
*fcalpkt
;
2935 soc_cmdonly_request_t
*scr
;
2936 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2937 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2940 if (lip_req
== FCAL_NO_LIP
) {
2941 mutex_enter(&port_statep
->sp_mtx
);
2942 if ((port_statep
->sp_status
& PORT_ONLINE_LOOP
) &&
2943 (port_statep
->sp_unsol_cb
->statec_cb
!= NULL
)) {
2944 mutex_exit(&port_statep
->sp_mtx
);
2945 (*port_statep
->sp_unsol_cb
->statec_cb
)
2946 (port_statep
->sp_unsol_cb
->arg
,
2947 FCAL_STATUS_LOOP_ONLINE
);
2948 return (FCAL_SUCCESS
);
2951 mutex_exit(&port_statep
->sp_mtx
);
2953 socalp
->socal_stats
.pstats
[port
].lips
++;
2955 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
2956 == (fcal_packet_t
*)NULL
)
2957 return (FCAL_ALLOC_FAILED
);
2959 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
2961 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
2962 scr
->scr_cqhdr
.cq_hdr_count
= 1;
2963 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_REQUEST_LIP
;
2965 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
2966 return (socal_doit(fcalpkt
, port_statep
, polled
, socal_force_lip_done
,
2967 SOCAL_LIP_TIMEOUT
, PORT_LIP_PENDING
, NULL
));
2971 socal_abort_cmd(void *ssp
, uint_t port
, fcal_packet_t
*fcalpkt
, uint_t polled
)
2973 fcal_packet_t
*fcalpkt2
, *fpkt
;
2974 soc_cmdonly_request_t
*scr
, *tscr
;
2975 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2976 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2979 socalp
->socal_stats
.pstats
[port
].abts
++;
2980 kcq
= &socalp
->request
[CQ_REQUEST_1
];
2981 mutex_enter(&kcq
->skc_mtx
);
2982 fcalpkt2
= kcq
->skc_overflowh
;
2984 while (fcalpkt2
!= NULL
) {
2985 if (fcalpkt2
== fcalpkt
) {
2987 kcq
->skc_overflowh
= fcalpkt
->fcal_pkt_next
;
2989 fpkt
->fcal_pkt_next
= fcalpkt
->fcal_pkt_next
;
2990 if (kcq
->skc_overflowt
== fcalpkt
)
2991 kcq
->skc_overflowt
= fpkt
;
2993 mutex_exit(&kcq
->skc_mtx
);
2994 socalp
->socal_stats
.pstats
[port
].abts_ok
++;
2995 SOCAL_ID_FREE(fcalpkt
->fcal_socal_request
.
2996 sr_soc_hdr
.sh_request_token
);
2997 return (FCAL_ABORTED
);
3000 fcalpkt2
= fcalpkt2
->fcal_pkt_next
;
3003 mutex_exit(&kcq
->skc_mtx
);
3005 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
3006 == (fcal_packet_t
*)NULL
)
3007 return (FCAL_ALLOC_FAILED
);
3009 mutex_enter(&socalp
->abort_mtx
);
3011 if (fcalpkt
->fcal_pkt_flags
& FCFLAG_COMPLETE
) {
3012 socal_packet_free(fcalpkt2
);
3013 mutex_exit(&socalp
->abort_mtx
);
3014 return (FCAL_ABORTED
);
3015 /* I lied. So shoot me. */
3017 /* Mark packet as being aborted and put it in the abort pending list. */
3018 fcalpkt
->fcal_pkt_flags
|= FCFLAG_ABORTING
;
3020 scr
= (soc_cmdonly_request_t
*)&fcalpkt2
->fcal_socal_request
;
3021 tscr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
3022 scr
->scr_soc_hdr
.sh_byte_cnt
= tscr
->scr_soc_hdr
.sh_request_token
;
3023 scr
->scr_cqhdr
.cq_hdr_count
= 1;
3024 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_REQUEST_ABORT
;
3026 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
3027 fcalpkt2
->fcal_pkt_cookie
= (void *)socalp
;
3028 mutex_exit(&socalp
->abort_mtx
);
3030 return (socal_doit(fcalpkt2
, port_statep
, polled
, socal_abort_done
,
3031 SOCAL_ABORT_TIMEOUT
, PORT_ABORT_PENDING
, NULL
));
3036 socal_els(void *ssp
, uint_t port
, uint_t elscode
, uint_t dest
,
3037 void (*callback
)(), void *arg
, caddr_t reqpl
, caddr_t
*rsppl
,
3040 return (FCAL_TRANSPORT_FAILURE
);
3044 socal_bypass_dev(void *ssp
, uint_t port
, uint_t dest
)
3046 fcal_packet_t
*fcalpkt
;
3047 soc_cmdonly_request_t
*scr
;
3048 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3049 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
3052 socal_packet_alloc(socalp
, FCAL_SLEEP
))
3053 == (fcal_packet_t
*)NULL
)
3054 return (FCAL_ALLOC_FAILED
);
3056 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
3058 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
3059 scr
->scr_soc_hdr
.sh_byte_cnt
= dest
;
3060 scr
->scr_cqhdr
.cq_hdr_count
= 1;
3061 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_BYPASS_DEV
;
3062 return (socal_doit(fcalpkt
, port_statep
, 0, socal_bypass_dev_done
,
3063 SOCAL_BYPASS_TIMEOUT
, PORT_BYPASS_PENDING
, NULL
));
3069 socal_force_reset(void *ssp
, uint_t port
, uint_t restart
)
3071 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3073 mutex_enter(&socalp
->k_imr_mtx
);
3074 if (socalp
->socal_shutdown
) {
3075 mutex_exit(&socalp
->k_imr_mtx
);
3078 socalp
->socal_shutdown
= 1;
3079 mutex_exit(&socalp
->k_imr_mtx
);
3081 socalp
->socal_stats
.resets
++;
3082 socal_doreset(socalp
);
3084 if (socal_start(socalp
) != FCAL_SUCCESS
) {
3085 cmn_err(CE_WARN
, "socal: start failed.\n");
3092 socal_add_ulp(void *ssp
, uint_t port
, uchar_t type
,
3093 void (*ulp_statec_callback
)(), void (*ulp_els_callback
)(),
3094 void (*ulp_data_callback
)(), void *arg
)
3096 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3097 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
3098 socal_unsol_cb_t
*cbentry
;
3100 mutex_enter(&port_statep
->sp_mtx
);
3101 for (cbentry
= port_statep
->sp_unsol_cb
; cbentry
;
3102 cbentry
= cbentry
->next
) {
3103 if (cbentry
->type
== type
) {
3104 cbentry
->statec_cb
= ulp_statec_callback
;
3105 cbentry
->els_cb
= ulp_els_callback
;
3106 cbentry
->data_cb
= ulp_data_callback
;
3108 mutex_exit(&port_statep
->sp_mtx
);
3112 mutex_exit(&port_statep
->sp_mtx
);
3114 (socal_unsol_cb_t
*)kmem_zalloc(sizeof (socal_unsol_cb_t
),
3115 KM_SLEEP
)) == (socal_unsol_cb_t
*)NULL
) {
3118 mutex_enter(&port_statep
->sp_mtx
);
3119 cbentry
->statec_cb
= ulp_statec_callback
;
3120 cbentry
->els_cb
= ulp_els_callback
;
3121 cbentry
->data_cb
= ulp_data_callback
;
3123 cbentry
->type
= type
;
3125 cbentry
->next
= port_statep
->sp_unsol_cb
;
3126 port_statep
->sp_unsol_cb
= cbentry
;
3127 mutex_exit(&port_statep
->sp_mtx
);
3132 * remove a ULP with matching type and arg
3135 socal_remove_ulp(void *ssp
, uint_t port
, uchar_t type
, void *arg
)
3137 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3138 socal_port_t
*port_statep
;
3139 socal_unsol_cb_t
*cbentry
;
3140 socal_unsol_cb_t
*p_cbentry
;
3143 ASSERT(ssp
!= NULL
);
3144 port_statep
= &socalp
->port_state
[port
];
3145 ASSERT(port_statep
!= NULL
);
3147 /* scan the list of unsolicited callback entries */
3148 mutex_enter(&port_statep
->sp_mtx
);
3150 for (cbentry
= port_statep
->sp_unsol_cb
;
3152 p_cbentry
= cbentry
, cbentry
= cbentry
->next
) {
3153 if ((cbentry
->type
!= type
) || (cbentry
->arg
!= arg
)) {
3154 continue; /* this entry doesn't match */
3156 /* found entry to remove */
3157 if (port_statep
->sp_unsol_cb
== cbentry
) {
3158 /* remove first entry in list */
3159 port_statep
->sp_unsol_cb
= cbentry
->next
;
3161 /* remove other entry in list */
3163 p_cbentry
->next
= cbentry
->next
;
3165 kmem_free((void *)cbentry
, sizeof (socal_unsol_cb_t
));
3166 DEBUGF(2, (CE_CONT
, "socal port %d ULP removed\n", port
));
3169 mutex_exit(&port_statep
->sp_mtx
);
3174 * static unsigned int
3175 * socal_intr() - this is the interrupt routine for the SOC. Process all
3176 * possible incoming interrupts from the soc device.
3180 socal_intr(caddr_t arg
)
3182 socal_state_t
*socalp
= (socal_state_t
*)arg
;
3183 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3187 int instance
= ddi_get_instance(socalp
->dip
);
3191 struct fcal_packet
*fpkt
, *nfpkt
;
3193 csr
= socalreg
->socal_csr
.w
;
3194 cause
= (int)SOCAL_INTR_CAUSE(socalp
, csr
);
3197 "socal%d: intr: csr: 0x%x cause: 0x%x\n",
3198 instance
, csr
, cause
));
3201 socalp
->socal_on_intr
= 0;
3202 return (DDI_INTR_UNCLAIMED
);
3205 socalp
->socal_on_intr
= 1;
3210 * Process the unsolicited messages first in case there are some
3211 * high priority async events that we should act on.
3215 if (cause
& SOCAL_CSR_RSP_QUE_1
) {
3216 socal_intr_unsolicited(socalp
, 1);
3217 DEBUGF(4, (CE_CONT
, "socal%d intr: did unsolicited\n", instance
));
3220 if (cause
& SOCAL_CSR_RSP_QUE_0
) {
3221 socal_intr_solicited(socalp
, 0);
3222 DEBUGF(4, (CE_CONT
, "socal%d intr: did solicited\n", instance
));
3226 * for use with token-only response queues in the future
3227 * if (cause & SOCAL_CSR_RSP_QUE_0) {
3228 * socal_intr_solicited(socalp, 0);
3234 * Process any request interrupts
3235 * We only allow request interrupts when the request
3236 * queue is full and we are waiting so we can enque
3239 if ((request
= (cause
& SOCAL_CSR_HOST_TO_SOCAL
)) != 0) {
3240 socalp
->socal_stats
.reqq_intrs
++;
3241 for (i
= SOCAL_CSR_1ST_H_TO_S
, j
= 0; j
< SOCAL_N_CQS
;
3244 socal_kcq_t
*kcq
= &socalp
->request
[j
];
3246 if (kcq
->skc_full
) {
3247 mutex_enter(&kcq
->skc_mtx
);
3248 full
= kcq
->skc_full
;
3250 while ((fpkt
= kcq
->skc_overflowh
) != NULL
) {
3251 nfpkt
= fpkt
->fcal_pkt_next
;
3252 fpkt
->fcal_pkt_next
= NULL
;
3253 kcq
->skc_overflowh
= nfpkt
;
3254 if (socal_cq_enque(socalp
, (socal_port_t
*)
3255 fpkt
->fcal_pkt_cookie
,
3256 (cqe_t
*)&fpkt
->fcal_socal_request
,
3257 j
, FCAL_NOSLEEP
, NULL
, 1) !=
3258 FCAL_TRANSPORT_SUCCESS
) {
3262 if (!kcq
->skc_overflowh
) {
3263 if (full
& SOCAL_SKC_SLEEP
)
3264 cv_broadcast(&kcq
->skc_cv
);
3266 /* Disable this queue's intrs */
3268 "socal%d: req que %d overflow cleared\n",
3270 mutex_enter(&socalp
->k_imr_mtx
);
3271 socalp
->socal_rp
->socal_imr
=
3272 (socalp
->socal_k_imr
&= ~i
);
3273 mutex_exit(&socalp
->k_imr_mtx
);
3275 mutex_exit(&kcq
->skc_mtx
);
3280 csr
= socalreg
->socal_csr
.w
;
3281 cause
= (int)SOCAL_INTR_CAUSE(socalp
, csr
);
3282 DEBUGF(4, (CE_CONT
, "socal%d intr: did request queues\n", instance
));
3286 socalp
->socal_on_intr
= 0;
3287 return (DDI_INTR_CLAIMED
);
3291 socal_intr_solicited(socal_state_t
*socalp
, uint32_t srq
)
3294 volatile socal_kcq_t
*kcqv
;
3295 soc_response_t
*srp
;
3298 fcal_packet_t
*fcalpkt
= NULL
;
3300 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3307 #if defined(DEBUG) && !defined(lint)
3308 int instance
= ddi_get_instance(socalp
->dip
);
3312 kcq
= &socalp
->response
[srq
];
3313 kcqv
= (volatile socal_kcq_t
*)kcq
;
3314 DEBUGF(4, (CE_CONT
, "socal%d intr_sol: entered \n", instance
));
3317 * Grab lock for request queue.
3319 mutex_enter(&kcq
->skc_mtx
);
3322 * Process as many response queue entries as we can.
3324 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3326 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3328 if (index_in
== kcqv
->skc_out
) {
3329 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3330 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_0
));
3332 /* make sure the write completed */
3333 i
= socalreg
->socal_csr
.w
;
3335 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3338 kcqv
->skc_in
= index_in
;
3340 while (kcqv
->skc_out
!= index_in
) {
3341 /* Find out where the newest entry lives in the queue */
3342 (void) ddi_dma_sync(kcq
->skc_dhandle
, 0, 0,
3343 DDI_DMA_SYNC_FORKERNEL
);
3345 srp
= (soc_response_t
*)cqe
;
3346 port
= srp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
;
3347 shp
= &srp
->sr_soc_hdr
;
3348 cq_hdr
= &srp
->sr_cqhdr
;
3350 * It turns out that on faster CPU's we have a problem where
3351 * the soc interrupts us before the response has been DMA'ed
3352 * in. This should not happen but does !!. So to workaround
3353 * the problem for now, check the sequence # of the response.
3354 * If it does not match with what we have, we must be
3355 * reading stale data
3357 if (cq_hdr
->cq_hdr_seqno
!= kcqv
->skc_seqno
) {
3358 #if defined(DEBUG) && !defined(lint)
3359 socal_read_stale_data
++;
3361 if (kcq
->deferred_intr_timeoutid
) {
3362 mutex_exit(&kcq
->skc_mtx
);
3365 kcq
->skc_saved_out
= kcqv
->skc_out
;
3366 kcq
->skc_saved_seqno
= kcqv
->skc_seqno
;
3367 kcq
->deferred_intr_timeoutid
= timeout(
3368 socal_deferred_intr
, (caddr_t
)kcq
,
3369 drv_usectohz(10000));
3370 mutex_exit(&kcq
->skc_mtx
);
3375 fcalpkt
= (fcal_packet_t
*)
3376 SOCAL_ID_LOOKUP(shp
->sh_request_token
);
3378 if ((socal_core
& SOCAL_TAKE_CORE
) && ddi_peek8(socalp
->dip
,
3379 (char *)fcalpkt
, &val
) != DDI_SUCCESS
) {
3380 cmn_err(CE_WARN
, "bad token = %p\n", (void *)fcalpkt
);
3381 mutex_exit(&kcq
->skc_mtx
);
3382 socal_take_core(socalp
);
3385 if ((fcalpkt
== (fcal_packet_t
*)NULL
) ||
3386 (fcalpkt
->fcal_magic
!= FCALP_MAGIC
)) {
3387 (void) sprintf(buf
, "!invalid FC packet; \n\
3388 in, out, seqno = 0x%x, 0x%x, 0x%x\n",
3389 kcqv
->skc_in
, kcqv
->skc_out
, kcqv
->skc_seqno
);
3390 socal_disp_err(socalp
, CE_WARN
, "link.4060", buf
);
3392 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3393 socalreg
->socal_cr
.w
,
3394 socalreg
->socal_sae
.w
,
3395 socalreg
->socal_csr
.w
,
3396 socalreg
->socal_imr
));
3398 * Update response queue ptrs and soc registers.
3401 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3408 DEBUGF(2, (CE_CONT
, "packet 0x%p complete\n",
3410 status
= srp
->sr_soc_status
;
3411 fcalpkt
->fcal_pkt_status
= status
;
3412 DEBUGF(2, (CE_CONT
, "SOC status: 0x%x\n", status
));
3414 * map soc status codes to
3415 * transport status codes
3418 ASSERT((fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)
3420 mutex_enter(&socalp
->abort_mtx
);
3421 fcalpkt
->fcal_pkt_flags
|= FCFLAG_COMPLETE
;
3422 mutex_exit(&socalp
->abort_mtx
);
3425 * Copy the response frame header (if there is one)
3426 * so that the upper levels can use it. Note that,
3427 * for now, we'll copy the header only if there was
3428 * some sort of non-OK status, to save the PIO reads
3429 * required to get the header from the host adapter's
3432 if (((status
!= FCAL_STATUS_OK
) ||
3433 (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
3434 & SOC_RESP_HEADER
)) &&
3435 (srp
->sr_soc_hdr
.sh_flags
& SOC_FC_HEADER
)) {
3436 src
= (caddr_t
)&srp
->sr_fc_frame_hdr
;
3437 dst
= (caddr_t
)&fcalpkt
->fcal_resp_hdr
;
3438 bcopy(src
, dst
, sizeof (fc_frame_header_t
));
3439 fcalpkt
->fcal_pkt_flags
|= FCFLAG_RESP_HEADER
;
3440 i
= srp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
?
3442 if ((status
!= FCAL_STATUS_OK
) &&
3443 (status
<= FCAL_STATUS_MAX_STATUS
)) {
3444 socalp
->socal_stats
.pstats
[i
].
3445 resp_status
[status
]++;
3447 socalp
->socal_stats
.pstats
[i
].
3448 resp_status
[FCAL_STATUS_ERROR
]++;
3450 } else if (status
== FCAL_STATUS_OK
) {
3451 fcalpkt
->fcal_socal_request
.
3452 sr_soc_hdr
.sh_byte_cnt
=
3455 fcalpkt
->fcal_diag_status
=
3456 (uint32_t)srp
->sr_dataseg
.fc_base
;
3457 fcalpkt
->fcal_ncmds
= srp
->sr_ncmds
;
3460 * Update response queue ptrs and soc registers.
3463 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3468 /* For incmplt DMA offline loop by loopback */
3469 if (fcalpkt
->fcal_pkt_status
==
3470 FCAL_STATUS_INCOMPLETE_DMA_ERR
) {
3471 socal_port_t
*port_statep
;
3475 * Give up the mutex to avoid a deadlock
3476 * with the loopback routine.
3478 mutex_exit(&kcq
->skc_mtx
);
3480 port_statep
= &socalp
->port_state
[port
];
3481 mutex_enter(&port_statep
->sp_mtx
);
3482 if (port_statep
->sp_status
&
3484 /* Already disabled */
3485 mutex_exit(&port_statep
->sp_mtx
);
3487 port_statep
->sp_status
|=
3489 mutex_exit(&port_statep
->sp_mtx
);
3490 (void) socal_diag_request(
3491 (void *)socalp
, port
,
3492 &r
, SOC_DIAG_INT_LOOP
);
3494 /* reacquire mutex */
3495 mutex_enter(&kcq
->skc_mtx
);
3499 * Complete the packet *ONLY* if it not being aborted
3500 * or the abort has already completed. Otherwise it is
3501 * not safe to free the ID.
3503 mutex_enter(&socalp
->abort_mtx
);
3504 if (!(fcalpkt
->fcal_pkt_flags
& FCFLAG_ABORTING
)) {
3506 * Call the completion routine
3508 SOCAL_ID_FREE(shp
->sh_request_token
);
3509 if (fcalpkt
->fcal_pkt_comp
!= NULL
) {
3510 fcalpkt
->fcal_cmd_state
|=
3514 * Give up the mutex to avoid a
3515 * deadlock with the callback routine.
3517 mutex_exit(&socalp
->abort_mtx
);
3518 mutex_exit(&kcq
->skc_mtx
);
3521 (*fcalpkt
->fcal_pkt_comp
)(fcalpkt
);
3523 /* reacquire mutex */
3524 mutex_enter(&kcq
->skc_mtx
);
3526 fcalpkt
->fcal_cmd_state
|=
3528 mutex_exit(&socalp
->abort_mtx
);
3531 mutex_exit(&socalp
->abort_mtx
);
3536 if (kcq
->skc_cq
== NULL
)
3538 * This action averts a potential PANIC scenario
3539 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3540 * when we let it go, to call our completion routine,
3541 * and "initialized" the response queue. We exit our
3542 * processing loop here, thereby averting a PANIC due
3543 * to a NULL de-reference from the response queue.
3545 * Note that this is an interim measure that needs
3546 * to be revisited when this driver is next revised
3547 * for enhanced performance.
3552 * We need to re-read the input and output pointers in
3553 * case a polling routine should process some entries
3554 * from the response queue while we're doing a callback
3555 * routine with the response queue mutex dropped.
3557 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3558 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3561 * Mess around with the hardware if we think we've run out
3562 * of entries in the queue, just to make sure we've read
3563 * all entries that are available.
3566 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3567 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_0
));
3569 /* Make sure the csr write has completed */
3570 i
= socalreg
->socal_csr
.w
;
3571 DEBUGF(9, (CE_CONT
, "csr.w = %x\n", i
));
3574 * Update our idea of where the host adapter has placed
3575 * the most recent entry in the response queue and resync
3576 * the response queue
3578 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3580 kcqv
->skc_in
= index_in
;
3583 /* Drop lock for request queue. */
3584 mutex_exit(&kcq
->skc_mtx
);
3588 * Function name : socal_intr_unsolicited()
3590 * Return Values : none
3592 * Description : Processes entries in the unsolicited response
3595 * The SOC+ will give us an unsolicited response
3596 * whenever its status changes: OFFLINE, ONLINE,
3597 * or in response to a packet arriving from an originator.
3599 * When message requests come in they will be placed in our
3600 * buffer queue or in the next "inline" packet by the SOC hardware.
3602 * Context : Unsolicited interrupts must be masked
3606 socal_intr_unsolicited(socal_state_t
*socalp
, uint32_t urq
)
3609 volatile socal_kcq_t
*kcqv
;
3610 soc_response_t
*srp
;
3611 volatile cqe_t
*cqe
;
3613 register uchar_t t_index
, t_seqno
;
3614 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3615 volatile cqe_t
*cqe_cont
= NULL
;
3621 socal_port_t
*port_statep
;
3622 #if defined(DEBUG) && !defined(lint)
3623 int instance
= ddi_get_instance(socalp
->dip
);
3626 socal_unsol_cb_t
*cblist
;
3628 kcq
= &socalp
->response
[urq
];
3629 kcqv
= (volatile socal_kcq_t
*)kcq
;
3632 * Grab lock for response queue.
3634 mutex_enter(&kcq
->skc_mtx
);
3636 cqe
= (volatile cqe_t
*)&(kcq
->skc_cq
[kcqv
->skc_out
]);
3638 index_in
= SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3640 kcqv
->skc_in
= index_in
;
3642 while (kcqv
->skc_out
!= index_in
) {
3643 (void) ddi_dma_sync(kcq
->skc_dhandle
, 0, 0,
3644 DDI_DMA_SYNC_FORKERNEL
);
3646 /* Check for continuation entries */
3647 if ((hdr_count
= cqe
->cqe_hdr
.cq_hdr_count
) != 1) {
3649 t_seqno
= kcqv
->skc_seqno
;
3650 t_index
= kcqv
->skc_out
+ hdr_count
;
3653 if (kcqv
->skc_out
> index_in
)
3654 i
+= kcq
->skc_last_index
+ 1;
3657 * If we think the continuation entries haven't yet
3658 * arrived, try once more before giving up
3662 socalreg
->socal_csr
.w
=
3663 ((kcqv
->skc_out
<< 24) |
3664 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3666 /* Make sure the csr write has completed */
3667 i
= socalreg
->socal_csr
.w
;
3670 * Update our idea of where the host adapter has placed
3671 * the most recent entry in the response queue
3673 i
= index_in
= SOCAL_RESPONSEQ_INDEX(urq
,
3674 socalreg
->socal_rspp
.w
);
3675 if (kcqv
->skc_out
> index_in
)
3676 i
+= kcq
->skc_last_index
+ 1;
3679 * Exit if the continuation entries haven't yet
3686 if (t_index
> kcq
->skc_last_index
) {
3688 t_index
&= kcq
->skc_last_index
;
3691 cqe_cont
= (volatile cqe_t
*)
3692 &(kcq
->skc_cq
[t_index
? t_index
- 1 :
3693 kcq
->skc_last_index
]);
3696 /* A cq_hdr_count > 2 is illegal; throw away the response */
3699 * XXX - should probably throw out as many entries as the
3700 * hdr_cout tells us there are
3702 if (hdr_count
!= 2) {
3703 socal_disp_err(socalp
, CE_WARN
, "driver.4030",
3704 "!too many continuation entries");
3706 "socal%d: soc+ unsolicited entry count = %d\n",
3707 instance
, cqe
->cqe_hdr
.cq_hdr_count
));
3709 if ((++t_index
& kcq
->skc_last_index
) == 0) {
3713 kcqv
->skc_out
= t_index
;
3714 kcqv
->skc_seqno
= t_seqno
;
3716 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3723 * Update unsolicited response queue ptrs
3726 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3731 if (cqe_cont
!= NULL
) {
3733 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3739 if (index_in
== kcqv
->skc_out
) {
3740 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3741 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3743 /* Make sure the csr write has completed */
3744 i
= socalreg
->socal_csr
.w
;
3747 srp
= (soc_response_t
*)cqe
;
3748 flags
= srp
->sr_soc_hdr
.sh_flags
;
3749 port
= flags
& SOC_PORT_B
;
3750 port_statep
= &socalp
->port_state
[port
];
3753 * XXX need to deal buffer pool entries here
3755 switch (flags
& ~SOC_PORT_B
) {
3756 case SOC_UNSOLICITED
| SOC_FC_HEADER
:
3758 srp
= (soc_response_t
*)cqe
;
3760 switch (srp
->sr_fc_frame_hdr
.r_ctl
& R_CTL_ROUTING
) {
3761 case R_CTL_EXTENDED_SVC
:
3763 * Extended Link Services frame received
3765 socalp
->socal_stats
.pstats
[port
].els_rcvd
++;
3766 socal_us_els(socalp
, (cqe_t
*)cqe
, (caddr_t
)cqe_cont
);
3768 /* do callbacks to any interested ULPs */
3769 mutex_enter(&port_statep
->sp_mtx
);
3770 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3771 cblist
= cblist
->next
) {
3772 if (cblist
->els_cb
) {
3773 mutex_exit(&port_statep
->sp_mtx
);
3774 mutex_exit(&kcq
->skc_mtx
);
3775 cblist
->els_cb(cblist
->arg
,
3778 mutex_enter(&kcq
->skc_mtx
);
3779 mutex_enter(&port_statep
->sp_mtx
);
3782 mutex_exit(&port_statep
->sp_mtx
);
3784 case R_CTL_BASIC_SVC
:
3786 "!unsupported Link Service command: 0x%x",
3787 srp
->sr_fc_frame_hdr
.type
);
3788 socal_disp_err(socalp
, CE_WARN
, "link.4020", buf
);
3790 case R_CTL_DEVICE_DATA
:
3791 switch (srp
->sr_fc_frame_hdr
.type
) {
3793 mutex_enter(&port_statep
->sp_mtx
);
3795 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3796 cblist
= cblist
->next
) {
3797 if (cblist
->data_cb
&&
3799 srp
->sr_fc_frame_hdr
.type
)) {
3800 mutex_exit(&port_statep
->sp_mtx
);
3801 mutex_exit(&kcq
->skc_mtx
);
3802 cblist
->data_cb(cblist
->arg
,
3803 (cqe_t
*)cqe
, (caddr_t
)cqe_cont
);
3804 mutex_enter(&kcq
->skc_mtx
);
3805 mutex_enter(&port_statep
->sp_mtx
);
3809 mutex_exit(&port_statep
->sp_mtx
);
3815 "!unknown FC-4 command: 0x%x",
3816 srp
->sr_fc_frame_hdr
.type
);
3817 socal_disp_err(socalp
, CE_WARN
,
3823 (void) sprintf(buf
, "!unsupported FC frame R_CTL: 0x%x",
3824 srp
->sr_fc_frame_hdr
.r_ctl
);
3825 socal_disp_err(socalp
, CE_WARN
, "link.4040", buf
);
3833 * Note that only the lsbyte of the status has
3834 * interesting information...
3836 status
= srp
->sr_soc_status
;
3840 case FCAL_STATUS_ONLINE
:
3842 "!port %d: Fibre Channel is ONLINE\n", port
);
3843 socal_disp_err(socalp
, CE_CONT
, "link.6010",
3845 mutex_enter(&port_statep
->sp_mtx
);
3846 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3847 port_statep
->sp_status
|= PORT_ONLINE
;
3848 mutex_exit(&port_statep
->sp_mtx
);
3849 socalp
->socal_stats
.pstats
[port
].onlines
++;
3851 "socal%d intr_unsol: ONLINE intr\n",
3855 case FCAL_STATUS_LOOP_ONLINE
:
3857 "!port %d: Fibre Channel Loop is ONLINE\n",
3859 socal_disp_err(socalp
, CE_CONT
, "link.6010",
3861 mutex_enter(&port_statep
->sp_mtx
);
3862 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3863 port_statep
->sp_status
|= PORT_ONLINE_LOOP
;
3864 mutex_exit(&port_statep
->sp_mtx
);
3865 socalp
->socal_stats
.pstats
[port
].online_loops
++;
3867 "socal%d intr_unsol: ONLINE-LOOP intr\n",
3871 case FCAL_STATUS_ERR_OFFLINE
:
3873 * SOC and Responder will both flush
3874 * all active commands.
3875 * So I don't have to do anything
3876 * until it comes back online.
3879 "!port %d: Fibre Channel is OFFLINE\n", port
);
3880 socal_disp_err(socalp
, CE_CONT
, "link.5010",
3883 mutex_enter(&port_statep
->sp_mtx
);
3884 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3885 port_statep
->sp_status
|= PORT_OFFLINE
;
3886 port_statep
->sp_lilpmap_valid
= 0;
3887 mutex_exit(&port_statep
->sp_mtx
);
3888 socalp
->socal_stats
.pstats
[port
].offlines
++;
3890 "socal%d intr_unsol: OFFLINE intr\n",
3895 (void) sprintf(buf
, "!unknown status: 0x%x\n",
3897 socal_disp_err(socalp
, CE_WARN
, "link.3020",
3900 mutex_exit(&kcq
->skc_mtx
);
3901 mutex_enter(&port_statep
->sp_mtx
);
3902 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3903 cblist
= cblist
->next
) {
3904 if (cblist
->statec_cb
) {
3905 mutex_exit(&port_statep
->sp_mtx
);
3906 (*cblist
->statec_cb
)(cblist
->arg
,
3908 mutex_enter(&port_statep
->sp_mtx
);
3911 mutex_exit(&port_statep
->sp_mtx
);
3912 if (status
== FCAL_STATUS_ERR_OFFLINE
) {
3913 socal_flush_overflowq(socalp
, port
,
3915 socal_flush_overflowq(socalp
, port
,
3918 mutex_enter(&kcq
->skc_mtx
);
3922 (void) sprintf(buf
, "!unexpected state: flags: 0x%x\n",
3924 socal_disp_err(socalp
, CE_WARN
, "link.4050", buf
);
3926 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3927 socalp
->socal_rp
->socal_cr
.w
,
3928 socalp
->socal_rp
->socal_sae
.w
,
3929 socalp
->socal_rp
->socal_csr
.w
,
3930 socalp
->socal_rp
->socal_imr
));
3934 if (kcq
->skc_cq
== NULL
)
3936 * This action averts a potential PANIC scenario
3937 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3938 * when we let it go, to call our completion routine,
3939 * and "initialized" the response queue. We exit our
3940 * processing loop here, thereby averting a PANIC due
3941 * to a NULL de-reference from the response queue.
3943 * Note that this is an interim measure that needs
3944 * to be revisited when this driver is next revised
3945 * for enhanced performance.
3950 * We need to re-read the input and output pointers in
3951 * case a polling routine should process some entries
3952 * from the response queue while we're doing a callback
3953 * routine with the response queue mutex dropped.
3955 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3956 index_in
= SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3960 * Mess around with the hardware if we think we've run out
3961 * of entries in the queue, just to make sure we've read
3962 * all entries that are available.
3964 if (index_in
== kcqv
->skc_out
) {
3966 socalreg
->socal_csr
.w
=
3967 ((kcqv
->skc_out
<< 24) |
3968 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3970 /* Make sure the csr write has completed */
3971 i
= socalreg
->socal_csr
.w
;
3974 * Update our idea of where the host adapter has placed
3975 * the most recent entry in the response queue
3978 SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3981 socalp
->socal_stats
.pstats
[port
].unsol_resps
++;
3983 kcqv
->skc_in
= index_in
;
3987 /* Release lock for response queue. */
3988 mutex_exit(&kcq
->skc_mtx
);
3992 * socal_us_els() - This function handles unsolicited extended link
3993 * service responses received from the soc.
3996 socal_us_els(socal_state_t
*socalp
, cqe_t
*cqe
, caddr_t payload
)
3998 soc_response_t
*srp
= (soc_response_t
*)cqe
;
3999 els_payload_t
*els
= (els_payload_t
*)payload
;
4005 * There should be a CQE continuation entry for all
4006 * extended link services
4008 if ((els
== NULL
) || ((i
= srp
->sr_soc_hdr
.sh_byte_cnt
) == 0)) {
4009 socal_disp_err(socalp
, CE_WARN
, "link.4010",
4010 "!incomplete continuation entry");
4014 /* Quietly impose a maximum byte count */
4015 if (i
> SOC_CQE_PAYLOAD
)
4016 i
= SOC_CQE_PAYLOAD
;
4017 i
-= sizeof (union els_cmd_u
);
4020 * Decode the LS_Command code
4022 switch (els
->els_cmd
.c
.ls_command
) {
4023 case LA_ELS_DISPLAY
:
4024 els
->els_data
[i
] = '\0'; /* terminate the string */
4025 for (bp
= (char *)&(els
->els_data
[0]); *bp
; bp
++) {
4026 /* squash newlines */
4027 if (*bp
== '\n') *bp
= ' ';
4029 (void) sprintf(buf
, "!message: %s\n", els
->els_data
);
4030 socal_disp_err(socalp
, CE_CONT
, "link.1010", buf
);
4034 DEBUGF(3, (CE_CONT
, "!unknown LS_Command, %x\n",
4042 static fcal_packet_t
*
4043 socal_packet_alloc(socal_state_t
*socalp
, fcal_sleep_t sleep
)
4048 if (sleep
== FCAL_SLEEP
)
4053 pkt
= (fcal_packet_t
*)kmem_zalloc(sizeof (fcal_packet_t
), flag
);
4055 if (pkt
!= (fcal_packet_t
*)NULL
)
4056 pkt
->fcal_magic
= FCALP_MAGIC
;
4062 socal_packet_free(fcal_packet_t
*fcalpkt
)
4064 kmem_free((void *)fcalpkt
, sizeof (fcal_packet_t
));
4068 socal_lilp_map_done(fcal_packet_t
*fcalpkt
)
4071 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4073 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4077 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4078 socalp
->port_state
[port
].sp_status
&= ~PORT_LILP_PENDING
;
4079 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4080 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4084 socal_force_lip_done(fcal_packet_t
*fcalpkt
)
4087 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4089 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4093 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4094 socalp
->port_state
[port
].sp_status
&= ~PORT_LIP_PENDING
;
4095 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4096 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4100 socal_adisc_done(fcal_packet_t
*fcalpkt
)
4103 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4105 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4109 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4110 socalp
->port_state
[port
].sp_status
&= ~PORT_ADISC_PENDING
;
4111 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4112 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4116 socal_lbf_done(fcal_packet_t
*fcalpkt
)
4119 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4121 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4125 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4126 socalp
->port_state
[port
].sp_status
&= ~PORT_LBF_PENDING
;
4127 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4128 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4132 socal_rls_done(fcal_packet_t
*fcalpkt
)
4135 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4137 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4141 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4142 socalp
->port_state
[port
].sp_status
&= ~PORT_RLS_PENDING
;
4143 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4144 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4148 socal_force_offline_done(fcal_packet_t
*fcalpkt
)
4151 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4153 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4157 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4158 socalp
->port_state
[port
].sp_status
&= ~PORT_OFFLINE_PENDING
;
4159 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4160 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4164 socal_abort_done(fcal_packet_t
*fcalpkt
)
4167 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4169 (soc_header_t
*)&fcalpkt
->fcal_socal_request
.sr_soc_hdr
;
4170 fcal_packet_t
*target
= (fcal_packet_t
*)
4171 SOCAL_ID_LOOKUP(shp
->sh_request_token
);
4173 mutex_enter(&socalp
->abort_mtx
);
4174 ASSERT(target
->fcal_pkt_flags
& FCFLAG_ABORTING
);
4175 if (!(target
->fcal_pkt_flags
& FCFLAG_COMPLETE
)) {
4176 SOCAL_ID_FREE(shp
->sh_request_token
);
4178 mutex_exit(&socalp
->abort_mtx
);
4179 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4183 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4184 socalp
->port_state
[port
].sp_status
&= ~PORT_ABORT_PENDING
;
4185 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4186 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4190 socal_bypass_dev_done(fcal_packet_t
*fcalpkt
)
4193 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4194 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4198 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4199 socalp
->port_state
[port
].sp_status
&= ~PORT_BYPASS_PENDING
;
4200 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4201 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4206 socal_dummy_intr(caddr_t arg
)
4208 return (DDI_INTR_UNCLAIMED
);
4212 socal_diag_request(socal_state_t
*socalp
, uint32_t port
, uint_t
*diagcode
,
4215 fcal_packet_t
*fcalpkt
;
4216 soc_diag_request_t
*sdr
;
4217 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
4218 struct fcal_lilp_map map
;
4220 /* Grabbing the state mutex is totally unnecessary.... */
4221 if (!(port_statep
->sp_status
& PORT_DISABLED
)) {
4222 if (socal_getmap(socalp
, port
, (caddr_t
)&map
, 0, FKIOCTL
)
4224 if (map
.lilp_length
!= 1 && ((port_statep
->sp_status
&
4225 PORT_ONLINE_LOOP
) && cmd
!= SOC_DIAG_REM_LOOP
))
4226 return (FCAL_TRANSPORT_UNAVAIL
);
4229 if ((fcalpkt
= socal_packet_alloc(socalp
, FCAL_SLEEP
))
4230 == (fcal_packet_t
*)NULL
)
4231 return (FCAL_ALLOC_FAILED
);
4232 sdr
= (soc_diag_request_t
*)&fcalpkt
->fcal_socal_request
;
4234 sdr
->sdr_soc_hdr
.sh_flags
= SOC_PORT_B
;
4235 sdr
->sdr_diag_cmd
= cmd
;
4236 sdr
->sdr_cqhdr
.cq_hdr_count
= 1;
4237 sdr
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_DIAGNOSTIC
;
4238 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4239 return (socal_doit(fcalpkt
, port_statep
, 1, NULL
,
4240 SOCAL_DIAG_TIMEOUT
, 0, diagcode
));
4244 socal_force_offline(void *ssp
, uint_t port
, uint_t polled
)
4246 fcal_packet_t
*fcalpkt
;
4247 soc_cmdonly_request_t
*scr
;
4248 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
4249 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
4252 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4253 == (fcal_packet_t
*)NULL
)
4254 return (FCAL_ALLOC_FAILED
);
4256 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
4258 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
4259 scr
->scr_cqhdr
.cq_hdr_count
= 1;
4260 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_OFFLINE
;
4261 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4262 return (socal_doit(fcalpkt
, port_statep
, 0, socal_force_offline_done
,
4263 SOCAL_OFFLINE_TIMEOUT
, PORT_OFFLINE_PENDING
, NULL
));
4267 socal_issue_adisc(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4268 la_els_adisc_t
*payload
, uint32_t polled
)
4271 la_els_adisc_t
*buf
;
4272 fcal_packet_t
*fcalpkt
;
4273 socal_port_t
*port_statep
;
4274 socal_priv_cmd_t
*privp
;
4276 port_statep
= &socalp
->port_state
[port
];
4279 socal_els_alloc(socalp
, port
, dest
, sizeof (la_els_adisc_t
),
4280 sizeof (la_els_adisc_t
), (caddr_t
*)&privp
, polled
))
4281 == (fcal_packet_t
*)NULL
)
4282 return (FCAL_ALLOC_FAILED
);
4284 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4285 buf
= (la_els_adisc_t
*)privp
->cmd
;
4286 buf
->ls_code
= LA_ELS_ADISC
;
4290 buf
->hard_address
= 0;
4291 bcopy((caddr_t
)&port_statep
->sp_p_wwn
,
4292 (caddr_t
)&buf
->port_wwn
, sizeof (buf
->port_wwn
));
4293 bcopy((caddr_t
)&socalp
->socal_n_wwn
,
4294 (caddr_t
)&buf
->node_wwn
, sizeof (buf
->node_wwn
));
4295 buf
->nport_id
= fcalpkt
->fcal_socal_request
.sr_fc_frame_hdr
.s_id
;
4296 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4298 retval
= socal_doit(fcalpkt
, port_statep
, 0, socal_adisc_done
,
4299 SOCAL_ADISC_TIMEOUT
, PORT_ADISC_PENDING
, NULL
);
4300 if (retval
== FCAL_SUCCESS
) {
4301 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4302 DDI_DMA_SYNC_FORKERNEL
);
4303 bcopy(privp
->rsp
, (caddr_t
)payload
, sizeof (la_els_adisc_t
));
4305 privp
->fapktp
= NULL
;
4306 socal_els_free(privp
);
4311 socal_issue_lbf(socal_state_t
*socalp
, uint32_t port
,
4312 uchar_t
*payload
, size_t length
, uint32_t polled
)
4315 fcal_packet_t
*fcalpkt
;
4316 socal_port_t
*port_statep
;
4317 socal_priv_cmd_t
*privp
;
4319 port_statep
= &socalp
->port_state
[port
];
4321 if ((fcalpkt
= socal_lbf_alloc(socalp
, port
, length
, length
,
4322 (caddr_t
*)&privp
, polled
)) == (fcal_packet_t
*)NULL
)
4323 return (FCAL_ALLOC_FAILED
);
4325 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4326 bcopy((caddr_t
)payload
, privp
->cmd
, length
);
4327 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4329 retval
= socal_doit(fcalpkt
, port_statep
, polled
, socal_lbf_done
,
4330 SOCAL_LBF_TIMEOUT
, PORT_LBF_PENDING
, NULL
);
4332 if (retval
== FCAL_SUCCESS
) {
4333 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4334 DDI_DMA_SYNC_FORKERNEL
);
4335 bcopy(privp
->rsp
, (caddr_t
)payload
, length
);
4337 privp
->fapktp
= NULL
;
4338 socal_lbf_free(privp
);
4343 socal_issue_rls(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4344 la_els_rls_reply_t
*payload
, uint32_t polled
)
4348 fcal_packet_t
*fcalpkt
;
4349 socal_port_t
*port_statep
;
4350 socal_priv_cmd_t
*privp
;
4353 port_statep
= &socalp
->port_state
[port
];
4355 if (dest
== socal_getmap(socalp
, port
, NULL
, 0, 0)) {
4356 /* load up the the struct with the local lesb */
4357 struct la_els_rjt
*rsp
= (struct la_els_rjt
*)payload
;
4359 rsp
->ls_code
= LA_ELS_RJT
;
4363 rsp
->reason_code
= RJT_UNSUPPORTED
;
4365 rsp
->explanation
= 0;
4367 return (FCAL_SUCCESS
);
4371 socal_els_alloc(socalp
, port
, dest
, sizeof (la_els_rls_t
),
4372 sizeof (la_els_rls_reply_t
), (caddr_t
*)&privp
, polled
))
4373 == (fcal_packet_t
*)NULL
)
4374 return (FCAL_ALLOC_FAILED
);
4376 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4378 if (payload
->link_failure
& 0xff000000)
4379 arg
= payload
->link_failure
;
4383 buf
= (la_els_rls_t
*)privp
->cmd
;
4384 buf
->ls_code
= LA_ELS_RLS
;
4389 buf
->nport_id
[0] = (arg
>> 16) & 0xff;
4390 buf
->nport_id
[1] = (arg
>> 8) & 0xff;
4391 buf
->nport_id
[2] = arg
& 0xff;
4392 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4394 retval
= socal_doit(fcalpkt
, port_statep
, 0, socal_rls_done
,
4395 SOCAL_RLS_TIMEOUT
, PORT_RLS_PENDING
, NULL
);
4396 if (retval
== FCAL_SUCCESS
) {
4397 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4398 DDI_DMA_SYNC_FORKERNEL
);
4399 bcopy(privp
->rsp
, (caddr_t
)payload
,
4400 sizeof (la_els_rls_reply_t
));
4402 privp
->fapktp
= NULL
;
4403 socal_els_free(privp
);
4408 socal_els_alloc(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4409 uint32_t cmd_size
, uint32_t rsp_size
, caddr_t
*rprivp
, uint32_t polled
)
4411 struct fcal_packet
*fcalpkt
;
4412 ddi_dma_cookie_t ccookie
;
4413 ddi_dma_cookie_t rcookie
;
4414 socal_priv_cmd_t
*privp
;
4415 ddi_dma_handle_t chandle
= NULL
;
4416 ddi_dma_handle_t rhandle
= NULL
;
4417 ddi_acc_handle_t cacchandle
;
4418 ddi_acc_handle_t racchandle
;
4420 fc_frame_header_t
*fhp
;
4421 uint_t ccount
, cmd_bound
= 0, rsp_bound
= 0;
4428 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4429 == (fcal_packet_t
*)NULL
)
4433 (socal_priv_cmd_t
*)kmem_zalloc(sizeof (socal_priv_cmd_t
),
4434 polled
? KM_NOSLEEP
: KM_SLEEP
)) == (socal_priv_cmd_t
*)NULL
) {
4438 rprivp
= (caddr_t
*)&privp
;
4440 fcalpkt
->fcal_pkt_private
= (caddr_t
)privp
;
4441 privp
->fapktp
= (void *)fcalpkt
;
4443 if ((ouralpa
= socal_getmap(socalp
, port
, NULL
, 0, 0)) == -1)
4446 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4447 DDI_DMA_DONTWAIT
, NULL
, &chandle
) != DDI_SUCCESS
)
4449 privp
->cmd_handle
= chandle
;
4451 if (ddi_dma_mem_alloc(chandle
, cmd_size
, &socal_acc_attr
,
4452 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4453 (caddr_t
*)&cmd
, &real_len
, &cacchandle
) != DDI_SUCCESS
)
4456 privp
->cmd_acchandle
= cacchandle
;
4458 if (real_len
< cmd_size
)
4461 if (ddi_dma_addr_bind_handle(chandle
, (struct as
*)NULL
,
4462 (caddr_t
)cmd
, cmd_size
,
4463 DDI_DMA_WRITE
| DDI_DMA_CONSISTENT
,
4464 DDI_DMA_DONTWAIT
, NULL
, &ccookie
, &ccount
)
4472 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4473 DDI_DMA_DONTWAIT
, NULL
, &rhandle
) != DDI_SUCCESS
)
4476 privp
->rsp_handle
= rhandle
;
4477 if (ddi_dma_mem_alloc(rhandle
, rsp_size
, &socal_acc_attr
,
4478 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4479 &rsp
, &real_len
, &racchandle
) != DDI_SUCCESS
)
4482 privp
->rsp_acchandle
= racchandle
;
4483 if (real_len
< rsp_size
)
4486 if (ddi_dma_addr_bind_handle(rhandle
, (struct as
*)NULL
,
4488 DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4489 DDI_DMA_DONTWAIT
, NULL
, &rcookie
, &ccount
)
4498 srp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
4499 srp
->sr_soc_hdr
.sh_flags
= SOC_FC_HEADER
;
4501 srp
->sr_soc_hdr
.sh_flags
|= SOC_PORT_B
;
4502 srp
->sr_soc_hdr
.sh_class
= 3;
4503 srp
->sr_soc_hdr
.sh_byte_cnt
= cmd_size
;
4504 srp
->sr_dataseg
[0].fc_base
= (uint32_t)ccookie
.dmac_address
;
4505 srp
->sr_dataseg
[0].fc_count
= cmd_size
;
4506 if (rsp_size
== 0) {
4507 srp
->sr_soc_hdr
.sh_seg_cnt
= 1;
4509 srp
->sr_soc_hdr
.sh_seg_cnt
= 2;
4510 srp
->sr_dataseg
[1].fc_base
= (uint32_t)rcookie
.dmac_address
;
4511 srp
->sr_dataseg
[1].fc_count
= rsp_size
;
4513 srp
->sr_cqhdr
.cq_hdr_count
= 1;
4514 /* this will potentially be overwritten by the calling function */
4515 srp
->sr_cqhdr
.cq_hdr_type
= CQ_TYPE_SIMPLE
;
4517 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4519 /* Fill in the Fabric Channel Header */
4520 fhp
= &srp
->sr_fc_frame_hdr
;
4521 fhp
->r_ctl
= R_CTL_ELS_REQ
;
4523 fhp
->s_id
= ouralpa
;
4524 fhp
->type
= TYPE_EXTENDED_LS
;
4525 fhp
->f_ctl
= F_CTL_SEQ_INITIATIVE
| F_CTL_FIRST_SEQ
;
4529 fhp
->ox_id
= 0xffff;
4530 fhp
->rx_id
= 0xffff;
4534 socal_packet_free(fcalpkt
);
4536 if (privp
->cmd_handle
) {
4538 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4539 ddi_dma_free_handle(&privp
->cmd_handle
);
4542 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4543 if (privp
->rsp_handle
) {
4545 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4546 ddi_dma_free_handle(&privp
->rsp_handle
);
4549 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4551 kmem_free(privp
, sizeof (*privp
));
4557 socal_lbf_alloc(socal_state_t
*socalp
, uint32_t port
,
4558 uint32_t cmd_size
, uint32_t rsp_size
, caddr_t
*rprivp
,
4561 struct fcal_packet
*fcalpkt
;
4562 ddi_dma_cookie_t ccookie
;
4563 ddi_dma_cookie_t rcookie
;
4564 socal_priv_cmd_t
*privp
;
4565 ddi_dma_handle_t chandle
= NULL
;
4566 ddi_dma_handle_t rhandle
= NULL
;
4567 ddi_acc_handle_t cacchandle
;
4568 ddi_acc_handle_t racchandle
;
4570 fc_frame_header_t
*fhp
;
4571 uint_t ccount
, cmd_bound
= 0, rsp_bound
= 0;
4577 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4578 == (fcal_packet_t
*)NULL
)
4582 (socal_priv_cmd_t
*)kmem_zalloc(sizeof (socal_priv_cmd_t
),
4583 polled
? KM_NOSLEEP
: KM_SLEEP
)) == (socal_priv_cmd_t
*)NULL
) {
4587 rprivp
= (caddr_t
*)&privp
;
4589 fcalpkt
->fcal_pkt_private
= (caddr_t
)privp
;
4590 privp
->fapktp
= (void *)fcalpkt
;
4592 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4593 DDI_DMA_DONTWAIT
, NULL
, &chandle
) != DDI_SUCCESS
)
4595 privp
->cmd_handle
= chandle
;
4597 if (ddi_dma_mem_alloc(chandle
, cmd_size
, &socal_acc_attr
,
4598 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4599 (caddr_t
*)&cmd
, &real_len
, &cacchandle
) != DDI_SUCCESS
)
4602 privp
->cmd_acchandle
= cacchandle
;
4604 if (real_len
< cmd_size
)
4607 if (ddi_dma_addr_bind_handle(chandle
, (struct as
*)NULL
,
4608 (caddr_t
)cmd
, cmd_size
,
4609 DDI_DMA_WRITE
| DDI_DMA_CONSISTENT
,
4610 DDI_DMA_DONTWAIT
, NULL
, &ccookie
, &ccount
)
4618 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4619 DDI_DMA_DONTWAIT
, NULL
, &rhandle
) != DDI_SUCCESS
)
4622 privp
->rsp_handle
= rhandle
;
4623 if (ddi_dma_mem_alloc(rhandle
, rsp_size
, &socal_acc_attr
,
4624 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4625 &rsp
, &real_len
, &racchandle
) != DDI_SUCCESS
)
4629 privp
->rsp_acchandle
= racchandle
;
4630 if (real_len
< rsp_size
)
4633 if (ddi_dma_addr_bind_handle(rhandle
, (struct as
*)NULL
,
4635 DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4636 DDI_DMA_DONTWAIT
, NULL
, &rcookie
, &ccount
)
4645 srp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
4646 srp
->sr_soc_hdr
.sh_flags
= SOC_FC_HEADER
;
4648 srp
->sr_soc_hdr
.sh_flags
|= SOC_PORT_B
;
4649 srp
->sr_soc_hdr
.sh_class
= 3;
4650 srp
->sr_soc_hdr
.sh_byte_cnt
= cmd_size
;
4651 srp
->sr_dataseg
[0].fc_base
= (uint32_t)ccookie
.dmac_address
;
4652 srp
->sr_dataseg
[0].fc_count
= cmd_size
;
4653 if (rsp_size
== 0) {
4654 srp
->sr_soc_hdr
.sh_seg_cnt
= 1;
4656 srp
->sr_soc_hdr
.sh_seg_cnt
= 2;
4657 srp
->sr_dataseg
[1].fc_base
= (uint32_t)rcookie
.dmac_address
;
4658 srp
->sr_dataseg
[1].fc_count
= rsp_size
;
4660 srp
->sr_cqhdr
.cq_hdr_count
= 1;
4661 /* this will potentially be overwritten by the calling function */
4662 srp
->sr_cqhdr
.cq_hdr_type
= CQ_TYPE_SIMPLE
;
4664 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4666 /* Fill in the Fabric Channel Header */
4667 fhp
= &srp
->sr_fc_frame_hdr
;
4668 fhp
->r_ctl
= R_CTL_SOLICITED_DATA
;
4669 fhp
->d_id
= socalp
->port_state
[port
].sp_src_id
;
4670 fhp
->s_id
= socalp
->port_state
[port
].sp_src_id
;
4671 fhp
->type
= TYPE_SCSI_FCP
;
4672 fhp
->f_ctl
= F_CTL_SEQ_INITIATIVE
| F_CTL_FIRST_SEQ
| F_CTL_LAST_SEQ
;
4676 fhp
->ox_id
= 0xffff;
4677 fhp
->rx_id
= 0xffff;
4681 socal_packet_free(fcalpkt
);
4683 if (privp
->cmd_handle
) {
4685 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4686 ddi_dma_free_handle(&privp
->cmd_handle
);
4689 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4690 if (privp
->rsp_handle
) {
4692 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4693 ddi_dma_free_handle(&privp
->rsp_handle
);
4696 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4698 kmem_free(privp
, sizeof (*privp
));
4704 socal_els_free(socal_priv_cmd_t
*privp
)
4706 fcal_packet_t
*fcalpkt
;
4709 fcalpkt
= (fcal_packet_t
*)privp
->fapktp
;
4713 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4714 ddi_dma_free_handle(&privp
->cmd_handle
);
4715 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4717 if (privp
->rsp_handle
) {
4718 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4719 ddi_dma_free_handle(&privp
->rsp_handle
);
4722 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4724 kmem_free(privp
, sizeof (*privp
));
4725 if (fcalpkt
!= NULL
)
4726 socal_packet_free(fcalpkt
);
4730 socal_lbf_free(socal_priv_cmd_t
*privp
)
4732 fcal_packet_t
*fcalpkt
;
4735 fcalpkt
= (fcal_packet_t
*)privp
->fapktp
;
4739 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4740 ddi_dma_free_handle(&privp
->cmd_handle
);
4741 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4743 if (privp
->rsp_handle
) {
4744 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4745 ddi_dma_free_handle(&privp
->rsp_handle
);
4749 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4751 kmem_free(privp
, sizeof (*privp
));
4752 if (fcalpkt
!= NULL
)
4753 socal_packet_free(fcalpkt
);
4757 socal_getmap(socal_state_t
*socalp
, uint32_t port
, caddr_t arg
,
4758 uint32_t polled
, int flags
)
4760 ddi_dma_cookie_t dcookie
;
4761 ddi_dma_handle_t dhandle
= NULL
;
4762 ddi_acc_handle_t acchandle
;
4765 fcal_lilp_map_t
*buf
= NULL
;
4766 int retval
, bound
= 0;
4767 socal_port_t
*port_statep
;
4769 port_statep
= &socalp
->port_state
[port
];
4771 if (port_statep
->sp_lilpmap_valid
) {
4773 buf
= &port_statep
->sp_lilpmap
; /* give from cache */
4776 if (ddi_copyout(buf
, (caddr_t
)arg
,
4777 sizeof (struct lilpmap
), flags
) == -1)
4781 return (buf
->lilp_myalpa
);
4784 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4785 DDI_DMA_DONTWAIT
, NULL
, &dhandle
) != DDI_SUCCESS
)
4788 i
= sizeof (struct fcal_lilp_map
);
4790 if (ddi_dma_mem_alloc(dhandle
, i
, &socal_acc_attr
,
4791 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4792 (caddr_t
*)&buf
, &real_len
, &acchandle
) != DDI_SUCCESS
)
4798 if (ddi_dma_addr_bind_handle(dhandle
, (struct as
*)NULL
,
4799 (caddr_t
)buf
, i
, DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4800 DDI_DMA_DONTWAIT
, NULL
, &dcookie
, &ccount
) != DDI_DMA_MAPPED
)
4807 retval
= socal_lilp_map((void *)socalp
, port
,
4808 (uint32_t)dcookie
.dmac_address
, polled
);
4810 (void) ddi_dma_sync(dhandle
, 0, 0, DDI_DMA_SYNC_FORKERNEL
);
4812 if (retval
== FCAL_SUCCESS
) {
4813 bcopy(buf
, &port_statep
->sp_lilpmap
, sizeof (fcal_lilp_map_t
));
4815 mutex_enter(&port_statep
->sp_mtx
);
4816 port_statep
->sp_src_id
= buf
->lilp_myalpa
;
4817 port_statep
->sp_lilpmap_valid
= 1; /* cached */
4818 mutex_exit(&port_statep
->sp_mtx
);
4821 if (ddi_copyout(buf
, (caddr_t
)arg
,
4822 sizeof (struct lilpmap
), flags
) == -1)
4826 retval
= buf
->lilp_myalpa
;
4831 (void) ddi_dma_unbind_handle(dhandle
);
4832 ddi_dma_mem_free(&acchandle
);
4833 ddi_dma_free_handle(&dhandle
);
4839 (void) ddi_dma_unbind_handle(dhandle
);
4840 ddi_dma_free_handle(&dhandle
);
4843 ddi_dma_mem_free(&acchandle
);
4848 socal_wcopy(uint_t
*h_src
, uint_t
*h_dest
, int len
)
4851 for (i
= 0; i
< len
/4; i
++) {
4852 *h_dest
++ = *h_src
++;
4857 socal_flush_overflowq(socal_state_t
*socalp
, int port
, int q_no
)
4860 fcal_packet_t
*fpkt1
, *fpkt2
, *head
= NULL
, *tmp
;
4862 kcq
= &socalp
->request
[q_no
];
4863 mutex_enter(&kcq
->skc_mtx
);
4864 fpkt2
= kcq
->skc_overflowh
;
4866 while (fpkt2
!= NULL
) {
4867 if ((((soc_request_t
*)&fpkt2
->fcal_socal_request
)
4868 ->sr_soc_hdr
.sh_flags
& SOC_PORT_B
) == port
) {
4870 kcq
->skc_overflowh
= fpkt2
->fcal_pkt_next
;
4872 fpkt1
->fcal_pkt_next
= fpkt2
->fcal_pkt_next
;
4873 if (kcq
->skc_overflowt
== fpkt2
)
4874 kcq
->skc_overflowt
= fpkt1
;
4876 tmp
= fpkt2
->fcal_pkt_next
;
4877 fpkt2
->fcal_pkt_next
= head
;
4880 SOCAL_ID_FREE(head
->fcal_socal_request
.
4881 sr_soc_hdr
.sh_request_token
);
4884 fpkt2
= fpkt2
->fcal_pkt_next
;
4887 mutex_exit(&kcq
->skc_mtx
);
4889 while (fpkt2
!= NULL
) {
4890 fpkt2
->fcal_pkt_status
= FCAL_STATUS_ERR_OFFLINE
;
4891 fpkt2
->fcal_cmd_state
|= FCAL_CMD_COMPLETE
;
4892 fpkt2
->fcal_pkt_flags
|= FCFLAG_COMPLETE
;
4893 tmp
= fpkt2
->fcal_pkt_next
;
4894 if (fpkt2
->fcal_pkt_comp
!= NULL
)
4895 (*fpkt2
->fcal_pkt_comp
)(fpkt2
);
4901 socal_deferred_intr(void *arg
)
4903 socal_kcq_t
*kcq
= (socal_kcq_t
*)arg
;
4904 socal_state_t
*socalp
= kcq
->skc_socalp
;
4906 ASSERT((socalp
!= NULL
));
4908 mutex_enter(&kcq
->skc_mtx
);
4910 if ((kcq
->skc_out
!= kcq
->skc_saved_out
) ||
4911 (kcq
->skc_seqno
!= kcq
->skc_saved_seqno
)) {
4912 kcq
->deferred_intr_timeoutid
= 0;
4913 mutex_exit(&kcq
->skc_mtx
);
4917 if (socalp
->socal_on_intr
) {
4918 mutex_exit(&kcq
->skc_mtx
);
4919 kcq
->deferred_intr_timeoutid
= timeout(socal_deferred_intr
,
4920 (caddr_t
)kcq
, drv_usectohz(10000));
4924 kcq
->deferred_intr_timeoutid
= 0;
4925 mutex_exit(&kcq
->skc_mtx
);
4926 socal_intr_solicited(socalp
, 0);
4930 socal_take_core(void *arg
)
4932 socal_state_t
*socalp
= (socal_state_t
*)arg
;
4935 socal_disable(socalp
);
4936 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
4937 mutex_enter(&socalp
->request
[i
].skc_mtx
);
4938 mutex_enter(&socalp
->response
[i
].skc_mtx
);
4940 for (i
= 0; i
< 4; i
++) {
4941 socalp
->socal_rp
->socal_cr
.w
&=
4942 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
4943 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
4944 (void) bcopy((caddr_t
)socalp
->socal_xrp
,
4945 (caddr_t
)&socal_xrambuf
[i
*0x10000], 0x10000);
4947 for (i
= 3; i
>= 0; i
--) {
4948 mutex_exit(&socalp
->request
[i
].skc_mtx
);
4949 mutex_exit(&socalp
->response
[i
].skc_mtx
);
4951 instance
= ddi_get_instance(socalp
->dip
);
4953 "socal take core (socal instance %d)", instance
);
4957 * Preset AL_PA in hardware, if is told.
4960 socal_fix_harda(socal_state_t
*socalp
, int port
)
4962 socal_port_t
*portp
= &socalp
->port_state
[port
];
4963 uint_t
*xrp
= (uint_t
*)socalp
->socal_xrp
;
4964 uint_t accum
, harda
;
4966 harda
= portp
->sp_hard_alpa
;
4967 accum
= xrp
[SOCAL_XRAM_PORTA_HRDA
/4];
4969 accum
&= 0x00FFFFFF;
4970 accum
|= ((harda
& 0xFF) << 24);
4972 accum
&= 0xFF00FFFF;
4973 accum
|= ((harda
& 0xFF) << 16);
4975 xrp
[SOCAL_XRAM_PORTA_HRDA
/4] = accum
;
4979 * Target-Mode attach function
4982 socal_sftm_attach(dev_t dev
, int loop_id
)
4984 int instance
= getminor(dev
) / 2;
4985 int port
= getminor(dev
) % 2;
4988 socal_state_t
*socalp
;
4991 * If the device is not a "socal" device, return
4993 if ((name
= ddi_major_to_name(getmajor(dev
))) == NULL
||
4994 strcmp(name
, "socal") != 0)
4998 * If no soft state structure, return
5000 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
5005 * If the port is already attached, return
5007 if (socalp
->port_state
[port
].sp_status
& PORT_CHILD_INIT
)
5010 if (loop_id
< 0 || loop_id
> 126)
5013 /* if this instance is detaching, don't attach */
5014 mutex_enter(&socalp
->board_mtx
);
5015 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
5016 if (socalp
->socal_busy
< 0) {
5017 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
5018 mutex_exit(&socalp
->board_mtx
);
5021 socalp
->socal_busy
++;
5022 socalp
->port_state
[port
].sp_status
|= PORT_CHILD_INIT
;
5023 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
5024 mutex_exit(&socalp
->board_mtx
);
5027 * Since we keep the Hard Loop-id in two config files, warn the
5028 * user if they don't match.
5030 hard_alpa
= socal_switch_to_alpa
[loop_id
];
5031 if (hard_alpa
!= socalp
->port_state
[port
].sp_hard_alpa
) {
5032 socalp
->port_state
[port
].sp_hard_alpa
= hard_alpa
;
5033 cmn_err(CE_WARN
, "socal%d: Hard Loop-id mismatch - "
5038 return (socalp
->port_state
[port
].sp_transport
);
5043 * Target-Mode detach function
5046 socal_sftm_detach(socal_state_t
*socalp
, int port
)
5048 mutex_enter(&socalp
->board_mtx
);
5049 socalp
->socal_busy
--;
5050 socalp
->port_state
[port
].sp_status
&= ~PORT_CHILD_INIT
;
5051 mutex_exit(&socalp
->board_mtx
);