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
420 static char socal_initmsg
[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
427 DEBUGF(4, (CE_CONT
, socal_initmsg
));
429 /* Allocate soft state. */
430 stat
= ddi_soft_state_init(&socal_soft_state_p
,
431 sizeof (socal_state_t
), SOCAL_INIT_ITEMS
);
435 /* Install the module */
436 stat
= mod_install(&modlinkage
);
438 ddi_soft_state_fini(&socal_soft_state_p
);
440 DEBUGF(4, (CE_CONT
, "socal: _init: return=%d\n", stat
));
449 if ((stat
= mod_remove(&modlinkage
)) != 0)
452 DEBUGF(4, (CE_CONT
, "socal: _fini: \n"));
454 ddi_soft_state_fini(&socal_soft_state_p
);
456 DEBUGF(4, (CE_CONT
, "socal: _fini: return=%d\n", stat
));
461 _info(struct modinfo
*modinfop
)
463 return (mod_info(&modlinkage
, modinfop
));
468 socal_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
471 socal_state_t
*socalp
;
472 struct ether_addr ourmacaddr
;
473 socal_port_t
*porta
, *portb
;
474 char buf
[MAXPATHLEN
];
485 instance
= ddi_get_instance(dip
);
487 DEBUGF(4, (CE_CONT
, "socal%d entering attach: cmd=%x\n", instance
,
490 if (cmd
== DDI_RESUME
) {
491 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
492 return (DDI_FAILURE
);
494 if (!socalp
->socal_shutdown
) {
495 /* our work is already done */
496 return (DDI_SUCCESS
);
498 if (socal_start(socalp
) != FCAL_SUCCESS
) {
499 return (DDI_FAILURE
);
501 DEBUGF(4, (CE_CONT
, "socal%d resumed\n", instance
));
502 return (DDI_SUCCESS
);
505 if (cmd
!= DDI_ATTACH
) {
506 return (DDI_FAILURE
);
509 if (ddi_dev_is_sid(dip
) != DDI_SUCCESS
) {
510 cmn_err(CE_WARN
, "socal%d probe: Not self-identifying",
512 return (DDI_FAILURE
);
515 /* If we are in a slave-slot, then we can't be used. */
516 if (ddi_slaveonly(dip
) == DDI_SUCCESS
) {
518 "socal%d attach failed: device in slave-only slot",
520 return (DDI_FAILURE
);
523 if (ddi_intr_hilevel(dip
, 0)) {
525 * Interrupt number '0' is a high-level interrupt.
526 * At this point you either add a special interrupt
527 * handler that triggers a soft interrupt at a lower level,
528 * or - more simply and appropriately here - you just
532 "socal%d attach failed: hilevel interrupt unsupported",
534 return (DDI_FAILURE
);
537 /* Allocate soft state. */
538 if (ddi_soft_state_zalloc(socal_soft_state_p
, instance
)
540 cmn_err(CE_WARN
, "socal%d attach failed: alloc soft state",
542 return (DDI_FAILURE
);
544 DEBUGF(4, (CE_CONT
, "socal%d attach: allocated soft state\n",
548 * Initialize the state structure.
550 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
551 if (socalp
== (socal_state_t
*)NULL
) {
552 cmn_err(CE_WARN
, "socal%d attach failed: bad soft state",
554 return (DDI_FAILURE
);
556 DEBUGF(4, (CE_CONT
, "socal%d: attach: soc soft state ptr=0x%p\n",
560 socallim
= &default_socallim
;
561 porta
= &socalp
->port_state
[0];
562 portb
= &socalp
->port_state
[1];
564 /* Get the full path name for displaying error messages */
565 cptr
= ddi_pathname(dip
, buf
);
566 (void) strcpy(socalp
->socal_name
, cptr
);
568 porta
->sp_unsol_cb
= NULL
;
569 portb
->sp_unsol_cb
= NULL
;
572 porta
->sp_board
= socalp
;
573 portb
->sp_board
= socalp
;
575 porta
->sp_lilpmap_valid
= 0;
576 portb
->sp_lilpmap_valid
= 0;
579 * If an hard loop-id property is present, then the port is going
580 * to be used in target-mode so set the target-mode flag.
582 loop_id
= ddi_getprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
583 "port0-loop-id", 127);
584 if (loop_id
>= 0 && loop_id
<= 126) {
585 porta
->sp_status
|= PORT_TARGET_MODE
;
586 porta
->sp_hard_alpa
= socal_switch_to_alpa
[loop_id
];
587 } else porta
->sp_hard_alpa
= 0xfe;
589 loop_id
= ddi_getprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
590 "port1-loop-id", 127);
591 if (loop_id
>= 0 && loop_id
<= 126) {
592 portb
->sp_status
|= PORT_TARGET_MODE
;
593 portb
->sp_hard_alpa
= socal_switch_to_alpa
[loop_id
];
594 } else portb
->sp_hard_alpa
= 0xfe;
596 /* Get out Node wwn and calculate port wwns */
597 rval
= ddi_prop_op(DDI_DEV_T_ANY
, dip
,
598 PROP_LEN_AND_VAL_ALLOC
, DDI_PROP_DONTPASS
|
599 DDI_PROP_CANSLEEP
, "wwn", (caddr_t
)&wwn
, &i
);
601 if ((rval
!= DDI_PROP_SUCCESS
) || (i
< FC_WWN_SIZE
) ||
602 (bcmp(wwn
, "00000000", FC_WWN_SIZE
) == 0)) {
603 (void) localetheraddr(NULL
, &ourmacaddr
);
605 bcopy((caddr_t
)&ourmacaddr
, (caddr_t
)&s
, sizeof (short));
606 socalp
->socal_n_wwn
.w
.wwn_hi
= s
;
607 bcopy((caddr_t
)&ourmacaddr
+2,
608 (caddr_t
)&socalp
->socal_n_wwn
.w
.wwn_lo
,
610 socalp
->socal_n_wwn
.w
.naa_id
= NAA_ID_IEEE
;
611 socalp
->socal_n_wwn
.w
.nport_id
= 0;
613 bcopy((caddr_t
)wwn
, (caddr_t
)&socalp
->socal_n_wwn
, FC_WWN_SIZE
);
616 if (rval
== DDI_SUCCESS
)
617 kmem_free((void *)wwn
, i
);
619 for (i
= 0; i
< FC_WWN_SIZE
; i
++) {
620 (void) sprintf(&socalp
->socal_stats
.node_wwn
[i
<< 1],
621 "%02x", socalp
->socal_n_wwn
.raw_wwn
[i
]);
623 DEBUGF(4, (CE_CONT
, "socal%d attach: node wwn: %s\n",
624 instance
, socalp
->socal_stats
.node_wwn
));
626 bcopy((caddr_t
)&socalp
->socal_n_wwn
, (caddr_t
)&porta
->sp_p_wwn
,
628 bcopy((caddr_t
)&socalp
->socal_n_wwn
, (caddr_t
)&portb
->sp_p_wwn
,
630 porta
->sp_p_wwn
.w
.naa_id
= NAA_ID_IEEE_EXTENDED
;
631 portb
->sp_p_wwn
.w
.naa_id
= NAA_ID_IEEE_EXTENDED
;
632 porta
->sp_p_wwn
.w
.nport_id
= instance
*2;
633 portb
->sp_p_wwn
.w
.nport_id
= instance
*2+1;
635 for (i
= 0; i
< FC_WWN_SIZE
; i
++) {
636 (void) sprintf(&socalp
->socal_stats
.port_wwn
[0][i
<< 1],
637 "%02x", porta
->sp_p_wwn
.raw_wwn
[i
]);
638 (void) sprintf(&socalp
->socal_stats
.port_wwn
[1][i
<< 1],
639 "%02x", portb
->sp_p_wwn
.raw_wwn
[i
]);
641 DEBUGF(4, (CE_CONT
, "socal%d attach: porta wwn: %s\n",
642 instance
, socalp
->socal_stats
.port_wwn
[0]));
643 DEBUGF(4, (CE_CONT
, "socal%d attach: portb wwn: %s\n",
644 instance
, socalp
->socal_stats
.port_wwn
[1]));
646 if ((porta
->sp_transport
= (fcal_transport_t
*)
647 kmem_zalloc(sizeof (fcal_transport_t
), KM_SLEEP
)) == NULL
) {
648 socal_disp_err(socalp
, CE_WARN
, "attach.4011",
649 "attach failed: unable to alloc xport struct");
653 if ((portb
->sp_transport
= (fcal_transport_t
*)
654 kmem_zalloc(sizeof (fcal_transport_t
), KM_SLEEP
)) == NULL
) {
655 socal_disp_err(socalp
, CE_WARN
, "attach.4012",
656 "attach failed: unable to alloc xport struct");
659 DEBUGF(4, (CE_CONT
, "socal%d attach: allocated transport structs\n",
663 * Map the external ram and registers for SOC+.
664 * Note: Soc+ sbus host adapter provides 3 register definition
665 * but on-board Soc+'s may have only one register definition.
667 if ((ddi_dev_nregs(dip
, &i
) == DDI_SUCCESS
) && (i
== 1)) {
669 if (ddi_map_regs(dip
, 0, &socalp
->socal_xrp
, 0, 0)
671 socalp
->socal_xrp
= NULL
;
672 socal_disp_err(socalp
, CE_WARN
, "attach.4020",
673 "attach failed: unable to map XRAM");
677 socalp
->socal_rp
= (socal_reg_t
*)(socalp
->socal_xrp
+
681 if (ddi_map_regs(dip
, 0, &socalp
->socal_eeprom
, 0, 0) !=
683 socalp
->socal_eeprom
= NULL
;
684 socal_disp_err(socalp
, CE_WARN
, "attach.4010",
685 "attach failed: unable to map eeprom");
688 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped eeprom 0x%p\n",
689 instance
, socalp
->socal_eeprom
));
691 if (ddi_map_regs(dip
, 1, &socalp
->socal_xrp
, 0, 0) !=
693 socalp
->socal_xrp
= NULL
;
694 socal_disp_err(socalp
, CE_WARN
, "attach.4020",
695 "attach failed: unable to map XRAM");
698 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped xram 0x%p\n",
699 instance
, socalp
->socal_xrp
));
701 if (ddi_map_regs(dip
, 2, (caddr_t
*)&socalp
->socal_rp
, 0, 0) !=
703 socalp
->socal_rp
= NULL
;
704 socal_disp_err(socalp
, CE_WARN
, "attach.4030",
705 "attach failed: unable to map registers");
708 DEBUGF(4, (CE_CONT
, "socal%d attach: mapped regs 0x%p\n",
709 instance
, socalp
->socal_rp
));
712 * Check to see we really have a SOC+ Host Adapter card installed
714 if (ddi_peek32(dip
, (int32_t *)&socalp
->socal_rp
->socal_csr
.w
,
715 (int32_t *)NULL
) != DDI_SUCCESS
) {
716 socal_disp_err(socalp
, CE_WARN
, "attach.4040",
717 "attach failed: unable to access status register");
720 /* now that we have our registers mapped make sure soc+ reset */
721 socal_disable(socalp
);
723 /* try defacing a spot in XRAM */
724 if (ddi_poke32(dip
, (int32_t *)(socalp
->socal_xrp
+ SOCAL_XRAM_UCODE
),
725 0xdefaced) != DDI_SUCCESS
) {
726 socal_disp_err(socalp
, CE_WARN
, "attach.4050",
727 "attach failed: unable to write host adapter XRAM");
731 /* see if it stayed defaced */
732 if (ddi_peek32(dip
, (int32_t *)(socalp
->socal_xrp
+ SOCAL_XRAM_UCODE
),
735 socal_disp_err(socalp
, CE_WARN
, "attach.4051",
736 "attach failed: unable to access host adapter XRAM");
741 for (i
= 0; i
< 4; i
++) {
742 socalp
->socal_rp
->socal_cr
.w
&=
743 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
744 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
745 cptr
= (char *)(socal_xrambuf
+ (i
*0x10000));
746 bcopy((caddr_t
)socalp
->socal_xrp
, (caddr_t
)cptr
, 0x10000);
748 socalp
->socal_rp
->socal_cr
.w
&= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
751 DEBUGF(4, (CE_CONT
, "socal%d attach: read xram\n", instance
));
753 if (y
!= 0xdefaced) {
754 socal_disp_err(socalp
, CE_WARN
, "attach.4052",
755 "attach failed: read/write mismatch in XRAM");
759 /* Point to the SOC XRAM CQ Descriptor locations. */
760 socalp
->xram_reqp
= (soc_cq_t
*)(socalp
->socal_xrp
+
761 SOCAL_XRAM_REQ_DESC
);
762 socalp
->xram_rspp
= (soc_cq_t
*)(socalp
->socal_xrp
+
763 SOCAL_XRAM_RSP_DESC
);
765 if ((socalp
->socal_ksp
= kstat_create("socal", instance
, "statistics",
766 "controller", KSTAT_TYPE_RAW
, sizeof (struct socal_stats
),
767 KSTAT_FLAG_VIRTUAL
)) == NULL
) {
768 socal_disp_err(socalp
, CE_WARN
, "attach.4053",
769 "unable to create kstats");
771 socalp
->socal_stats
.version
= 2;
772 (void) sprintf(socalp
->socal_stats
.drvr_name
,
773 "%s: %s", SOCAL_NAME
, socal_version
);
774 socalp
->socal_stats
.pstats
[0].port
= 0;
775 socalp
->socal_stats
.pstats
[1].port
= 1;
776 socalp
->socal_ksp
->ks_data
= (void *)&socalp
->socal_stats
;
777 kstat_install(socalp
->socal_ksp
);
781 * Install a dummy interrupt routine.
783 if (ddi_add_intr(dip
,
788 (caddr_t
)socalp
) != DDI_SUCCESS
) {
789 socal_disp_err(socalp
, CE_WARN
, "attach.4060",
790 "attach failed: unable to install interrupt handler");
794 ddi_set_driver_private(dip
, socalp
);
796 /* initialize the interrupt mutex */
797 mutex_init(&socalp
->k_imr_mtx
, NULL
, MUTEX_DRIVER
,
798 (void *)socalp
->iblkc
);
800 mutex_init(&socalp
->board_mtx
, NULL
, MUTEX_DRIVER
,
801 (void *)socalp
->iblkc
);
802 mutex_init(&socalp
->ioctl_mtx
, NULL
, MUTEX_DRIVER
,
803 (void *)socalp
->iblkc
);
805 /* initialize the abort mutex */
806 mutex_init(&socalp
->abort_mtx
, NULL
, MUTEX_DRIVER
,
807 (void *)socalp
->iblkc
);
809 cv_init(&socalp
->board_cv
, NULL
, CV_DRIVER
, NULL
);
811 "socal%d: attach: inited imr mutex, board mutex, board cv\n",
814 /* init the port mutexes */
815 mutex_init(&porta
->sp_mtx
, NULL
, MUTEX_DRIVER
, socalp
->iblkc
);
816 cv_init(&porta
->sp_cv
, NULL
, CV_DRIVER
, NULL
);
817 mutex_init(&portb
->sp_mtx
, NULL
, MUTEX_DRIVER
, socalp
->iblkc
);
818 cv_init(&portb
->sp_cv
, NULL
, CV_DRIVER
, NULL
);
819 DEBUGF(4, (CE_CONT
, "socal%d: attach: inited port mutexes and cvs\n",
822 /* get local copy of service params */
823 socal_wcopy((uint_t
*)socalp
->socal_xrp
+ SOCAL_XRAM_SERV_PARAMS
,
824 (uint_t
*)socalp
->socal_service_params
, SOCAL_SVC_LENGTH
);
825 DEBUGF(4, (CE_CONT
, "socal%d: attach: got service params\n", instance
));
827 * Initailize the FCAL transport interface.
829 socal_init_transport_interface(socalp
);
830 DEBUGF(4, (CE_CONT
, "socal%d: attach: initalized transport interface\n",
834 * Allocate request and response queues and init their mutexs.
836 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
837 if (socal_cqalloc_init(socalp
, i
) != FCAL_SUCCESS
) {
841 DEBUGF(4, (CE_CONT
, "socal%d: attach: allocated cqs\n", instance
));
844 * Adjust the burst size we'll use.
846 burstsize
= ddi_dma_burstsizes(socalp
->request
[0].skc_dhandle
);
847 DEBUGF(4, (CE_CONT
, "socal%d: attach: burstsize = 0x%x\n",
848 instance
, burstsize
));
849 j
= burstsize
& BURSTSIZE_MASK
;
850 for (i
= 0; socal_burst32_table
[i
] != SOCAL_CR_BURST_64
; i
++)
851 if (!(j
>>= 1)) break;
853 socalp
->socal_cfg
= (socalp
->socal_cfg
& ~SOCAL_CR_SBUS_BURST_SIZE_MASK
)
854 | socal_burst32_table
[i
];
856 if (socal_64bitsbus
) {
857 if (ddi_dma_set_sbus64(socalp
->request
[0].skc_dhandle
,
858 socal_dma_attr
.dma_attr_burstsizes
| BURST128
) ==
860 DEBUGF(4, (CE_CONT
, "socal%d: enabled 64 bit sbus\n",
862 socalp
->socal_cfg
|= SOCAL_CR_SBUS_ENHANCED
;
863 burstsize
= ddi_dma_burstsizes(socalp
->request
[0].
865 DEBUGF(4, (CE_CONT
, "socal%d: attach: 64bit burstsize = 0x%x\n",
866 instance
, burstsize
));
867 j
= burstsize
& BURSTSIZE_MASK
;
868 for (i
= 0; socal_burst64_table
[i
] !=
869 (SOCAL_CR_BURST_128
<< 8); i
++)
873 socalp
->socal_cfg
= (socalp
->socal_cfg
&
874 ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK
) |
875 socal_burst64_table
[i
];
879 ddi_remove_intr(dip
, 0, socalp
->iblkc
);
880 socalp
->iblkc
= NULL
;
882 * Install the interrupt routine.
884 if (ddi_add_intr(dip
,
889 (caddr_t
)socalp
) != DDI_SUCCESS
) {
890 socal_disp_err(socalp
, CE_WARN
, "attach.4060",
891 "attach failed: unable to install interrupt handler");
895 DEBUGF(4, (CE_CONT
, "socal%d: attach: set config reg %x\n",
896 instance
, socalp
->socal_cfg
));
898 if (ddi_create_minor_node(dip
, SOCAL_PORTA_NAME
, S_IFCHR
,
899 instance
*N_SOCAL_NPORTS
, SOCAL_NT_PORT
, 0) != DDI_SUCCESS
)
901 if (ddi_create_minor_node(dip
, SOCAL_PORTB_NAME
, S_IFCHR
,
902 instance
*N_SOCAL_NPORTS
+1, SOCAL_NT_PORT
, 0) != DDI_SUCCESS
)
905 if (socal_start(socalp
) != FCAL_SUCCESS
)
907 DEBUGF(4, (CE_CONT
, "socal%d: attach: soc+ started\n", instance
));
911 DEBUGF(2, (CE_CONT
, "socal%d: attach O.K.\n\n", instance
));
913 return (DDI_SUCCESS
);
916 DEBUGF(4, (CE_CONT
, "socal%d: attach: DDI_FAILURE\n", instance
));
918 /* Make sure soc reset */
919 socal_disable(socalp
);
921 /* let detach do the dirty work */
922 (void) socal_dodetach(dip
);
924 return (DDI_FAILURE
);
928 socal_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
931 socal_state_t
*socalp
;
938 DEBUGF(4, (CE_CONT
, "socal: suspend called\n"));
940 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
941 return (DDI_FAILURE
);
944 * If any of the ports are in target-mode, don't suspend
946 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
947 if (socalp
->port_state
[i
].sp_status
& PORT_TARGET_MODE
)
948 return (DDI_FAILURE
);
951 /* do not restart socal after reset */
952 socal_force_reset((void *)socalp
, 0, DONT_RESET_PORT
);
954 return (DDI_SUCCESS
);
957 DEBUGF(4, (CE_CONT
, "socal: detach called\n"));
958 resp
= socal_dodetach(dip
);
959 if (resp
== DDI_SUCCESS
)
960 ddi_set_driver_private(dip
, NULL
);
964 return (DDI_FAILURE
);
969 socal_dodetach(dev_info_t
*dip
)
972 int instance
= ddi_get_instance(dip
);
974 socal_state_t
*socalp
;
976 socal_unsol_cb_t
*cb
, *cbn
= NULL
;
978 /* Get the soft state struct. */
979 if ((socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
)) == 0) {
980 return (DDI_FAILURE
);
984 * If somebody is still attached to us from above fail
987 mutex_enter(&socalp
->board_mtx
);
988 if (socalp
->socal_busy
> 0) {
989 mutex_exit(&socalp
->board_mtx
);
990 return (DDI_FAILURE
);
992 /* mark socal_busy = -1 to disallow sftm attach */
993 socalp
->socal_busy
= -1;
994 mutex_exit(&socalp
->board_mtx
);
996 /* Make sure soc+ reset */
997 mutex_enter(&socalp
->k_imr_mtx
);
998 socal_disable(socalp
);
999 mutex_exit(&socalp
->k_imr_mtx
);
1001 /* remove soc+ interrupt */
1002 if (socalp
->iblkc
!= NULL
) {
1003 ddi_remove_intr(dip
, (uint_t
)0, socalp
->iblkc
);
1005 "socal%d: detach: Removed SOC+ interrupt from ddi\n",
1009 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
1010 portp
= &socalp
->port_state
[i
];
1011 mutex_destroy(&portp
->sp_mtx
);
1012 cv_destroy(&portp
->sp_cv
);
1013 mutex_destroy(&portp
->sp_transport
->fcal_mtx
);
1014 cv_destroy(&portp
->sp_transport
->fcal_cv
);
1015 kmem_free((void *)portp
->sp_transport
,
1016 sizeof (fcal_transport_t
));
1017 for (cb
= portp
->sp_unsol_cb
; cb
!= (socal_unsol_cb_t
*)NULL
;
1020 kmem_free((void *)cb
, sizeof (socal_unsol_cb_t
));
1022 portp
->sp_unsol_cb
= (socal_unsol_cb_t
*)NULL
;
1026 * Free request queues, if allocated
1028 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1029 /* Free the queues and destroy their mutexes. */
1030 mutex_destroy(&socalp
->request
[i
].skc_mtx
);
1031 mutex_destroy(&socalp
->response
[i
].skc_mtx
);
1032 cv_destroy(&socalp
->request
[i
].skc_cv
);
1033 cv_destroy(&socalp
->response
[i
].skc_cv
);
1035 if (socalp
->request
[i
].skc_dhandle
) {
1036 (void) ddi_dma_unbind_handle(socalp
->
1037 request
[i
].skc_dhandle
);
1038 ddi_dma_free_handle(&socalp
->request
[i
].skc_dhandle
);
1040 if (socalp
->request
[i
].skc_cq_raw
) {
1041 ddi_dma_mem_free(&socalp
->request
[i
].skc_acchandle
);
1042 socalp
->request
[i
].skc_cq_raw
= NULL
;
1043 socalp
->request
[i
].skc_cq
= NULL
;
1045 if (socalp
->response
[i
].skc_dhandle
) {
1046 (void) ddi_dma_unbind_handle(socalp
->
1047 response
[i
].skc_dhandle
);
1048 ddi_dma_free_handle(&socalp
->response
[i
].skc_dhandle
);
1050 if (socalp
->response
[i
].skc_cq_raw
) {
1051 ddi_dma_mem_free(&socalp
->response
[i
].skc_acchandle
);
1052 socalp
->response
[i
].skc_cq_raw
= NULL
;
1053 socalp
->response
[i
].skc_cq
= NULL
;
1055 if (socalp
->request
[i
].deferred_intr_timeoutid
) {
1056 (void) untimeout(socalp
->
1057 request
[i
].deferred_intr_timeoutid
);
1059 if (socalp
->response
[i
].deferred_intr_timeoutid
) {
1060 (void) untimeout(socalp
->
1061 response
[i
].deferred_intr_timeoutid
);
1065 mutex_destroy(&socalp
->abort_mtx
);
1066 mutex_destroy(&socalp
->board_mtx
);
1067 mutex_destroy(&socalp
->ioctl_mtx
);
1068 cv_destroy(&socalp
->board_cv
);
1071 * Free soc data buffer pool
1073 if (socalp
->pool_dhandle
) {
1074 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
1075 ddi_dma_free_handle(&socalp
->pool_dhandle
);
1078 ddi_dma_mem_free(&socalp
->pool_acchandle
);
1081 /* release register maps */
1083 if (socalp
->socal_eeprom
!= NULL
) {
1084 ddi_unmap_regs(dip
, 0, &socalp
->socal_eeprom
, 0, 0);
1088 if (socalp
->socal_xrp
!= NULL
) {
1089 ddi_unmap_regs(dip
, 1, &socalp
->socal_xrp
, 0, 0);
1092 /* Unmap registers */
1093 if (socalp
->socal_rp
!= NULL
) {
1094 ddi_unmap_regs(dip
, 2, (caddr_t
*)&socalp
->socal_rp
, 0, 0);
1097 if (socalp
->socal_ksp
!= NULL
)
1098 kstat_delete(socalp
->socal_ksp
);
1100 mutex_destroy(&socalp
->k_imr_mtx
);
1102 ddi_remove_minor_node(dip
, NULL
);
1104 ddi_soft_state_free(socal_soft_state_p
, instance
);
1106 return (DDI_SUCCESS
);
1111 socal_bus_ctl(dev_info_t
*dip
, dev_info_t
*rip
, ddi_ctl_enum_t op
,
1118 case DDI_CTLOPS_REPORTDEV
:
1119 port
= ddi_getprop(DDI_DEV_T_ANY
, rip
, DDI_PROP_DONTPASS
,
1120 SOCAL_PORT_NO_PROP
, -1);
1121 if ((port
< 0) || (port
> 1)) {
1122 port
= ddi_getprop(DDI_DEV_T_ANY
, rip
,
1123 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1125 /* log text identifying this driver (d) & its child (r) */
1126 cmn_err(CE_CONT
, "?%s%d at %s%d: socal_port %d\n",
1127 ddi_driver_name(rip
), ddi_get_instance(rip
),
1128 ddi_driver_name(dip
), ddi_get_instance(dip
),
1132 case DDI_CTLOPS_INITCHILD
: {
1133 dev_info_t
*child_dip
= (dev_info_t
*)a
;
1134 char name
[MAXNAMELEN
];
1135 socal_state_t
*socalp
;
1137 if ((socalp
= ddi_get_driver_private(dip
)) == NULL
)
1138 return (DDI_FAILURE
);
1140 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1141 DDI_PROP_DONTPASS
, SOCAL_PORT_NO_PROP
, -1);
1143 if ((port
< 0) || (port
> 1)) {
1144 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1145 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1146 if ((port
< 0) || (port
> 1)) {
1147 return (DDI_NOT_WELL_FORMED
);
1150 mutex_enter(&socalp
->board_mtx
);
1151 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
1152 if (socalp
->port_state
[port
].sp_status
&
1153 (PORT_CHILD_INIT
| PORT_TARGET_MODE
)) {
1154 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1155 mutex_exit(&socalp
->board_mtx
);
1156 return (DDI_FAILURE
);
1158 socalp
->socal_busy
++;
1159 socalp
->port_state
[port
].sp_status
|= PORT_CHILD_INIT
;
1160 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1161 mutex_exit(&socalp
->board_mtx
);
1162 ddi_set_parent_data(child_dip
,
1163 socalp
->port_state
[port
].sp_transport
);
1164 (void) sprintf((char *)name
, "%x,0", port
);
1165 ddi_set_name_addr(child_dip
, name
);
1169 case DDI_CTLOPS_UNINITCHILD
: {
1170 dev_info_t
*child_dip
= (dev_info_t
*)a
;
1171 socal_state_t
*socalp
;
1173 socalp
= ddi_get_driver_private(dip
);
1174 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1175 DDI_PROP_DONTPASS
, SOCAL_PORT_NO_PROP
, -1);
1177 if ((port
< 0) || (port
> 1)) {
1178 port
= ddi_getprop(DDI_DEV_T_ANY
, child_dip
,
1179 DDI_PROP_DONTPASS
, SOCAL_ALT_PORT_NO_PROP
, -1);
1180 if ((port
< 0) || (port
> 1)) {
1181 return (DDI_NOT_WELL_FORMED
);
1185 ddi_set_parent_data(child_dip
, NULL
);
1186 (void) ddi_set_name_addr(child_dip
, NULL
);
1187 mutex_enter(&socalp
->board_mtx
);
1188 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
1189 socalp
->socal_busy
--;
1190 socalp
->port_state
[port
].sp_status
&= ~PORT_CHILD_INIT
;
1191 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
1192 mutex_exit(&socalp
->board_mtx
);
1197 case DDI_CTLOPS_IOMIN
: {
1201 val
= maxbit(val
, socallim
->dlim_minxfer
);
1203 * The 'arg' value of nonzero indicates 'streaming' mode.
1204 * If in streaming mode, pick the largest of our burstsizes
1205 * available and say that that is our minimum value (modulo
1208 if ((int)(uintptr_t)a
) {
1210 1<<(ddi_fls(socallim
->dlim_burstsizes
)-1));
1213 1<<(ddi_ffs(socallim
->dlim_burstsizes
)-1));
1217 return (ddi_ctlops(dip
, rip
, op
, a
, v
));
1221 * These ops are not available on this nexus.
1224 case DDI_CTLOPS_DMAPMAPC
:
1225 case DDI_CTLOPS_REGSIZE
:
1226 case DDI_CTLOPS_NREGS
:
1227 case DDI_CTLOPS_AFFINITY
:
1228 case DDI_CTLOPS_SIDDEV
:
1229 case DDI_CTLOPS_POKE
:
1230 case DDI_CTLOPS_PEEK
:
1231 return (DDI_FAILURE
);
1233 case DDI_CTLOPS_SLAVEONLY
:
1234 case DDI_CTLOPS_REPORTINT
:
1237 * Remaining requests get passed up to our parent
1239 DEBUGF(2, (CE_CONT
, "%s%d: op (%d) from %s%d\n",
1240 ddi_get_name(dip
), ddi_get_instance(dip
),
1241 op
, ddi_get_name(rip
), ddi_get_instance(rip
)));
1242 return (ddi_ctlops(dip
, rip
, op
, a
, v
));
1245 return (DDI_SUCCESS
);
1252 * socal_getinfo() - Given the device number, return the devinfo
1253 * pointer or the instance number. Note: this routine must be
1254 * successful on DDI_INFO_DEVT2INSTANCE even before attach.
1257 socal_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
,
1261 socal_state_t
*socalp
;
1263 instance
= getminor((dev_t
)arg
) / 2;
1266 case DDI_INFO_DEVT2DEVINFO
:
1267 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
1269 *result
= socalp
->dip
;
1274 case DDI_INFO_DEVT2INSTANCE
:
1275 *result
= (void *)(uintptr_t)instance
;
1279 return (DDI_FAILURE
);
1282 return (DDI_SUCCESS
);
1287 socal_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
1289 int instance
= getminor(*devp
)/2;
1290 socal_state_t
*socalp
=
1291 ddi_get_soft_state(socal_soft_state_p
, instance
);
1292 socal_port_t
*port_statep
;
1298 port
= getminor(*devp
)%2;
1299 port_statep
= &socalp
->port_state
[port
];
1301 mutex_enter(&port_statep
->sp_mtx
);
1302 port_statep
->sp_status
|= PORT_OPEN
;
1303 mutex_exit(&port_statep
->sp_mtx
);
1305 "socal%d: open of port %d\n", instance
, port
));
1311 socal_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred_p
)
1313 int instance
= getminor(dev
)/2;
1314 socal_state_t
*socalp
=
1315 ddi_get_soft_state(socal_soft_state_p
, instance
);
1316 socal_port_t
*port_statep
;
1319 port
= getminor(dev
)%2;
1320 port_statep
= &socalp
->port_state
[port
];
1322 mutex_enter(&port_statep
->sp_mtx
);
1323 port_statep
->sp_status
&= ~PORT_OPEN
;
1324 mutex_exit(&port_statep
->sp_mtx
);
1326 "socal%d: clsoe of port %d\n", instance
, port
));
1332 socal_ioctl(dev_t dev
,
1333 int cmd
, intptr_t arg
, int mode
, cred_t
*cred_p
, int *rval_p
)
1335 int instance
= getminor(dev
)/2;
1336 socal_state_t
*socalp
=
1337 ddi_get_soft_state(socal_soft_state_p
, instance
);
1339 socal_port_t
*port_statep
;
1343 int retval
= FCAL_SUCCESS
;
1344 la_els_adisc_t
*adisc_pl
;
1345 la_els_rls_reply_t
*rls_pl
;
1347 char *buffer
, tmp
[10];
1348 struct socal_fm_version ver
;
1349 #ifdef _MULTI_DATAMODEL
1350 struct socal_fm_version32
{
1351 uint_t fcode_ver_len
;
1352 uint_t mcode_ver_len
;
1353 uint_t prom_ver_len
;
1354 caddr32_t fcode_ver
;
1355 caddr32_t mcode_ver
;
1368 DEBUGF(4, (CE_CONT
, "socal%d ioctl: got command %x\n", instance
, cmd
));
1369 port
= getminor(dev
)%2;
1372 case FCIO_FCODE_MCODE_VERSION
:
1373 #ifdef _MULTI_DATAMODEL
1374 switch (ddi_model_convert_from(mode
& FMODELS
)) {
1375 case DDI_MODEL_ILP32
:
1377 if (ddi_copyin((caddr_t
)arg
,
1378 (caddr_t
)&ver32
, sizeof (ver32
),
1382 ver32
.fcode_ver_len
;
1384 ver32
.mcode_ver_len
;
1388 (caddr_t
)(uintptr_t)ver32
.fcode_ver
;
1390 (caddr_t
)(uintptr_t)ver32
.mcode_ver
;
1392 (caddr_t
)(uintptr_t)ver32
.prom_ver
;
1394 case DDI_MODEL_NONE
:
1395 if (ddi_copyin((caddr_t
)arg
,
1396 (caddr_t
)&ver
, sizeof (ver
),
1400 #else /* _MULTI_DATAMODEL */
1401 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ver
,
1402 sizeof (ver
), mode
) == -1)
1404 #endif /* _MULTI_DATAMODEL */
1406 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
1407 PROP_LEN_AND_VAL_ALLOC
, DDI_PROP_DONTPASS
|
1408 DDI_PROP_CANSLEEP
, "version", (caddr_t
)&buffer
,
1409 &i
) != DDI_PROP_SUCCESS
)
1411 if (i
< ver
.fcode_ver_len
)
1412 ver
.fcode_ver_len
= i
;
1413 if (ddi_copyout((caddr_t
)buffer
,
1414 (caddr_t
)ver
.fcode_ver
, ver
.fcode_ver_len
,
1416 kmem_free((caddr_t
)buffer
, i
);
1419 kmem_free((caddr_t
)buffer
, i
);
1420 if (socalp
->socal_eeprom
) {
1421 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1423 &socalp
->request
[i
].skc_mtx
);
1425 &socalp
->response
[i
].skc_mtx
);
1427 i
= socalp
->socal_rp
->socal_cr
.w
;
1428 socalp
->socal_rp
->socal_cr
.w
&=
1429 ~SOCAL_CR_EEPROM_BANK_MASK
;
1430 socalp
->socal_rp
->socal_cr
.w
|= 3 << 16;
1431 if (ver
.prom_ver_len
> 10)
1432 ver
.prom_ver_len
= 10;
1433 bcopy((caddr_t
)socalp
->socal_eeprom
+ (unsigned)
1435 socalp
->socal_rp
->socal_cr
.w
= i
;
1436 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
1437 mutex_exit(&socalp
->request
[i
].skc_mtx
);
1439 &socalp
->response
[i
].skc_mtx
);
1441 if (ddi_copyout((caddr_t
)tmp
,
1442 (caddr_t
)ver
.prom_ver
,
1443 ver
.prom_ver_len
, mode
) == -1)
1446 ver
.prom_ver_len
= 0;
1448 ver
.mcode_ver_len
= 0;
1449 #ifdef _MULTI_DATAMODEL
1451 ver32
.fcode_ver_len
= ver
.fcode_ver_len
;
1452 ver32
.mcode_ver_len
= ver
.mcode_ver_len
;
1453 ver32
.prom_ver_len
= ver
.prom_ver_len
;
1454 ver32
.fcode_ver
= (caddr32_t
)(uintptr_t)
1456 ver32
.mcode_ver
= (caddr32_t
)(uintptr_t)
1458 ver32
.prom_ver
= (caddr32_t
)(uintptr_t)
1460 if (ddi_copyout((caddr_t
)&ver32
,
1461 (caddr_t
)arg
, sizeof (ver32
),
1465 #endif /* _MULTI_DATAMODEL */
1466 if (ddi_copyout((caddr_t
)&ver
, (caddr_t
)arg
,
1467 sizeof (struct socal_fm_version
), mode
) == -1)
1470 case FCIO_LOADUCODE
:
1471 mutex_enter(&socalp
->k_imr_mtx
);
1472 socal_disable(socalp
);
1473 mutex_exit(&socalp
->k_imr_mtx
);
1474 if (copyin((caddr_t
)arg
, (caddr_t
)socal_ucode
, 0x10000)
1477 /* restart socal after resetting */
1478 (void) socal_force_reset((void *)socalp
, 0,
1482 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
1483 mutex_enter(&socalp
->request
[i
].skc_mtx
);
1484 mutex_enter(&socalp
->response
[i
].skc_mtx
);
1486 for (i
= 0; i
< 4; i
++) {
1487 offset
= arg
+(0x10000 * i
);
1488 socalp
->socal_rp
->socal_cr
.w
&=
1489 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
1490 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
1491 (void) copyout((caddr_t
)socalp
->socal_xrp
,
1492 (caddr_t
)(uintptr_t)offset
, 0x10000);
1494 socalp
->socal_rp
->socal_cr
.w
&=
1495 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
1496 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
1497 mutex_exit(&socalp
->request
[i
].skc_mtx
);
1498 mutex_exit(&socalp
->response
[i
].skc_mtx
);
1502 case FCIO_DUMPXRAMBUF
:
1503 (void) copyout((caddr_t
)socal_xrambuf
, (caddr_t
)arg
,
1508 mutex_enter(&socalp
->ioctl_mtx
);
1509 if (socal_getmap(socalp
, port
, (caddr_t
)arg
, 0, 0) ==
1511 retval
= FCAL_ALLOC_FAILED
;
1512 mutex_exit(&socalp
->ioctl_mtx
);
1514 case FCIO_BYPASS_DEV
:
1515 mutex_enter(&socalp
->ioctl_mtx
);
1516 retval
= socal_bypass_dev((void *)socalp
, port
, arg
);
1517 mutex_exit(&socalp
->ioctl_mtx
);
1519 case FCIO_FORCE_LIP
:
1520 mutex_enter(&socalp
->ioctl_mtx
);
1521 retval
= socal_force_lip((void *)socalp
, port
, 0,
1523 mutex_exit(&socalp
->ioctl_mtx
);
1525 case FCIO_FORCE_OFFLINE
:
1526 mutex_enter(&socalp
->ioctl_mtx
);
1527 retval
= socal_force_offline((void *)socalp
, port
, 0);
1528 mutex_exit(&socalp
->ioctl_mtx
);
1530 case FCIO_ADISC_ELS
:
1533 (la_els_adisc_t
*)kmem_zalloc(
1534 sizeof (la_els_adisc_t
),
1535 KM_NOSLEEP
)) == NULL
)
1538 if (copyin((caddr_t
)arg
, (caddr_t
)adisc_pl
,
1539 sizeof (la_els_adisc_t
)) == -1) {
1540 kmem_free((void *)adisc_pl
,
1541 sizeof (la_els_adisc_t
));
1544 mutex_enter(&socalp
->ioctl_mtx
);
1545 retval
= socal_issue_adisc(socalp
, port
,
1548 mutex_exit(&socalp
->ioctl_mtx
);
1550 if (retval
== FCAL_SUCCESS
) {
1551 if (copyout((caddr_t
)adisc_pl
, (caddr_t
)arg
,
1552 sizeof (la_els_adisc_t
)) == -1) {
1553 kmem_free((void *)adisc_pl
,
1554 sizeof (la_els_adisc_t
));
1559 kmem_free((void *)adisc_pl
, sizeof (la_els_adisc_t
));
1562 case FCIO_LINKSTATUS
:
1566 (la_els_rls_reply_t
*)
1567 kmem_zalloc(sizeof (la_els_rls_reply_t
),
1568 KM_NOSLEEP
)) == NULL
)
1571 if (copyin((caddr_t
)arg
, (caddr_t
)rls_pl
,
1572 sizeof (la_els_rls_reply_t
)) == -1) {
1573 kmem_free((void *)rls_pl
,
1574 sizeof (la_els_rls_reply_t
));
1577 dest
= (rls_pl
->mbz
[0] << 16) + (rls_pl
->mbz
[1] << 8) +
1579 mutex_enter(&socalp
->ioctl_mtx
);
1580 retval
= socal_issue_rls(socalp
, port
, dest
,
1582 mutex_exit(&socalp
->ioctl_mtx
);
1584 if (retval
== FCAL_SUCCESS
) {
1585 if (copyout((caddr_t
)rls_pl
, (caddr_t
)arg
,
1586 sizeof (la_els_rls_reply_t
)) == -1) {
1587 kmem_free((void *)rls_pl
,
1588 sizeof (la_els_rls_reply_t
));
1592 kmem_free((void *)rls_pl
, sizeof (la_els_rls_reply_t
));
1595 case FCIO_LOOPBACK_INTERNAL
:
1597 * If userland doesn't provide a location for a return
1598 * value the driver will permanently offline the port,
1599 * ignoring any checks for devices on the loop.
1601 mutex_enter(&socalp
->ioctl_mtx
);
1603 port_statep
= &socalp
->port_state
[port
];
1604 mutex_enter(&port_statep
->sp_mtx
);
1605 if (port_statep
->sp_status
& PORT_DISABLED
) {
1606 /* Already disabled */
1607 mutex_exit(&port_statep
->sp_mtx
);
1608 mutex_exit(&socalp
->ioctl_mtx
);
1611 port_statep
->sp_status
|= PORT_DISABLED
;
1612 mutex_exit(&port_statep
->sp_mtx
);
1614 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1616 mutex_exit(&socalp
->ioctl_mtx
);
1617 if (arg
== 0) break;
1618 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1622 case FCIO_LOOPBACK_MANUAL
:
1623 mutex_enter(&socalp
->ioctl_mtx
);
1624 port_statep
= &socalp
->port_state
[port
];
1625 mutex_enter(&port_statep
->sp_mtx
);
1626 if (port_statep
->sp_status
& PORT_DISABLED
) {
1627 mutex_exit(&port_statep
->sp_mtx
);
1628 mutex_exit(&socalp
->ioctl_mtx
);
1631 mutex_exit(&port_statep
->sp_mtx
);
1632 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1634 mutex_exit(&socalp
->ioctl_mtx
);
1635 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1639 case FCIO_NO_LOOPBACK
:
1640 mutex_enter(&socalp
->ioctl_mtx
);
1641 port_statep
= &socalp
->port_state
[port
];
1642 mutex_enter(&port_statep
->sp_mtx
);
1643 /* Do not allow online if we're disabled */
1644 if (port_statep
->sp_status
& PORT_DISABLED
) {
1646 mutex_exit(&port_statep
->sp_mtx
);
1647 mutex_exit(&socalp
->ioctl_mtx
);
1649 * It's permanently disabled -- Need to
1654 /* This was a request to online. */
1655 port_statep
->sp_status
&= ~PORT_DISABLED
;
1657 mutex_exit(&port_statep
->sp_mtx
);
1658 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1660 mutex_exit(&socalp
->ioctl_mtx
);
1661 if (arg
== 0) break;
1662 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1667 mutex_enter(&socalp
->ioctl_mtx
);
1668 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1670 mutex_exit(&socalp
->ioctl_mtx
);
1671 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1675 case FCIO_DIAG_XRAM
:
1676 mutex_enter(&socalp
->ioctl_mtx
);
1677 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1678 SOC_DIAG_XRAM_TEST
);
1679 mutex_exit(&socalp
->ioctl_mtx
);
1680 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1685 mutex_enter(&socalp
->ioctl_mtx
);
1686 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1688 mutex_exit(&socalp
->ioctl_mtx
);
1689 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1694 mutex_enter(&socalp
->ioctl_mtx
);
1695 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1697 mutex_exit(&socalp
->ioctl_mtx
);
1698 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1702 case FCIO_DIAG_SOCLB
:
1703 mutex_enter(&socalp
->ioctl_mtx
);
1704 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1705 SOC_DIAG_SOCLB_TEST
);
1706 mutex_exit(&socalp
->ioctl_mtx
);
1707 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1711 case FCIO_DIAG_SRDSLB
:
1712 mutex_enter(&socalp
->ioctl_mtx
);
1713 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1714 SOC_DIAG_SRDSLB_TEST
);
1715 mutex_exit(&socalp
->ioctl_mtx
);
1716 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1720 case FCIO_DIAG_EXTLB
:
1721 mutex_enter(&socalp
->ioctl_mtx
);
1722 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1723 SOC_DIAG_EXTOE_TEST
);
1724 mutex_exit(&socalp
->ioctl_mtx
);
1725 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1730 if (copyin((caddr_t
)arg
, (caddr_t
)&i
, sizeof (uint_t
))
1733 mutex_enter(&socalp
->ioctl_mtx
);
1734 retval
= socal_diag_request((void *)socalp
, port
, &r
,
1736 mutex_exit(&socalp
->ioctl_mtx
);
1737 if (copyout((caddr_t
)&r
, (caddr_t
)arg
, sizeof (uint_t
))
1741 case FCIO_LOOPBACK_FRAME
:
1742 if ((flb_hdr
= (flb_hdr_t
*)kmem_zalloc(sizeof (flb_hdr_t
),
1743 KM_NOSLEEP
)) == NULL
)
1746 if (copyin((caddr_t
)arg
,
1747 (caddr_t
)flb_hdr
, sizeof (flb_hdr_t
)) == -1) {
1748 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1752 flb_size
= flb_hdr
->length
;
1755 (uchar_t
*)kmem_zalloc(flb_size
, KM_NOSLEEP
)) == NULL
)
1758 if (copyin((caddr_t
)(arg
+ sizeof (flb_hdr_t
)),
1759 (caddr_t
)flb_pl
, flb_size
) == -1) {
1760 kmem_free((void *)flb_pl
, flb_size
);
1763 mutex_enter(&socalp
->ioctl_mtx
);
1764 retval
= socal_issue_lbf(socalp
, port
, flb_pl
,
1766 mutex_exit(&socalp
->ioctl_mtx
);
1768 if (retval
== FCAL_SUCCESS
) {
1769 if (copyout((caddr_t
)flb_pl
,
1770 (caddr_t
)(arg
+ sizeof (flb_hdr_t
) +
1771 flb_hdr
->max_length
), flb_size
) == -1) {
1772 kmem_free((void *)flb_pl
, flb_size
);
1773 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1778 kmem_free((void *)flb_pl
, flb_size
);
1779 kmem_free((void *)flb_hdr
, sizeof (flb_hdr_t
));
1788 case FCAL_ALLOC_FAILED
:
1790 case FCAL_STATUS_DIAG_BUSY
:
1792 case FCAL_STATUS_DIAG_INVALID
:
1801 * Function name : socal_disable()
1803 * Return Values : none
1805 * Description : Reset the soc+
1807 * Context : Can be called from different kernel process threads.
1808 * Can be called by interrupt thread.
1810 * Note: before calling this, the interface should be locked down
1811 * so that it is guaranteed that no other threads are accessing
1815 socal_disable(socal_state_t
*socalp
)
1818 /* Don't touch the hardware if the registers aren't mapped */
1819 if (!socalp
->socal_rp
)
1822 socalp
->socal_rp
->socal_imr
= socalp
->socal_k_imr
= 0;
1823 socalp
->socal_rp
->socal_csr
.w
= SOCAL_CSR_SOFT_RESET
;
1824 i
= socalp
->socal_rp
->socal_csr
.w
;
1825 DEBUGF(9, (CE_CONT
, "csr.w = %x\n", i
));
1829 * Function name : socal_init_transport_interface()
1831 * Return Values : none
1833 * Description : Fill up the fcal_tranpsort struct for ULPs
1836 * Note: Only called during attach, so no protection
1839 socal_init_transport_interface(socal_state_t
*socalp
)
1842 fcal_transport_t
*xport
;
1844 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
1845 xport
= socalp
->port_state
[i
].sp_transport
;
1846 mutex_init(&xport
->fcal_mtx
, NULL
, MUTEX_DRIVER
,
1847 (void *)(socalp
->iblkc
));
1849 cv_init(&xport
->fcal_cv
, NULL
, CV_DRIVER
, NULL
);
1851 xport
->fcal_handle
= (void *)socalp
;
1852 xport
->fcal_dmalimp
= socallim
;
1853 xport
->fcal_iblock
= socalp
->iblkc
;
1854 xport
->fcal_dmaattr
= &socal_dma_attr
;
1855 xport
->fcal_accattr
= &socal_acc_attr
;
1856 xport
->fcal_loginparms
= socalp
->socal_service_params
;
1857 bcopy((caddr_t
)&socalp
->socal_n_wwn
,
1858 (caddr_t
)&xport
->fcal_n_wwn
, sizeof (la_wwn_t
));
1859 bcopy((caddr_t
)&socalp
->port_state
[i
].sp_p_wwn
,
1860 (caddr_t
)&xport
->fcal_p_wwn
, sizeof (la_wwn_t
));
1861 xport
->fcal_portno
= i
;
1862 xport
->fcal_cmdmax
= SOCAL_MAX_XCHG
;
1863 xport
->fcal_ops
= &socal_transport_ops
;
1869 * socal_cqalloc_init() - Inialize the circular queue tables.
1870 * Also, init the locks that are associated with the tables.
1872 * Returns: FCAL_SUCCESS, if able to init properly.
1873 * FCAL_FAILURE, if unable to init properly.
1877 socal_cqalloc_init(socal_state_t
*socalp
, uint32_t index
)
1883 int req_bound
= 0, rsp_bound
= 0;
1886 * Initialize the Request and Response Queue locks.
1889 mutex_init(&socalp
->request
[index
].skc_mtx
, NULL
, MUTEX_DRIVER
,
1890 (void *)socalp
->iblkc
);
1891 mutex_init(&socalp
->response
[index
].skc_mtx
, NULL
, MUTEX_DRIVER
,
1892 (void *)socalp
->iblkc
);
1893 cv_init(&socalp
->request
[index
].skc_cv
, NULL
, CV_DRIVER
, NULL
);
1894 cv_init(&socalp
->response
[index
].skc_cv
, NULL
, CV_DRIVER
, NULL
);
1896 /* Allocate DVMA resources for the Request Queue. */
1897 cq_size
= socal_req_entries
[index
] * sizeof (cqe_t
);
1899 cqp
= &socalp
->request
[index
];
1901 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
1902 DDI_DMA_DONTWAIT
, NULL
,
1903 &cqp
->skc_dhandle
) != DDI_SUCCESS
) {
1904 socal_disp_err(socalp
, CE_WARN
, "driver.4020",
1905 "!alloc of dma handle failed");
1909 if (ddi_dma_mem_alloc(cqp
->skc_dhandle
,
1910 cq_size
+ SOCAL_CQ_ALIGN
, &socal_acc_attr
,
1911 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
1912 (caddr_t
*)&cqp
->skc_cq_raw
, &real_len
,
1913 &cqp
->skc_acchandle
) != DDI_SUCCESS
) {
1914 socal_disp_err(socalp
, CE_WARN
, "driver.4030",
1915 "!alloc of dma space failed");
1919 if (real_len
< (cq_size
+ SOCAL_CQ_ALIGN
)) {
1920 socal_disp_err(socalp
, CE_WARN
, "driver.4035",
1921 "!alloc of dma space failed");
1924 cqp
->skc_cq
= (cqe_t
*)(((uintptr_t)cqp
->skc_cq_raw
+
1925 (uintptr_t)SOCAL_CQ_ALIGN
- 1) &
1926 ((uintptr_t)(~(SOCAL_CQ_ALIGN
-1))));
1928 if (ddi_dma_addr_bind_handle(cqp
->skc_dhandle
,
1929 NULL
, (caddr_t
)cqp
->skc_cq
, cq_size
,
1930 DDI_DMA_RDWR
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
1931 NULL
, &cqp
->skc_dcookie
, &ccount
) != DDI_DMA_MAPPED
) {
1932 socal_disp_err(socalp
, CE_WARN
, "driver.4040",
1933 "!bind of dma handle failed");
1939 socal_disp_err(socalp
, CE_WARN
, "driver.4045",
1940 "!bind of dma handle failed");
1945 socalp
->request
[index
].skc_cq_raw
= NULL
;
1946 socalp
->request
[index
].skc_cq
= (cqe_t
*)NULL
;
1947 socalp
->request
[index
].skc_dhandle
= 0;
1950 /* Allocate DVMA resources for the response Queue. */
1951 cq_size
= socal_rsp_entries
[index
] * sizeof (cqe_t
);
1953 cqp
= &socalp
->response
[index
];
1955 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
1956 DDI_DMA_DONTWAIT
, NULL
,
1957 &cqp
->skc_dhandle
) != DDI_SUCCESS
) {
1958 socal_disp_err(socalp
, CE_WARN
, "driver.4050",
1959 "!alloc of dma handle failed");
1963 if (ddi_dma_mem_alloc(cqp
->skc_dhandle
,
1964 cq_size
+ SOCAL_CQ_ALIGN
, &socal_acc_attr
,
1965 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
1966 (caddr_t
*)&cqp
->skc_cq_raw
, &real_len
,
1967 &cqp
->skc_acchandle
) != DDI_SUCCESS
) {
1968 socal_disp_err(socalp
, CE_WARN
, "driver.4060",
1969 "!alloc of dma space failed");
1973 if (real_len
< (cq_size
+ SOCAL_CQ_ALIGN
)) {
1974 socal_disp_err(socalp
, CE_WARN
, "driver.4065",
1975 "!alloc of dma space failed");
1979 cqp
->skc_cq
= (cqe_t
*)(((uintptr_t)cqp
->skc_cq_raw
+
1980 (uintptr_t)SOCAL_CQ_ALIGN
- 1) &
1981 ((uintptr_t)(~(SOCAL_CQ_ALIGN
-1))));
1983 if (ddi_dma_addr_bind_handle(cqp
->skc_dhandle
,
1984 NULL
, (caddr_t
)cqp
->skc_cq
, cq_size
,
1985 DDI_DMA_RDWR
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
1986 NULL
, &cqp
->skc_dcookie
, &ccount
) != DDI_DMA_MAPPED
) {
1987 socal_disp_err(socalp
, CE_WARN
, "driver.4070",
1988 "!bind of dma handle failed");
1994 socal_disp_err(socalp
, CE_WARN
, "driver.4075",
1995 "!bind of dma handle failed");
2000 socalp
->response
[index
].skc_cq_raw
= NULL
;
2001 socalp
->response
[index
].skc_cq
= (cqe_t
*)NULL
;
2002 socalp
->response
[index
].skc_dhandle
= 0;
2006 * Initialize the queue pointers
2008 socal_cqinit(socalp
, index
);
2010 return (FCAL_SUCCESS
);
2012 if (socalp
->request
[index
].skc_dhandle
) {
2014 (void) ddi_dma_unbind_handle(socalp
->
2015 request
[index
].skc_dhandle
);
2016 ddi_dma_free_handle(&socalp
->request
[index
].skc_dhandle
);
2018 if (socalp
->request
[index
].skc_cq_raw
)
2019 ddi_dma_mem_free(&socalp
->request
[index
].skc_acchandle
);
2021 if (socalp
->response
[index
].skc_dhandle
) {
2023 (void) ddi_dma_unbind_handle(socalp
->
2024 response
[index
].skc_dhandle
);
2025 ddi_dma_free_handle(&socalp
->response
[index
].skc_dhandle
);
2027 if (socalp
->response
[index
].skc_cq_raw
)
2028 ddi_dma_mem_free(&socalp
->response
[index
].skc_acchandle
);
2030 socalp
->request
[index
].skc_dhandle
= NULL
;
2031 socalp
->response
[index
].skc_dhandle
= NULL
;
2032 socalp
->request
[index
].skc_cq_raw
= NULL
;
2033 socalp
->request
[index
].skc_cq
= NULL
;
2034 socalp
->response
[index
].skc_cq_raw
= NULL
;
2035 socalp
->response
[index
].skc_cq
= NULL
;
2036 mutex_destroy(&socalp
->request
[index
].skc_mtx
);
2037 mutex_destroy(&socalp
->response
[index
].skc_mtx
);
2038 cv_destroy(&socalp
->request
[index
].skc_cv
);
2039 cv_destroy(&socalp
->response
[index
].skc_cv
);
2040 return (FCAL_FAILURE
);
2045 * socal_cqinit() - initializes the driver's circular queue pointers, etc.
2049 socal_cqinit(socal_state_t
*socalp
, uint32_t index
)
2051 socal_kcq_t
*kcq_req
= &socalp
->request
[index
];
2052 socal_kcq_t
*kcq_rsp
= &socalp
->response
[index
];
2055 * Initialize the Request and Response Queue pointers
2057 kcq_req
->skc_seqno
= 1;
2058 kcq_rsp
->skc_seqno
= 1;
2059 kcq_req
->skc_in
= 0;
2060 kcq_rsp
->skc_in
= 0;
2061 kcq_req
->skc_out
= 0;
2062 kcq_rsp
->skc_out
= 0;
2063 kcq_req
->skc_last_index
= socal_req_entries
[index
] - 1;
2064 kcq_rsp
->skc_last_index
= socal_rsp_entries
[index
] - 1;
2065 kcq_req
->skc_full
= 0;
2066 kcq_rsp
->deferred_intr_timeoutid
= 0;
2067 kcq_req
->skc_socalp
= socalp
;
2068 kcq_rsp
->skc_socalp
= socalp
;
2070 kcq_req
->skc_xram_cqdesc
=
2071 (socalp
->xram_reqp
+ (index
* sizeof (struct cq
))/8);
2072 kcq_rsp
->skc_xram_cqdesc
=
2073 (socalp
->xram_rspp
+ (index
* sizeof (struct cq
))/8);
2075 /* Clear out memory we have allocated */
2076 if (kcq_req
->skc_cq
!= NULL
)
2077 bzero((caddr_t
)kcq_req
->skc_cq
,
2078 socal_req_entries
[index
] * sizeof (cqe_t
));
2079 if (kcq_rsp
->skc_cq
!= NULL
)
2080 bzero((caddr_t
)kcq_rsp
->skc_cq
,
2081 socal_rsp_entries
[index
] * sizeof (cqe_t
));
2086 socal_start(socal_state_t
*socalp
)
2091 return (FCAL_FAILURE
);
2093 socal_download_ucode(socalp
);
2094 socal_init_cq_desc(socalp
);
2095 socal_init_wwn(socalp
);
2097 mutex_enter(&socalp
->port_state
[0].sp_mtx
);
2098 socalp
->port_state
[0].sp_status
2099 &= (PORT_OPEN
|PORT_CHILD_INIT
|PORT_DISABLED
|PORT_TARGET_MODE
);
2100 socalp
->port_state
[0].sp_status
|= PORT_OFFLINE
;
2101 mutex_exit(&socalp
->port_state
[0].sp_mtx
);
2103 mutex_enter(&socalp
->port_state
[1].sp_mtx
);
2104 socalp
->port_state
[1].sp_status
2105 &= (PORT_OPEN
|PORT_CHILD_INIT
|PORT_DISABLED
|PORT_TARGET_MODE
);
2106 socalp
->port_state
[1].sp_status
|= PORT_OFFLINE
;
2107 mutex_exit(&socalp
->port_state
[1].sp_mtx
);
2109 socal_enable(socalp
);
2110 /* Make sure disabled ports stay disabled. */
2111 if (socalp
->port_state
[0].sp_status
& PORT_DISABLED
)
2112 (void) socal_diag_request((void *)socalp
, 0, &r
,
2114 if (socalp
->port_state
[1].sp_status
& PORT_DISABLED
)
2115 (void) socal_diag_request((void *)socalp
, 1, &r
,
2118 mutex_enter(&socalp
->k_imr_mtx
);
2119 socalp
->socal_shutdown
= 0;
2120 mutex_exit(&socalp
->k_imr_mtx
);
2122 mutex_enter(&socalp
->board_mtx
);
2123 if (socal_establish_pool(socalp
, 1) != FCAL_SUCCESS
) {
2124 mutex_exit(&socalp
->board_mtx
);
2125 return (FCAL_FAILURE
);
2127 if (socal_add_pool_buffer(socalp
, 1) != FCAL_SUCCESS
) {
2128 mutex_exit(&socalp
->board_mtx
);
2129 return (FCAL_FAILURE
);
2132 mutex_exit(&socalp
->board_mtx
);
2133 return (FCAL_SUCCESS
);
2137 socal_doreset(socal_state_t
*socalp
)
2140 socal_port_t
*port_statep
;
2141 socal_unsol_cb_t
*scbp
;
2143 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2144 mutex_enter(&socalp
->request
[i
].skc_mtx
);
2145 mutex_enter(&socalp
->response
[i
].skc_mtx
);
2148 mutex_enter(&socalp
->k_imr_mtx
);
2149 socal_disable(socalp
);
2151 if (socalp
->pool_dhandle
) {
2152 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
2153 ddi_dma_free_handle(&socalp
->pool_dhandle
);
2157 ddi_dma_mem_free(&socalp
->pool_acchandle
);
2159 socalp
->pool_dhandle
= NULL
;
2160 socalp
->pool
= NULL
;
2162 for (i
= 0; i
< SOCAL_N_CQS
; i
++)
2163 socal_cqinit(socalp
, i
);
2165 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
2166 port_statep
= &socalp
->port_state
[i
];
2168 mutex_enter(&port_statep
->sp_mtx
);
2169 port_statep
->sp_status
&= ~ (PORT_STATUS_MASK
|
2170 PORT_LILP_PENDING
| PORT_LIP_PENDING
|
2171 PORT_ABORT_PENDING
| PORT_BYPASS_PENDING
|
2173 mutex_exit(&port_statep
->sp_mtx
);
2176 mutex_exit(&socalp
->k_imr_mtx
);
2178 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
2179 mutex_exit(&socalp
->request
[i
].skc_mtx
);
2180 mutex_exit(&socalp
->response
[i
].skc_mtx
);
2183 for (i
= 0; i
< N_SOCAL_NPORTS
; i
++) {
2184 for (scbp
= socalp
->port_state
[i
].sp_unsol_cb
; scbp
;
2186 (scbp
->statec_cb
)(scbp
->arg
, FCAL_STATE_RESET
);
2189 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2190 mutex_enter(&socalp
->request
[i
].skc_mtx
);
2191 mutex_enter(&socalp
->response
[i
].skc_mtx
);
2195 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2196 socalp
->request
[i
].skc_overflowh
= NULL
;
2197 if (socalp
->request
[i
].skc_full
& SOCAL_SKC_SLEEP
)
2198 cv_broadcast(&socalp
->request
[i
].skc_cv
);
2201 for (i
= SOCAL_N_CQS
-1; i
>= 0; i
--) {
2202 mutex_exit(&socalp
->request
[i
].skc_mtx
);
2203 mutex_exit(&socalp
->response
[i
].skc_mtx
);
2210 * Function name : socal_download_ucode ()
2214 * Description : Copies firmware from code that has been linked into
2215 * the socal module into the soc+'s XRAM. Prints the date
2220 socal_download_ucode(socal_state_t
*socalp
)
2223 uint_t date_str
[16];
2226 fw_len
= (uint_t
)socal_ucode_size
;
2228 /* Copy the firmware image */
2229 socal_wcopy((uint_t
*)&socal_ucode
,
2230 (uint_t
*)socalp
->socal_xrp
, fw_len
);
2232 socal_fix_harda(socalp
, 0);
2233 socal_fix_harda(socalp
, 1);
2235 /* Get the date string from the firmware image */
2236 socal_wcopy((uint_t
*)(socalp
->socal_xrp
+SOCAL_XRAM_FW_DATE_STR
),
2237 date_str
, sizeof (date_str
));
2238 date_str
[sizeof (date_str
) / sizeof (uint_t
) - 1] = 0;
2240 if (*(caddr_t
)date_str
!= '\0') {
2242 "!Downloading host adapter, fw date code: %s\n",
2244 socal_disp_err(socalp
, CE_CONT
, "driver.1010", buf
);
2245 (void) strcpy(socalp
->socal_stats
.fw_revision
,
2249 "!Downloading host adapter fw, "
2250 "date code: <not available>\n");
2251 socal_disp_err(socalp
, CE_CONT
, "driver.3010", buf
);
2252 (void) strcpy(socalp
->socal_stats
.fw_revision
,
2258 * Function name : socal_disp_err()
2260 * Return Values : none
2262 * Description : displays an error message on the system console
2263 * with the full device pathname displayed
2267 socal_state_t
*socalp
,
2275 instance
= ddi_get_instance(socalp
->dip
);
2279 if (c
== '!') /* log only */
2281 "!ID[SUNWssa.socal.%s] socal%d: %s", mid
, instance
, msg
+1);
2282 else if (c
== '?') /* boot message - log && maybe console */
2284 "?ID[SUNWssa.socal.%s] socal%d: %s", mid
, instance
, msg
+1);
2285 else if (c
== '^') /* console only */
2286 cmn_err(level
, "^socal%d: %s", instance
, msg
+1);
2287 else { /* log and console */
2288 cmn_err(level
, "^socal%d: %s", instance
, msg
);
2289 cmn_err(level
, "!ID[SUNWssa.socal.%s] socal%d: %s", mid
,
2295 * Function name : socal_init_cq_desc()
2297 * Return Values : none
2299 * Description : Initializes the request and response queue
2300 * descriptors in the SOC+'s XRAM
2302 * Context : Should only be called during initialiation when
2303 * the SOC+ is reset.
2306 socal_init_cq_desc(socal_state_t
*socalp
)
2308 soc_cq_t que_desc
[SOCAL_N_CQS
];
2312 * Finish CQ table initialization and give the descriptor
2313 * table to the soc+. Note that we don't use all of the queues
2314 * provided by the hardware, but we make sure we initialize the
2315 * quantities in the unused fields in the hardware to zeroes.
2321 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2322 if (socal_req_entries
[i
]) {
2323 que_desc
[i
].cq_address
=
2324 (uint32_t)socalp
->request
[i
].
2325 skc_dcookie
.dmac_address
;
2326 que_desc
[i
].cq_last_index
= socal_req_entries
[i
] - 1;
2328 que_desc
[i
].cq_address
= (uint32_t)0;
2329 que_desc
[i
].cq_last_index
= 0;
2331 que_desc
[i
].cq_in
= 0;
2332 que_desc
[i
].cq_out
= 0;
2333 que_desc
[i
].cq_seqno
= 1; /* required by SOC+ microcode */
2337 socal_wcopy((uint_t
*)que_desc
, /* pointer to kernel copy */
2338 (uint_t
*)socalp
->xram_reqp
, /* pointer to xram location */
2339 SOCAL_N_CQS
* sizeof (soc_cq_t
));
2342 * Do response queues
2344 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
2345 if (socal_rsp_entries
[i
]) {
2346 que_desc
[i
].cq_last_index
= socal_rsp_entries
[i
] - 1;
2347 que_desc
[i
].cq_address
=
2348 (uint32_t)socalp
->response
[i
].
2349 skc_dcookie
.dmac_address
;
2352 que_desc
[i
].cq_address
= 0;
2353 que_desc
[i
].cq_last_index
= 0;
2358 socal_wcopy((uint_t
*)que_desc
, /* pointer to kernel copy */
2359 (uint_t
*)socalp
->xram_rspp
, /* pointer to xram location */
2360 SOCAL_N_CQS
* sizeof (soc_cq_t
));
2364 socal_init_wwn(socal_state_t
*socalp
)
2366 /* copy the node wwn to xram */
2367 socal_wcopy((uint_t
*)&socalp
->socal_n_wwn
,
2368 (uint_t
*)(socalp
->socal_xrp
+
2369 SOCAL_XRAM_NODE_WWN
), sizeof (la_wwn_t
));
2371 /* copy port a's wwn to xram */
2372 socal_wcopy((uint_t
*)&socalp
->port_state
[0].sp_p_wwn
,
2373 (uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_PORTA_WWN
),
2376 /* copy port b's wwn to xram */
2377 socal_wcopy((uint_t
*)&socalp
->port_state
[1].sp_p_wwn
,
2378 (uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_PORTB_WWN
),
2382 * need to avoid deadlock by assuring no other thread grabs both of
2385 mutex_enter(&socalp
->port_state
[0].sp_transport
->fcal_mtx
);
2386 mutex_enter(&socalp
->port_state
[1].sp_transport
->fcal_mtx
);
2388 socal_wcopy((uint_t
*)(socalp
->socal_xrp
+ SOCAL_XRAM_SERV_PARAMS
),
2389 (uint_t
*)&socalp
->socal_service_params
, SOCAL_SVC_LENGTH
);
2390 mutex_exit(&socalp
->port_state
[1].sp_transport
->fcal_mtx
);
2391 mutex_exit(&socalp
->port_state
[0].sp_transport
->fcal_mtx
);
2395 socal_enable(socal_state_t
*socalp
)
2397 DEBUGF(2, (CE_CONT
, "socal%d: enable:\n",
2398 ddi_get_instance(socalp
->dip
)));
2400 socalp
->socal_rp
->socal_cr
.w
= socalp
->socal_cfg
;
2401 socalp
->socal_rp
->socal_csr
.w
= SOCAL_CSR_SOCAL_TO_HOST
;
2403 socalp
->socal_k_imr
= (uint32_t)SOCAL_CSR_SOCAL_TO_HOST
|
2404 SOCAL_CSR_SLV_ACC_ERR
;
2405 socalp
->socal_rp
->socal_imr
= (uint32_t)socalp
->socal_k_imr
;
2410 * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
2411 * to place LINK ctl application data as it arrives.
2414 * FCAL_SUCCESS, upon establishing the pool.
2415 * FCAL_FAILURE, if unable to establish the pool.
2419 socal_establish_pool(socal_state_t
*socalp
, uint32_t poolid
)
2421 soc_pool_request_t
*prq
;
2425 (soc_pool_request_t
*)kmem_zalloc(sizeof (soc_pool_request_t
),
2426 KM_NOSLEEP
)) == NULL
)
2427 return (FCAL_FAILURE
);
2429 * Fill in the request structure.
2431 prq
->spr_soc_hdr
.sh_request_token
= 1;
2432 prq
->spr_soc_hdr
.sh_flags
= SOC_FC_HEADER
| SOC_UNSOLICITED
|
2434 prq
->spr_soc_hdr
.sh_class
= 0;
2435 prq
->spr_soc_hdr
.sh_seg_cnt
= 1;
2436 prq
->spr_soc_hdr
.sh_byte_cnt
= 0;
2438 prq
->spr_pool_id
= poolid
;
2439 prq
->spr_header_mask
= SOCPR_MASK_RCTL
;
2440 prq
->spr_buf_size
= SOCAL_POOL_SIZE
;
2441 prq
->spr_n_entries
= 0;
2443 prq
->spr_fc_frame_hdr
.r_ctl
= R_CTL_ELS_REQ
;
2444 prq
->spr_fc_frame_hdr
.d_id
= 0;
2445 prq
->spr_fc_frame_hdr
.s_id
= 0;
2446 prq
->spr_fc_frame_hdr
.type
= 0;
2447 prq
->spr_fc_frame_hdr
.f_ctl
= 0;
2448 prq
->spr_fc_frame_hdr
.seq_id
= 0;
2449 prq
->spr_fc_frame_hdr
.df_ctl
= 0;
2450 prq
->spr_fc_frame_hdr
.seq_cnt
= 0;
2451 prq
->spr_fc_frame_hdr
.ox_id
= 0;
2452 prq
->spr_fc_frame_hdr
.rx_id
= 0;
2453 prq
->spr_fc_frame_hdr
.ro
= 0;
2455 prq
->spr_cqhdr
.cq_hdr_count
= 1;
2456 prq
->spr_cqhdr
.cq_hdr_type
= CQ_TYPE_ADD_POOL
;
2457 prq
->spr_cqhdr
.cq_hdr_flags
= 0;
2458 prq
->spr_cqhdr
.cq_hdr_seqno
= 0;
2460 /* Enque the request. */
2461 result
= socal_cq_enque(socalp
, NULL
, (cqe_t
*)prq
, CQ_REQUEST_1
,
2462 FCAL_NOSLEEP
, NULL
, 0);
2463 kmem_free((void *)prq
, sizeof (soc_pool_request_t
));
2471 * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
2472 * to an established pool of buffers
2475 * DDI_SUCCESS, upon establishing the pool.
2476 * DDI_FAILURE, if unable to establish the pool.
2480 socal_add_pool_buffer(socal_state_t
*socalp
, uint32_t poolid
)
2482 soc_data_request_t
*drq
;
2489 (soc_data_request_t
*)kmem_zalloc(sizeof (soc_data_request_t
),
2490 KM_NOSLEEP
)) == NULL
)
2491 return (FCAL_FAILURE
);
2493 /* Allocate DVMA resources for the buffer pool */
2494 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
2495 DDI_DMA_DONTWAIT
, NULL
, &socalp
->pool_dhandle
) != DDI_SUCCESS
)
2498 if (ddi_dma_mem_alloc(socalp
->pool_dhandle
, SOCAL_POOL_SIZE
,
2499 &socal_acc_attr
, DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
2500 (caddr_t
*)&socalp
->pool
, &real_len
, &socalp
->pool_acchandle
)
2504 if (real_len
< SOCAL_POOL_SIZE
)
2507 if (ddi_dma_addr_bind_handle(socalp
->pool_dhandle
, NULL
,
2508 (caddr_t
)socalp
->pool
, SOCAL_POOL_SIZE
,
2509 DDI_DMA_READ
| DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
,
2510 NULL
, &socalp
->pool_dcookie
, &ccount
) != DDI_DMA_MAPPED
)
2518 * Fill in the request structure.
2520 drq
->sdr_soc_hdr
.sh_request_token
= poolid
;
2521 drq
->sdr_soc_hdr
.sh_flags
= SOC_UNSOLICITED
| SOC_NO_RESPONSE
;
2522 drq
->sdr_soc_hdr
.sh_class
= 0;
2523 drq
->sdr_soc_hdr
.sh_seg_cnt
= 1;
2524 drq
->sdr_soc_hdr
.sh_byte_cnt
= 0;
2526 drq
->sdr_dataseg
[0].fc_base
=
2527 (uint32_t)socalp
->pool_dcookie
.dmac_address
;
2528 drq
->sdr_dataseg
[0].fc_count
= SOCAL_POOL_SIZE
;
2529 drq
->sdr_dataseg
[1].fc_base
= 0;
2530 drq
->sdr_dataseg
[1].fc_count
= 0;
2531 drq
->sdr_dataseg
[2].fc_base
= 0;
2532 drq
->sdr_dataseg
[2].fc_count
= 0;
2533 drq
->sdr_dataseg
[3].fc_base
= 0;
2534 drq
->sdr_dataseg
[3].fc_count
= 0;
2535 drq
->sdr_dataseg
[4].fc_base
= 0;
2536 drq
->sdr_dataseg
[4].fc_count
= 0;
2537 drq
->sdr_dataseg
[5].fc_base
= 0;
2538 drq
->sdr_dataseg
[5].fc_count
= 0;
2540 drq
->sdr_cqhdr
.cq_hdr_count
= 1;
2541 drq
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_ADD_BUFFER
;
2542 drq
->sdr_cqhdr
.cq_hdr_flags
= 0;
2543 drq
->sdr_cqhdr
.cq_hdr_seqno
= 0;
2545 /* Transport the request. */
2546 result
= socal_cq_enque(socalp
, NULL
, (cqe_t
*)drq
, CQ_REQUEST_1
,
2547 FCAL_NOSLEEP
, NULL
, 0);
2548 kmem_free((void *)drq
, sizeof (soc_data_request_t
));
2552 socal_disp_err(socalp
, CE_WARN
, "driver.4110",
2553 "!Buffer pool DVMA alloc failed");
2554 if (socalp
->pool_dhandle
) {
2556 (void) ddi_dma_unbind_handle(socalp
->pool_dhandle
);
2557 ddi_dma_free_handle(&socalp
->pool_dhandle
);
2560 ddi_dma_mem_free(&socalp
->pool_acchandle
);
2561 socalp
->pool_dhandle
= NULL
;
2562 return (FCAL_FAILURE
);
2566 socal_transport(fcal_packet_t
*fcalpkt
, fcal_sleep_t sleep
, int req_q_no
)
2568 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2569 socal_port_t
*port_statep
;
2570 #if defined(DEBUG) && !defined(lint)
2571 int instance
= ddi_get_instance(socalp
->dip
);
2574 soc_request_t
*sp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
2576 if (sp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
2580 port_statep
= &socalp
->port_state
[port
];
2582 DEBUGF(4, (CE_CONT
, "socal%d: transport: packet, sleep = %p, %d\n",
2583 instance
, fcalpkt
, sleep
));
2585 fcalpkt
->fcal_cmd_state
= 0;
2586 fcalpkt
->fcal_pkt_flags
&= ~(FCFLAG_COMPLETE
| FCFLAG_ABORTING
);
2588 return (socal_cq_enque(socalp
, port_statep
, (cqe_t
*)sp
,
2589 req_q_no
, sleep
, fcalpkt
, 0));
2593 * Function name : socal_cq_enque()
2596 * FCAL_TRANSPORT_SUCCESS, if able to que the entry.
2597 * FCAL_TRANSPORT_QFULL, if queue full & sleep not set
2598 * FCAL_TRANSPORT_UNAVAIL if this port down
2600 * Description : Enqueues an entry into the solicited request
2608 socal_cq_enque(socal_state_t
*socalp
, socal_port_t
*port_statep
, cqe_t
*cqe
,
2609 int rqix
, fcal_sleep_t sleep
, fcal_packet_t
*to_queue
,
2612 #if defined(DEBUG) && !defined(lint)
2613 int instance
= ddi_get_instance(socalp
->dip
);
2617 uint_t bitmask
, wmask
;
2622 kcq
= &socalp
->request
[rqix
];
2624 bitmask
= SOCAL_CSR_1ST_H_TO_S
<< rqix
;
2625 wmask
= SOCAL_CSR_SOCAL_TO_HOST
| bitmask
;
2626 p
= (longlong_t
*)cqe
;
2629 * Since we're only reading we don't need a mutex.
2631 if (socalp
->socal_shutdown
) {
2632 return (FCAL_TRANSPORT_UNAVAIL
);
2635 * Get a token early. That way we won't sleep
2636 * in id32_alloc() with a mutex held.
2639 if ((to_queue
->fcal_socal_request
.sr_soc_hdr
.sh_request_token
=
2640 SOCAL_ID_GET(to_queue
, mtxheld
? FCAL_NOSLEEP
:
2642 return (FCAL_TRANSPORT_QFULL
);
2646 * Grab lock for request queue.
2650 mutex_enter(&kcq
->skc_mtx
);
2653 * Determine if the queue is full
2658 if (kcq
->skc_full
) {
2660 * If soc's queue full, then we wait for an interrupt
2661 * telling us we are not full.
2665 to_queue
->fcal_pkt_next
= NULL
;
2666 if (!kcq
->skc_overflowh
) {
2668 "socal%d: cq_enque: request "
2671 kcq
->skc_overflowh
= to_queue
;
2672 socalp
->socal_stats
.qfulls
++;
2674 kcq
->skc_overflowt
->fcal_pkt_next
= to_queue
;
2675 kcq
->skc_overflowt
= to_queue
;
2677 mutex_enter(&socalp
->k_imr_mtx
);
2678 socalp
->socal_rp
->socal_imr
=
2679 (socalp
->socal_k_imr
|= bitmask
);
2680 mutex_exit(&socalp
->k_imr_mtx
);
2681 to_queue
->fcal_cmd_state
|= FCAL_CMD_IN_TRANSPORT
;
2683 mutex_exit(&kcq
->skc_mtx
);
2684 return (FCAL_TRANSPORT_SUCCESS
);
2688 mutex_exit(&kcq
->skc_mtx
);
2689 return (FCAL_TRANSPORT_QFULL
);
2692 if (((kcq
->skc_in
+ 1) & kcq
->skc_last_index
)
2693 == (out
= kcq
->skc_out
)) {
2695 * get SOC+'s copy of out to update our copy of out
2698 SOCAL_REQUESTQ_INDEX(rqix
, socalp
->socal_rp
->socal_reqp
.w
);
2700 "socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
2701 instance
, &kcq
->skc_xram_cqdesc
->cq_in
, s_out
));
2703 kcq
->skc_out
= out
= s_out
;
2704 /* if soc+'s que still full set flag */
2705 kcq
->skc_full
= ((((kcq
->skc_in
+ 1) &
2706 kcq
->skc_last_index
) == out
)) ? SOCAL_SKC_FULL
: 0;
2709 } while (kcq
->skc_full
);
2711 /* Now enque the entry. */
2712 sp
= &(kcq
->skc_cq
[kcq
->skc_in
]);
2713 cqe
->cqe_hdr
.cq_hdr_seqno
= kcq
->skc_seqno
;
2715 /* Give the entry to the SOC. */
2716 q
= (longlong_t
*)sp
;
2725 (void) ddi_dma_sync(kcq
->skc_dhandle
, (int)((caddr_t
)sp
-
2726 (caddr_t
)kcq
->skc_cq
), sizeof (cqe_t
), DDI_DMA_SYNC_FORDEV
);
2728 to_queue
->fcal_cmd_state
|= FCAL_CMD_IN_TRANSPORT
;
2731 * Update circular queue and ring SOC's doorbell.
2734 if ((kcq
->skc_in
& kcq
->skc_last_index
) == 0) {
2739 socalp
->socal_rp
->socal_csr
.w
= wmask
| (kcq
->skc_in
<< 24);
2740 /* Let lock go for request queue. */
2742 mutex_exit(&kcq
->skc_mtx
);
2744 return (FCAL_TRANSPORT_SUCCESS
);
2748 socal_transport_poll(fcal_packet_t
*fcalpkt
, uint_t timeout
, int req_q_no
)
2750 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2751 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
2753 socal_port_t
*port_statep
;
2755 soc_request_t
*sp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
2759 /* make the timeout meaningful */
2760 timeout
= drv_usectohz(timeout
);
2761 if (sp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
2765 port_statep
= &socalp
->port_state
[port
];
2767 fcalpkt
->fcal_cmd_state
= 0;
2768 fcalpkt
->fcal_pkt_flags
&= ~(FCFLAG_COMPLETE
| FCFLAG_ABORTING
);
2770 ticker
= ddi_get_lbolt();
2772 if ((retval
= socal_cq_enque(socalp
, port_statep
, (cqe_t
*)sp
,
2773 req_q_no
, FCAL_NOSLEEP
, fcalpkt
, 0)) != FCAL_TRANSPORT_SUCCESS
) {
2776 while (!(fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)) {
2777 drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME
);
2778 t
= ddi_get_lbolt();
2779 if ((ticker
+ timeout
) < t
)
2780 return (FCAL_TRANSPORT_TIMEOUT
);
2781 csr
= socalreg
->socal_csr
.w
;
2782 if ((SOCAL_INTR_CAUSE(socalp
, csr
)) &
2783 SOCAL_CSR_RSP_QUE_0
) {
2784 socal_intr_solicited(socalp
, 0);
2788 return (FCAL_TRANSPORT_SUCCESS
);
2792 socal_doit(fcal_packet_t
*fcalpkt
, socal_port_t
*port_statep
, int polled
,
2793 void (*func
)(), int timo
, int flag
, uint_t
*diagcode
)
2796 uint32_t retval
, status
;
2797 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
2800 fcalpkt
->fcal_pkt_comp
= NULL
;
2801 status
= socal_transport_poll(fcalpkt
, timo
, CQ_REQUEST_0
);
2803 fcalpkt
->fcal_pkt_comp
= func
;
2804 mutex_enter(&port_statep
->sp_mtx
);
2805 port_statep
->sp_status
|= flag
;
2806 if ((status
= socal_transport(fcalpkt
, FCAL_NOSLEEP
,
2807 CQ_REQUEST_0
)) == FCAL_TRANSPORT_SUCCESS
) {
2808 lb
= ddi_get_lbolt();
2809 while (!(fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)) {
2810 if ((retval
= cv_timedwait(&port_statep
->sp_cv
,
2811 &port_statep
->sp_mtx
,
2812 lb
+drv_usectohz(timo
))) == -1) {
2813 status
= FCAL_TRANSPORT_TIMEOUT
;
2818 port_statep
->sp_status
&= ~flag
;
2819 mutex_exit(&port_statep
->sp_mtx
);
2823 case FCAL_TRANSPORT_SUCCESS
:
2824 status
= fcalpkt
->fcal_pkt_status
;
2826 *diagcode
= fcalpkt
->fcal_diag_status
;
2828 case FCAL_STATUS_ABORT_FAILED
:
2829 if (flag
== PORT_ABORT_PENDING
)
2830 retval
= FCAL_ABORT_FAILED
;
2832 case FCAL_STATUS_OK
:
2833 if (flag
== PORT_ABORT_PENDING
)
2834 retval
= FCAL_ABORT_FAILED
;
2836 retval
= FCAL_SUCCESS
;
2838 case FCAL_STATUS_OLD_PORT
:
2839 retval
= FCAL_OLD_PORT
;
2841 case FCAL_STATUS_ERR_OFFLINE
:
2842 retval
= FCAL_OFFLINE
;
2844 case FCAL_STATUS_ABORTED
:
2845 retval
= FCAL_ABORTED
;
2846 port_statep
->sp_board
->
2847 socal_stats
.pstats
[port_statep
2848 ->sp_port
].abts_ok
++;
2850 case FCAL_STATUS_BAD_XID
:
2851 retval
= FCAL_BAD_ABORT
;
2853 case FCAL_STATUS_BAD_DID
:
2854 retval
= FCAL_BAD_PARAMS
;
2856 case FCAL_STATUS_DIAG_BUSY
:
2857 case FCAL_STATUS_DIAG_INVALID
:
2861 retval
= FCAL_LINK_ERROR
;
2864 case FCAL_TRANSPORT_TIMEOUT
:
2865 if (flag
== PORT_LIP_PENDING
||
2866 flag
== PORT_LILP_PENDING
) {
2868 (socal_core
& SOCAL_FAILED_LIP
)) {
2870 socal_take_core(socalp
);
2872 socal_disp_err(socalp
, CE_WARN
, "link.6040",
2873 "SOCAL:Forcing SOC+ reset as LIP timed out\n");
2874 /* restart socal after resetting */
2875 (void) socal_force_reset(port_statep
->sp_board
,
2876 polled
, RESET_PORT
);
2879 (void) socal_force_lip(port_statep
->sp_board
,
2880 port_statep
->sp_port
, polled
,
2882 retval
= FCAL_TIMEOUT
;
2884 case FCAL_TRANSPORT_FAILURE
:
2885 case FCAL_BAD_PACKET
:
2886 case FCAL_TRANSPORT_UNAVAIL
:
2887 case FCAL_TRANSPORT_QFULL
:
2891 retval
= FCAL_LINK_ERROR
;
2893 socal_packet_free(fcalpkt
);
2898 socal_lilp_map(void *ssp
, uint_t port
, uint32_t bufid
, uint_t polled
)
2900 fcal_packet_t
*fcalpkt
;
2901 soc_data_request_t
*sdr
;
2902 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2903 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2906 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
2907 == (fcal_packet_t
*)NULL
)
2908 return (FCAL_ALLOC_FAILED
);
2910 sdr
= (soc_data_request_t
*)&fcalpkt
->fcal_socal_request
;
2912 sdr
->sdr_soc_hdr
.sh_flags
= SOC_PORT_B
;
2913 sdr
->sdr_soc_hdr
.sh_seg_cnt
= 1;
2914 sdr
->sdr_soc_hdr
.sh_byte_cnt
= 132;
2915 sdr
->sdr_dataseg
[0].fc_base
= bufid
;
2916 sdr
->sdr_dataseg
[0].fc_count
= 132;
2917 sdr
->sdr_cqhdr
.cq_hdr_count
= 1;
2918 sdr
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_REPORT_MAP
;
2919 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
2921 return (socal_doit(fcalpkt
, port_statep
, polled
, socal_lilp_map_done
,
2922 SOCAL_LILP_TIMEOUT
, PORT_LILP_PENDING
, NULL
));
2926 socal_force_lip(void *ssp
, uint_t port
, uint_t polled
, uint_t lip_req
)
2928 fcal_packet_t
*fcalpkt
;
2929 soc_cmdonly_request_t
*scr
;
2930 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2931 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2934 if (lip_req
== FCAL_NO_LIP
) {
2935 mutex_enter(&port_statep
->sp_mtx
);
2936 if ((port_statep
->sp_status
& PORT_ONLINE_LOOP
) &&
2937 (port_statep
->sp_unsol_cb
->statec_cb
!= NULL
)) {
2938 mutex_exit(&port_statep
->sp_mtx
);
2939 (*port_statep
->sp_unsol_cb
->statec_cb
)
2940 (port_statep
->sp_unsol_cb
->arg
,
2941 FCAL_STATUS_LOOP_ONLINE
);
2942 return (FCAL_SUCCESS
);
2945 mutex_exit(&port_statep
->sp_mtx
);
2947 socalp
->socal_stats
.pstats
[port
].lips
++;
2949 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
2950 == (fcal_packet_t
*)NULL
)
2951 return (FCAL_ALLOC_FAILED
);
2953 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
2955 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
2956 scr
->scr_cqhdr
.cq_hdr_count
= 1;
2957 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_REQUEST_LIP
;
2959 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
2960 return (socal_doit(fcalpkt
, port_statep
, polled
, socal_force_lip_done
,
2961 SOCAL_LIP_TIMEOUT
, PORT_LIP_PENDING
, NULL
));
2965 socal_abort_cmd(void *ssp
, uint_t port
, fcal_packet_t
*fcalpkt
, uint_t polled
)
2967 fcal_packet_t
*fcalpkt2
, *fpkt
;
2968 soc_cmdonly_request_t
*scr
, *tscr
;
2969 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
2970 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
2973 socalp
->socal_stats
.pstats
[port
].abts
++;
2974 kcq
= &socalp
->request
[CQ_REQUEST_1
];
2975 mutex_enter(&kcq
->skc_mtx
);
2976 fcalpkt2
= kcq
->skc_overflowh
;
2978 while (fcalpkt2
!= NULL
) {
2979 if (fcalpkt2
== fcalpkt
) {
2981 kcq
->skc_overflowh
= fcalpkt
->fcal_pkt_next
;
2983 fpkt
->fcal_pkt_next
= fcalpkt
->fcal_pkt_next
;
2984 if (kcq
->skc_overflowt
== fcalpkt
)
2985 kcq
->skc_overflowt
= fpkt
;
2987 mutex_exit(&kcq
->skc_mtx
);
2988 socalp
->socal_stats
.pstats
[port
].abts_ok
++;
2989 SOCAL_ID_FREE(fcalpkt
->fcal_socal_request
.
2990 sr_soc_hdr
.sh_request_token
);
2991 return (FCAL_ABORTED
);
2994 fcalpkt2
= fcalpkt2
->fcal_pkt_next
;
2997 mutex_exit(&kcq
->skc_mtx
);
2999 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
3000 == (fcal_packet_t
*)NULL
)
3001 return (FCAL_ALLOC_FAILED
);
3003 mutex_enter(&socalp
->abort_mtx
);
3005 if (fcalpkt
->fcal_pkt_flags
& FCFLAG_COMPLETE
) {
3006 socal_packet_free(fcalpkt2
);
3007 mutex_exit(&socalp
->abort_mtx
);
3008 return (FCAL_ABORTED
);
3009 /* I lied. So shoot me. */
3011 /* Mark packet as being aborted and put it in the abort pending list. */
3012 fcalpkt
->fcal_pkt_flags
|= FCFLAG_ABORTING
;
3014 scr
= (soc_cmdonly_request_t
*)&fcalpkt2
->fcal_socal_request
;
3015 tscr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
3016 scr
->scr_soc_hdr
.sh_byte_cnt
= tscr
->scr_soc_hdr
.sh_request_token
;
3017 scr
->scr_cqhdr
.cq_hdr_count
= 1;
3018 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_REQUEST_ABORT
;
3020 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
3021 fcalpkt2
->fcal_pkt_cookie
= (void *)socalp
;
3022 mutex_exit(&socalp
->abort_mtx
);
3024 return (socal_doit(fcalpkt2
, port_statep
, polled
, socal_abort_done
,
3025 SOCAL_ABORT_TIMEOUT
, PORT_ABORT_PENDING
, NULL
));
3030 socal_els(void *ssp
, uint_t port
, uint_t elscode
, uint_t dest
,
3031 void (*callback
)(), void *arg
, caddr_t reqpl
, caddr_t
*rsppl
,
3034 return (FCAL_TRANSPORT_FAILURE
);
3038 socal_bypass_dev(void *ssp
, uint_t port
, uint_t dest
)
3040 fcal_packet_t
*fcalpkt
;
3041 soc_cmdonly_request_t
*scr
;
3042 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3043 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
3046 socal_packet_alloc(socalp
, FCAL_SLEEP
))
3047 == (fcal_packet_t
*)NULL
)
3048 return (FCAL_ALLOC_FAILED
);
3050 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
3052 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
3053 scr
->scr_soc_hdr
.sh_byte_cnt
= dest
;
3054 scr
->scr_cqhdr
.cq_hdr_count
= 1;
3055 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_BYPASS_DEV
;
3056 return (socal_doit(fcalpkt
, port_statep
, 0, socal_bypass_dev_done
,
3057 SOCAL_BYPASS_TIMEOUT
, PORT_BYPASS_PENDING
, NULL
));
3063 socal_force_reset(void *ssp
, uint_t port
, uint_t restart
)
3065 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3067 mutex_enter(&socalp
->k_imr_mtx
);
3068 if (socalp
->socal_shutdown
) {
3069 mutex_exit(&socalp
->k_imr_mtx
);
3072 socalp
->socal_shutdown
= 1;
3073 mutex_exit(&socalp
->k_imr_mtx
);
3075 socalp
->socal_stats
.resets
++;
3076 socal_doreset(socalp
);
3078 if (socal_start(socalp
) != FCAL_SUCCESS
) {
3079 cmn_err(CE_WARN
, "socal: start failed.\n");
3086 socal_add_ulp(void *ssp
, uint_t port
, uchar_t type
,
3087 void (*ulp_statec_callback
)(), void (*ulp_els_callback
)(),
3088 void (*ulp_data_callback
)(), void *arg
)
3090 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3091 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
3092 socal_unsol_cb_t
*cbentry
;
3094 mutex_enter(&port_statep
->sp_mtx
);
3095 for (cbentry
= port_statep
->sp_unsol_cb
; cbentry
;
3096 cbentry
= cbentry
->next
) {
3097 if (cbentry
->type
== type
) {
3098 cbentry
->statec_cb
= ulp_statec_callback
;
3099 cbentry
->els_cb
= ulp_els_callback
;
3100 cbentry
->data_cb
= ulp_data_callback
;
3102 mutex_exit(&port_statep
->sp_mtx
);
3106 mutex_exit(&port_statep
->sp_mtx
);
3108 (socal_unsol_cb_t
*)kmem_zalloc(sizeof (socal_unsol_cb_t
),
3109 KM_SLEEP
)) == (socal_unsol_cb_t
*)NULL
) {
3112 mutex_enter(&port_statep
->sp_mtx
);
3113 cbentry
->statec_cb
= ulp_statec_callback
;
3114 cbentry
->els_cb
= ulp_els_callback
;
3115 cbentry
->data_cb
= ulp_data_callback
;
3117 cbentry
->type
= type
;
3119 cbentry
->next
= port_statep
->sp_unsol_cb
;
3120 port_statep
->sp_unsol_cb
= cbentry
;
3121 mutex_exit(&port_statep
->sp_mtx
);
3126 * remove a ULP with matching type and arg
3129 socal_remove_ulp(void *ssp
, uint_t port
, uchar_t type
, void *arg
)
3131 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
3132 socal_port_t
*port_statep
;
3133 socal_unsol_cb_t
*cbentry
;
3134 socal_unsol_cb_t
*p_cbentry
;
3137 ASSERT(ssp
!= NULL
);
3138 port_statep
= &socalp
->port_state
[port
];
3139 ASSERT(port_statep
!= NULL
);
3141 /* scan the list of unsolicited callback entries */
3142 mutex_enter(&port_statep
->sp_mtx
);
3144 for (cbentry
= port_statep
->sp_unsol_cb
;
3146 p_cbentry
= cbentry
, cbentry
= cbentry
->next
) {
3147 if ((cbentry
->type
!= type
) || (cbentry
->arg
!= arg
)) {
3148 continue; /* this entry doesn't match */
3150 /* found entry to remove */
3151 if (port_statep
->sp_unsol_cb
== cbentry
) {
3152 /* remove first entry in list */
3153 port_statep
->sp_unsol_cb
= cbentry
->next
;
3155 /* remove other entry in list */
3157 p_cbentry
->next
= cbentry
->next
;
3159 kmem_free((void *)cbentry
, sizeof (socal_unsol_cb_t
));
3160 DEBUGF(2, (CE_CONT
, "socal port %d ULP removed\n", port
));
3163 mutex_exit(&port_statep
->sp_mtx
);
3168 * static unsigned int
3169 * socal_intr() - this is the interrupt routine for the SOC. Process all
3170 * possible incoming interrupts from the soc device.
3174 socal_intr(caddr_t arg
)
3176 socal_state_t
*socalp
= (socal_state_t
*)arg
;
3177 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3180 int instance
= ddi_get_instance(socalp
->dip
);
3183 struct fcal_packet
*fpkt
, *nfpkt
;
3185 csr
= socalreg
->socal_csr
.w
;
3186 cause
= (int)SOCAL_INTR_CAUSE(socalp
, csr
);
3189 "socal%d: intr: csr: 0x%x cause: 0x%x\n",
3190 instance
, csr
, cause
));
3193 socalp
->socal_on_intr
= 0;
3194 return (DDI_INTR_UNCLAIMED
);
3197 socalp
->socal_on_intr
= 1;
3202 * Process the unsolicited messages first in case there are some
3203 * high priority async events that we should act on.
3207 if (cause
& SOCAL_CSR_RSP_QUE_1
) {
3208 socal_intr_unsolicited(socalp
, 1);
3209 DEBUGF(4, (CE_CONT
, "socal%d intr: did unsolicited\n", instance
));
3212 if (cause
& SOCAL_CSR_RSP_QUE_0
) {
3213 socal_intr_solicited(socalp
, 0);
3214 DEBUGF(4, (CE_CONT
, "socal%d intr: did solicited\n", instance
));
3218 * for use with token-only response queues in the future
3219 * if (cause & SOCAL_CSR_RSP_QUE_0) {
3220 * socal_intr_solicited(socalp, 0);
3226 * Process any request interrupts
3227 * We only allow request interrupts when the request
3228 * queue is full and we are waiting so we can enque
3231 if ((request
= (cause
& SOCAL_CSR_HOST_TO_SOCAL
)) != 0) {
3232 socalp
->socal_stats
.reqq_intrs
++;
3233 for (i
= SOCAL_CSR_1ST_H_TO_S
, j
= 0; j
< SOCAL_N_CQS
;
3236 socal_kcq_t
*kcq
= &socalp
->request
[j
];
3238 if (kcq
->skc_full
) {
3239 mutex_enter(&kcq
->skc_mtx
);
3240 full
= kcq
->skc_full
;
3242 while ((fpkt
= kcq
->skc_overflowh
) != NULL
) {
3243 nfpkt
= fpkt
->fcal_pkt_next
;
3244 fpkt
->fcal_pkt_next
= NULL
;
3245 kcq
->skc_overflowh
= nfpkt
;
3246 if (socal_cq_enque(socalp
, (socal_port_t
*)
3247 fpkt
->fcal_pkt_cookie
,
3248 (cqe_t
*)&fpkt
->fcal_socal_request
,
3249 j
, FCAL_NOSLEEP
, NULL
, 1) !=
3250 FCAL_TRANSPORT_SUCCESS
) {
3254 if (!kcq
->skc_overflowh
) {
3255 if (full
& SOCAL_SKC_SLEEP
)
3256 cv_broadcast(&kcq
->skc_cv
);
3258 /* Disable this queue's intrs */
3260 "socal%d: req que %d overflow cleared\n",
3262 mutex_enter(&socalp
->k_imr_mtx
);
3263 socalp
->socal_rp
->socal_imr
=
3264 (socalp
->socal_k_imr
&= ~i
);
3265 mutex_exit(&socalp
->k_imr_mtx
);
3267 mutex_exit(&kcq
->skc_mtx
);
3272 csr
= socalreg
->socal_csr
.w
;
3273 cause
= (int)SOCAL_INTR_CAUSE(socalp
, csr
);
3274 DEBUGF(4, (CE_CONT
, "socal%d intr: did request queues\n", instance
));
3278 socalp
->socal_on_intr
= 0;
3279 return (DDI_INTR_CLAIMED
);
3283 socal_intr_solicited(socal_state_t
*socalp
, uint32_t srq
)
3286 volatile socal_kcq_t
*kcqv
;
3287 soc_response_t
*srp
;
3290 fcal_packet_t
*fcalpkt
= NULL
;
3292 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3299 #if defined(DEBUG) && !defined(lint)
3300 int instance
= ddi_get_instance(socalp
->dip
);
3304 kcq
= &socalp
->response
[srq
];
3305 kcqv
= (volatile socal_kcq_t
*)kcq
;
3306 DEBUGF(4, (CE_CONT
, "socal%d intr_sol: entered \n", instance
));
3309 * Grab lock for request queue.
3311 mutex_enter(&kcq
->skc_mtx
);
3314 * Process as many response queue entries as we can.
3316 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3318 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3320 if (index_in
== kcqv
->skc_out
) {
3321 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3322 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_0
));
3324 /* make sure the write completed */
3325 i
= socalreg
->socal_csr
.w
;
3327 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3330 kcqv
->skc_in
= index_in
;
3332 while (kcqv
->skc_out
!= index_in
) {
3333 /* Find out where the newest entry lives in the queue */
3334 (void) ddi_dma_sync(kcq
->skc_dhandle
, 0, 0,
3335 DDI_DMA_SYNC_FORKERNEL
);
3337 srp
= (soc_response_t
*)cqe
;
3338 port
= srp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
;
3339 shp
= &srp
->sr_soc_hdr
;
3340 cq_hdr
= &srp
->sr_cqhdr
;
3342 * It turns out that on faster CPU's we have a problem where
3343 * the soc interrupts us before the response has been DMA'ed
3344 * in. This should not happen but does !!. So to workaround
3345 * the problem for now, check the sequence # of the response.
3346 * If it does not match with what we have, we must be
3347 * reading stale data
3349 if (cq_hdr
->cq_hdr_seqno
!= kcqv
->skc_seqno
) {
3350 #if defined(DEBUG) && !defined(lint)
3351 socal_read_stale_data
++;
3353 if (kcq
->deferred_intr_timeoutid
) {
3354 mutex_exit(&kcq
->skc_mtx
);
3357 kcq
->skc_saved_out
= kcqv
->skc_out
;
3358 kcq
->skc_saved_seqno
= kcqv
->skc_seqno
;
3359 kcq
->deferred_intr_timeoutid
= timeout(
3360 socal_deferred_intr
, (caddr_t
)kcq
,
3361 drv_usectohz(10000));
3362 mutex_exit(&kcq
->skc_mtx
);
3367 fcalpkt
= (fcal_packet_t
*)
3368 SOCAL_ID_LOOKUP(shp
->sh_request_token
);
3370 if ((socal_core
& SOCAL_TAKE_CORE
) && ddi_peek8(socalp
->dip
,
3371 (char *)fcalpkt
, &val
) != DDI_SUCCESS
) {
3372 cmn_err(CE_WARN
, "bad token = %p\n", (void *)fcalpkt
);
3373 mutex_exit(&kcq
->skc_mtx
);
3374 socal_take_core(socalp
);
3377 if ((fcalpkt
== (fcal_packet_t
*)NULL
) ||
3378 (fcalpkt
->fcal_magic
!= FCALP_MAGIC
)) {
3379 (void) sprintf(buf
, "!invalid FC packet; \n\
3380 in, out, seqno = 0x%x, 0x%x, 0x%x\n",
3381 kcqv
->skc_in
, kcqv
->skc_out
, kcqv
->skc_seqno
);
3382 socal_disp_err(socalp
, CE_WARN
, "link.4060", buf
);
3384 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3385 socalreg
->socal_cr
.w
,
3386 socalreg
->socal_sae
.w
,
3387 socalreg
->socal_csr
.w
,
3388 socalreg
->socal_imr
));
3390 * Update response queue ptrs and soc registers.
3393 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3400 DEBUGF(2, (CE_CONT
, "packet 0x%p complete\n",
3402 status
= srp
->sr_soc_status
;
3403 fcalpkt
->fcal_pkt_status
= status
;
3404 DEBUGF(2, (CE_CONT
, "SOC status: 0x%x\n", status
));
3406 * map soc status codes to
3407 * transport status codes
3410 ASSERT((fcalpkt
->fcal_cmd_state
& FCAL_CMD_COMPLETE
)
3412 mutex_enter(&socalp
->abort_mtx
);
3413 fcalpkt
->fcal_pkt_flags
|= FCFLAG_COMPLETE
;
3414 mutex_exit(&socalp
->abort_mtx
);
3417 * Copy the response frame header (if there is one)
3418 * so that the upper levels can use it. Note that,
3419 * for now, we'll copy the header only if there was
3420 * some sort of non-OK status, to save the PIO reads
3421 * required to get the header from the host adapter's
3424 if (((status
!= FCAL_STATUS_OK
) ||
3425 (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
3426 & SOC_RESP_HEADER
)) &&
3427 (srp
->sr_soc_hdr
.sh_flags
& SOC_FC_HEADER
)) {
3428 src
= (caddr_t
)&srp
->sr_fc_frame_hdr
;
3429 dst
= (caddr_t
)&fcalpkt
->fcal_resp_hdr
;
3430 bcopy(src
, dst
, sizeof (fc_frame_header_t
));
3431 fcalpkt
->fcal_pkt_flags
|= FCFLAG_RESP_HEADER
;
3432 i
= srp
->sr_soc_hdr
.sh_flags
& SOC_PORT_B
?
3434 if ((status
!= FCAL_STATUS_OK
) &&
3435 (status
<= FCAL_STATUS_MAX_STATUS
)) {
3436 socalp
->socal_stats
.pstats
[i
].
3437 resp_status
[status
]++;
3439 socalp
->socal_stats
.pstats
[i
].
3440 resp_status
[FCAL_STATUS_ERROR
]++;
3442 } else if (status
== FCAL_STATUS_OK
) {
3443 fcalpkt
->fcal_socal_request
.
3444 sr_soc_hdr
.sh_byte_cnt
=
3447 fcalpkt
->fcal_diag_status
=
3448 (uint32_t)srp
->sr_dataseg
.fc_base
;
3449 fcalpkt
->fcal_ncmds
= srp
->sr_ncmds
;
3452 * Update response queue ptrs and soc registers.
3455 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3460 /* For incmplt DMA offline loop by loopback */
3461 if (fcalpkt
->fcal_pkt_status
==
3462 FCAL_STATUS_INCOMPLETE_DMA_ERR
) {
3463 socal_port_t
*port_statep
;
3467 * Give up the mutex to avoid a deadlock
3468 * with the loopback routine.
3470 mutex_exit(&kcq
->skc_mtx
);
3472 port_statep
= &socalp
->port_state
[port
];
3473 mutex_enter(&port_statep
->sp_mtx
);
3474 if (port_statep
->sp_status
&
3476 /* Already disabled */
3477 mutex_exit(&port_statep
->sp_mtx
);
3479 port_statep
->sp_status
|=
3481 mutex_exit(&port_statep
->sp_mtx
);
3482 (void) socal_diag_request(
3483 (void *)socalp
, port
,
3484 &r
, SOC_DIAG_INT_LOOP
);
3486 /* reacquire mutex */
3487 mutex_enter(&kcq
->skc_mtx
);
3491 * Complete the packet *ONLY* if it not being aborted
3492 * or the abort has already completed. Otherwise it is
3493 * not safe to free the ID.
3495 mutex_enter(&socalp
->abort_mtx
);
3496 if (!(fcalpkt
->fcal_pkt_flags
& FCFLAG_ABORTING
)) {
3498 * Call the completion routine
3500 SOCAL_ID_FREE(shp
->sh_request_token
);
3501 if (fcalpkt
->fcal_pkt_comp
!= NULL
) {
3502 fcalpkt
->fcal_cmd_state
|=
3506 * Give up the mutex to avoid a
3507 * deadlock with the callback routine.
3509 mutex_exit(&socalp
->abort_mtx
);
3510 mutex_exit(&kcq
->skc_mtx
);
3513 (*fcalpkt
->fcal_pkt_comp
)(fcalpkt
);
3515 /* reacquire mutex */
3516 mutex_enter(&kcq
->skc_mtx
);
3518 fcalpkt
->fcal_cmd_state
|=
3520 mutex_exit(&socalp
->abort_mtx
);
3523 mutex_exit(&socalp
->abort_mtx
);
3528 if (kcq
->skc_cq
== NULL
)
3530 * This action averts a potential PANIC scenario
3531 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3532 * when we let it go, to call our completion routine,
3533 * and "initialized" the response queue. We exit our
3534 * processing loop here, thereby averting a PANIC due
3535 * to a NULL de-reference from the response queue.
3537 * Note that this is an interim measure that needs
3538 * to be revisited when this driver is next revised
3539 * for enhanced performance.
3544 * We need to re-read the input and output pointers in
3545 * case a polling routine should process some entries
3546 * from the response queue while we're doing a callback
3547 * routine with the response queue mutex dropped.
3549 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3550 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3553 * Mess around with the hardware if we think we've run out
3554 * of entries in the queue, just to make sure we've read
3555 * all entries that are available.
3558 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3559 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_0
));
3561 /* Make sure the csr write has completed */
3562 i
= socalreg
->socal_csr
.w
;
3563 DEBUGF(9, (CE_CONT
, "csr.w = %x\n", i
));
3566 * Update our idea of where the host adapter has placed
3567 * the most recent entry in the response queue and resync
3568 * the response queue
3570 index_in
= SOCAL_RESPONSEQ_INDEX(srq
, socalreg
->socal_rspp
.w
);
3572 kcqv
->skc_in
= index_in
;
3575 /* Drop lock for request queue. */
3576 mutex_exit(&kcq
->skc_mtx
);
3580 * Function name : socal_intr_unsolicited()
3582 * Return Values : none
3584 * Description : Processes entries in the unsolicited response
3587 * The SOC+ will give us an unsolicited response
3588 * whenever its status changes: OFFLINE, ONLINE,
3589 * or in response to a packet arriving from an originator.
3591 * When message requests come in they will be placed in our
3592 * buffer queue or in the next "inline" packet by the SOC hardware.
3594 * Context : Unsolicited interrupts must be masked
3598 socal_intr_unsolicited(socal_state_t
*socalp
, uint32_t urq
)
3601 volatile socal_kcq_t
*kcqv
;
3602 soc_response_t
*srp
;
3603 volatile cqe_t
*cqe
;
3605 register uchar_t t_index
, t_seqno
;
3606 register volatile socal_reg_t
*socalreg
= socalp
->socal_rp
;
3607 volatile cqe_t
*cqe_cont
= NULL
;
3613 socal_port_t
*port_statep
;
3614 #if defined(DEBUG) && !defined(lint)
3615 int instance
= ddi_get_instance(socalp
->dip
);
3618 socal_unsol_cb_t
*cblist
;
3620 kcq
= &socalp
->response
[urq
];
3621 kcqv
= (volatile socal_kcq_t
*)kcq
;
3624 * Grab lock for response queue.
3626 mutex_enter(&kcq
->skc_mtx
);
3628 cqe
= (volatile cqe_t
*)&(kcq
->skc_cq
[kcqv
->skc_out
]);
3630 index_in
= SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3632 kcqv
->skc_in
= index_in
;
3634 while (kcqv
->skc_out
!= index_in
) {
3635 (void) ddi_dma_sync(kcq
->skc_dhandle
, 0, 0,
3636 DDI_DMA_SYNC_FORKERNEL
);
3638 /* Check for continuation entries */
3639 if ((hdr_count
= cqe
->cqe_hdr
.cq_hdr_count
) != 1) {
3641 t_seqno
= kcqv
->skc_seqno
;
3642 t_index
= kcqv
->skc_out
+ hdr_count
;
3645 if (kcqv
->skc_out
> index_in
)
3646 i
+= kcq
->skc_last_index
+ 1;
3649 * If we think the continuation entries haven't yet
3650 * arrived, try once more before giving up
3654 socalreg
->socal_csr
.w
=
3655 ((kcqv
->skc_out
<< 24) |
3656 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3658 /* Make sure the csr write has completed */
3659 i
= socalreg
->socal_csr
.w
;
3662 * Update our idea of where the host adapter has placed
3663 * the most recent entry in the response queue
3665 i
= index_in
= SOCAL_RESPONSEQ_INDEX(urq
,
3666 socalreg
->socal_rspp
.w
);
3667 if (kcqv
->skc_out
> index_in
)
3668 i
+= kcq
->skc_last_index
+ 1;
3671 * Exit if the continuation entries haven't yet
3678 if (t_index
> kcq
->skc_last_index
) {
3680 t_index
&= kcq
->skc_last_index
;
3683 cqe_cont
= (volatile cqe_t
*)
3684 &(kcq
->skc_cq
[t_index
? t_index
- 1 :
3685 kcq
->skc_last_index
]);
3688 /* A cq_hdr_count > 2 is illegal; throw away the response */
3691 * XXX - should probably throw out as many entries as the
3692 * hdr_cout tells us there are
3694 if (hdr_count
!= 2) {
3695 socal_disp_err(socalp
, CE_WARN
, "driver.4030",
3696 "!too many continuation entries");
3698 "socal%d: soc+ unsolicited entry count = %d\n",
3699 instance
, cqe
->cqe_hdr
.cq_hdr_count
));
3701 if ((++t_index
& kcq
->skc_last_index
) == 0) {
3705 kcqv
->skc_out
= t_index
;
3706 kcqv
->skc_seqno
= t_seqno
;
3708 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3715 * Update unsolicited response queue ptrs
3718 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3723 if (cqe_cont
!= NULL
) {
3725 if ((kcqv
->skc_out
& kcq
->skc_last_index
) == 0) {
3731 if (index_in
== kcqv
->skc_out
) {
3732 socalreg
->socal_csr
.w
= ((kcqv
->skc_out
<< 24) |
3733 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3735 /* Make sure the csr write has completed */
3736 i
= socalreg
->socal_csr
.w
;
3739 srp
= (soc_response_t
*)cqe
;
3740 flags
= srp
->sr_soc_hdr
.sh_flags
;
3741 port
= flags
& SOC_PORT_B
;
3742 port_statep
= &socalp
->port_state
[port
];
3745 * XXX need to deal buffer pool entries here
3747 switch (flags
& ~SOC_PORT_B
) {
3748 case SOC_UNSOLICITED
| SOC_FC_HEADER
:
3750 srp
= (soc_response_t
*)cqe
;
3752 switch (srp
->sr_fc_frame_hdr
.r_ctl
& R_CTL_ROUTING
) {
3753 case R_CTL_EXTENDED_SVC
:
3755 * Extended Link Services frame received
3757 socalp
->socal_stats
.pstats
[port
].els_rcvd
++;
3758 socal_us_els(socalp
, (cqe_t
*)cqe
, (caddr_t
)cqe_cont
);
3760 /* do callbacks to any interested ULPs */
3761 mutex_enter(&port_statep
->sp_mtx
);
3762 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3763 cblist
= cblist
->next
) {
3764 if (cblist
->els_cb
) {
3765 mutex_exit(&port_statep
->sp_mtx
);
3766 mutex_exit(&kcq
->skc_mtx
);
3767 cblist
->els_cb(cblist
->arg
,
3770 mutex_enter(&kcq
->skc_mtx
);
3771 mutex_enter(&port_statep
->sp_mtx
);
3774 mutex_exit(&port_statep
->sp_mtx
);
3776 case R_CTL_BASIC_SVC
:
3778 "!unsupported Link Service command: 0x%x",
3779 srp
->sr_fc_frame_hdr
.type
);
3780 socal_disp_err(socalp
, CE_WARN
, "link.4020", buf
);
3782 case R_CTL_DEVICE_DATA
:
3783 switch (srp
->sr_fc_frame_hdr
.type
) {
3785 mutex_enter(&port_statep
->sp_mtx
);
3787 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3788 cblist
= cblist
->next
) {
3789 if (cblist
->data_cb
&&
3791 srp
->sr_fc_frame_hdr
.type
)) {
3792 mutex_exit(&port_statep
->sp_mtx
);
3793 mutex_exit(&kcq
->skc_mtx
);
3794 cblist
->data_cb(cblist
->arg
,
3795 (cqe_t
*)cqe
, (caddr_t
)cqe_cont
);
3796 mutex_enter(&kcq
->skc_mtx
);
3797 mutex_enter(&port_statep
->sp_mtx
);
3801 mutex_exit(&port_statep
->sp_mtx
);
3807 "!unknown FC-4 command: 0x%x",
3808 srp
->sr_fc_frame_hdr
.type
);
3809 socal_disp_err(socalp
, CE_WARN
,
3815 (void) sprintf(buf
, "!unsupported FC frame R_CTL: 0x%x",
3816 srp
->sr_fc_frame_hdr
.r_ctl
);
3817 socal_disp_err(socalp
, CE_WARN
, "link.4040", buf
);
3825 * Note that only the lsbyte of the status has
3826 * interesting information...
3828 status
= srp
->sr_soc_status
;
3832 case FCAL_STATUS_ONLINE
:
3834 "!port %d: Fibre Channel is ONLINE\n", port
);
3835 socal_disp_err(socalp
, CE_CONT
, "link.6010",
3837 mutex_enter(&port_statep
->sp_mtx
);
3838 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3839 port_statep
->sp_status
|= PORT_ONLINE
;
3840 mutex_exit(&port_statep
->sp_mtx
);
3841 socalp
->socal_stats
.pstats
[port
].onlines
++;
3843 "socal%d intr_unsol: ONLINE intr\n",
3847 case FCAL_STATUS_LOOP_ONLINE
:
3849 "!port %d: Fibre Channel Loop is ONLINE\n",
3851 socal_disp_err(socalp
, CE_CONT
, "link.6010",
3853 mutex_enter(&port_statep
->sp_mtx
);
3854 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3855 port_statep
->sp_status
|= PORT_ONLINE_LOOP
;
3856 mutex_exit(&port_statep
->sp_mtx
);
3857 socalp
->socal_stats
.pstats
[port
].online_loops
++;
3859 "socal%d intr_unsol: ONLINE-LOOP intr\n",
3863 case FCAL_STATUS_ERR_OFFLINE
:
3865 * SOC and Responder will both flush
3866 * all active commands.
3867 * So I don't have to do anything
3868 * until it comes back online.
3871 "!port %d: Fibre Channel is OFFLINE\n", port
);
3872 socal_disp_err(socalp
, CE_CONT
, "link.5010",
3875 mutex_enter(&port_statep
->sp_mtx
);
3876 port_statep
->sp_status
&= ~PORT_STATUS_MASK
;
3877 port_statep
->sp_status
|= PORT_OFFLINE
;
3878 port_statep
->sp_lilpmap_valid
= 0;
3879 mutex_exit(&port_statep
->sp_mtx
);
3880 socalp
->socal_stats
.pstats
[port
].offlines
++;
3882 "socal%d intr_unsol: OFFLINE intr\n",
3887 (void) sprintf(buf
, "!unknown status: 0x%x\n",
3889 socal_disp_err(socalp
, CE_WARN
, "link.3020",
3892 mutex_exit(&kcq
->skc_mtx
);
3893 mutex_enter(&port_statep
->sp_mtx
);
3894 for (cblist
= port_statep
->sp_unsol_cb
; cblist
;
3895 cblist
= cblist
->next
) {
3896 if (cblist
->statec_cb
) {
3897 mutex_exit(&port_statep
->sp_mtx
);
3898 (*cblist
->statec_cb
)(cblist
->arg
,
3900 mutex_enter(&port_statep
->sp_mtx
);
3903 mutex_exit(&port_statep
->sp_mtx
);
3904 if (status
== FCAL_STATUS_ERR_OFFLINE
) {
3905 socal_flush_overflowq(socalp
, port
,
3907 socal_flush_overflowq(socalp
, port
,
3910 mutex_enter(&kcq
->skc_mtx
);
3914 (void) sprintf(buf
, "!unexpected state: flags: 0x%x\n",
3916 socal_disp_err(socalp
, CE_WARN
, "link.4050", buf
);
3918 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3919 socalp
->socal_rp
->socal_cr
.w
,
3920 socalp
->socal_rp
->socal_sae
.w
,
3921 socalp
->socal_rp
->socal_csr
.w
,
3922 socalp
->socal_rp
->socal_imr
));
3926 if (kcq
->skc_cq
== NULL
)
3928 * This action averts a potential PANIC scenario
3929 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3930 * when we let it go, to call our completion routine,
3931 * and "initialized" the response queue. We exit our
3932 * processing loop here, thereby averting a PANIC due
3933 * to a NULL de-reference from the response queue.
3935 * Note that this is an interim measure that needs
3936 * to be revisited when this driver is next revised
3937 * for enhanced performance.
3942 * We need to re-read the input and output pointers in
3943 * case a polling routine should process some entries
3944 * from the response queue while we're doing a callback
3945 * routine with the response queue mutex dropped.
3947 cqe
= &(kcq
->skc_cq
[kcqv
->skc_out
]);
3948 index_in
= SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3952 * Mess around with the hardware if we think we've run out
3953 * of entries in the queue, just to make sure we've read
3954 * all entries that are available.
3956 if (index_in
== kcqv
->skc_out
) {
3958 socalreg
->socal_csr
.w
=
3959 ((kcqv
->skc_out
<< 24) |
3960 (SOCAL_CSR_SOCAL_TO_HOST
& ~SOCAL_CSR_RSP_QUE_1
));
3962 /* Make sure the csr write has completed */
3963 i
= socalreg
->socal_csr
.w
;
3966 * Update our idea of where the host adapter has placed
3967 * the most recent entry in the response queue
3970 SOCAL_RESPONSEQ_INDEX(urq
, socalreg
->socal_rspp
.w
);
3973 socalp
->socal_stats
.pstats
[port
].unsol_resps
++;
3975 kcqv
->skc_in
= index_in
;
3979 /* Release lock for response queue. */
3980 mutex_exit(&kcq
->skc_mtx
);
3984 * socal_us_els() - This function handles unsolicited extended link
3985 * service responses received from the soc.
3988 socal_us_els(socal_state_t
*socalp
, cqe_t
*cqe
, caddr_t payload
)
3990 soc_response_t
*srp
= (soc_response_t
*)cqe
;
3991 els_payload_t
*els
= (els_payload_t
*)payload
;
3997 * There should be a CQE continuation entry for all
3998 * extended link services
4000 if ((els
== NULL
) || ((i
= srp
->sr_soc_hdr
.sh_byte_cnt
) == 0)) {
4001 socal_disp_err(socalp
, CE_WARN
, "link.4010",
4002 "!incomplete continuation entry");
4006 /* Quietly impose a maximum byte count */
4007 if (i
> SOC_CQE_PAYLOAD
)
4008 i
= SOC_CQE_PAYLOAD
;
4009 i
-= sizeof (union els_cmd_u
);
4012 * Decode the LS_Command code
4014 switch (els
->els_cmd
.c
.ls_command
) {
4015 case LA_ELS_DISPLAY
:
4016 els
->els_data
[i
] = '\0'; /* terminate the string */
4017 for (bp
= (char *)&(els
->els_data
[0]); *bp
; bp
++) {
4018 /* squash newlines */
4019 if (*bp
== '\n') *bp
= ' ';
4021 (void) sprintf(buf
, "!message: %s\n", els
->els_data
);
4022 socal_disp_err(socalp
, CE_CONT
, "link.1010", buf
);
4026 DEBUGF(3, (CE_CONT
, "!unknown LS_Command, %x\n",
4034 static fcal_packet_t
*
4035 socal_packet_alloc(socal_state_t
*socalp
, fcal_sleep_t sleep
)
4040 if (sleep
== FCAL_SLEEP
)
4045 pkt
= (fcal_packet_t
*)kmem_zalloc(sizeof (fcal_packet_t
), flag
);
4047 if (pkt
!= (fcal_packet_t
*)NULL
)
4048 pkt
->fcal_magic
= FCALP_MAGIC
;
4054 socal_packet_free(fcal_packet_t
*fcalpkt
)
4056 kmem_free((void *)fcalpkt
, sizeof (fcal_packet_t
));
4060 socal_lilp_map_done(fcal_packet_t
*fcalpkt
)
4063 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4065 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4069 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4070 socalp
->port_state
[port
].sp_status
&= ~PORT_LILP_PENDING
;
4071 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4072 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4076 socal_force_lip_done(fcal_packet_t
*fcalpkt
)
4079 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4081 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4085 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4086 socalp
->port_state
[port
].sp_status
&= ~PORT_LIP_PENDING
;
4087 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4088 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4092 socal_adisc_done(fcal_packet_t
*fcalpkt
)
4095 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4097 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4101 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4102 socalp
->port_state
[port
].sp_status
&= ~PORT_ADISC_PENDING
;
4103 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4104 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4108 socal_lbf_done(fcal_packet_t
*fcalpkt
)
4111 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4113 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4117 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4118 socalp
->port_state
[port
].sp_status
&= ~PORT_LBF_PENDING
;
4119 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4120 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4124 socal_rls_done(fcal_packet_t
*fcalpkt
)
4127 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4129 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4133 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4134 socalp
->port_state
[port
].sp_status
&= ~PORT_RLS_PENDING
;
4135 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4136 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4140 socal_force_offline_done(fcal_packet_t
*fcalpkt
)
4143 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4145 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4149 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4150 socalp
->port_state
[port
].sp_status
&= ~PORT_OFFLINE_PENDING
;
4151 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4152 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4156 socal_abort_done(fcal_packet_t
*fcalpkt
)
4159 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4161 (soc_header_t
*)&fcalpkt
->fcal_socal_request
.sr_soc_hdr
;
4162 fcal_packet_t
*target
= (fcal_packet_t
*)
4163 SOCAL_ID_LOOKUP(shp
->sh_request_token
);
4165 mutex_enter(&socalp
->abort_mtx
);
4166 ASSERT(target
->fcal_pkt_flags
& FCFLAG_ABORTING
);
4167 if (!(target
->fcal_pkt_flags
& FCFLAG_COMPLETE
)) {
4168 SOCAL_ID_FREE(shp
->sh_request_token
);
4170 mutex_exit(&socalp
->abort_mtx
);
4171 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4175 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4176 socalp
->port_state
[port
].sp_status
&= ~PORT_ABORT_PENDING
;
4177 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4178 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4182 socal_bypass_dev_done(fcal_packet_t
*fcalpkt
)
4185 socal_state_t
*socalp
= (socal_state_t
*)fcalpkt
->fcal_pkt_cookie
;
4186 if (fcalpkt
->fcal_socal_request
.sr_soc_hdr
.sh_flags
& SOC_PORT_B
)
4190 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
4191 socalp
->port_state
[port
].sp_status
&= ~PORT_BYPASS_PENDING
;
4192 cv_broadcast(&socalp
->port_state
[port
].sp_cv
);
4193 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
4198 socal_dummy_intr(caddr_t arg
)
4200 return (DDI_INTR_UNCLAIMED
);
4204 socal_diag_request(socal_state_t
*socalp
, uint32_t port
, uint_t
*diagcode
,
4207 fcal_packet_t
*fcalpkt
;
4208 soc_diag_request_t
*sdr
;
4209 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
4210 struct fcal_lilp_map map
;
4212 /* Grabbing the state mutex is totally unnecessary.... */
4213 if (!(port_statep
->sp_status
& PORT_DISABLED
)) {
4214 if (socal_getmap(socalp
, port
, (caddr_t
)&map
, 0, FKIOCTL
)
4216 if (map
.lilp_length
!= 1 && ((port_statep
->sp_status
&
4217 PORT_ONLINE_LOOP
) && cmd
!= SOC_DIAG_REM_LOOP
))
4218 return (FCAL_TRANSPORT_UNAVAIL
);
4221 if ((fcalpkt
= socal_packet_alloc(socalp
, FCAL_SLEEP
))
4222 == (fcal_packet_t
*)NULL
)
4223 return (FCAL_ALLOC_FAILED
);
4224 sdr
= (soc_diag_request_t
*)&fcalpkt
->fcal_socal_request
;
4226 sdr
->sdr_soc_hdr
.sh_flags
= SOC_PORT_B
;
4227 sdr
->sdr_diag_cmd
= cmd
;
4228 sdr
->sdr_cqhdr
.cq_hdr_count
= 1;
4229 sdr
->sdr_cqhdr
.cq_hdr_type
= CQ_TYPE_DIAGNOSTIC
;
4230 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4231 return (socal_doit(fcalpkt
, port_statep
, 1, NULL
,
4232 SOCAL_DIAG_TIMEOUT
, 0, diagcode
));
4236 socal_force_offline(void *ssp
, uint_t port
, uint_t polled
)
4238 fcal_packet_t
*fcalpkt
;
4239 soc_cmdonly_request_t
*scr
;
4240 socal_state_t
*socalp
= (socal_state_t
*)ssp
;
4241 socal_port_t
*port_statep
= &socalp
->port_state
[port
];
4244 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4245 == (fcal_packet_t
*)NULL
)
4246 return (FCAL_ALLOC_FAILED
);
4248 scr
= (soc_cmdonly_request_t
*)&fcalpkt
->fcal_socal_request
;
4250 scr
->scr_soc_hdr
.sh_flags
= SOC_PORT_B
;
4251 scr
->scr_cqhdr
.cq_hdr_count
= 1;
4252 scr
->scr_cqhdr
.cq_hdr_type
= CQ_TYPE_OFFLINE
;
4253 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4254 return (socal_doit(fcalpkt
, port_statep
, 0, socal_force_offline_done
,
4255 SOCAL_OFFLINE_TIMEOUT
, PORT_OFFLINE_PENDING
, NULL
));
4259 socal_issue_adisc(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4260 la_els_adisc_t
*payload
, uint32_t polled
)
4263 la_els_adisc_t
*buf
;
4264 fcal_packet_t
*fcalpkt
;
4265 socal_port_t
*port_statep
;
4266 socal_priv_cmd_t
*privp
;
4268 port_statep
= &socalp
->port_state
[port
];
4271 socal_els_alloc(socalp
, port
, dest
, sizeof (la_els_adisc_t
),
4272 sizeof (la_els_adisc_t
), (caddr_t
*)&privp
, polled
))
4273 == (fcal_packet_t
*)NULL
)
4274 return (FCAL_ALLOC_FAILED
);
4276 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4277 buf
= (la_els_adisc_t
*)privp
->cmd
;
4278 buf
->ls_code
= LA_ELS_ADISC
;
4282 buf
->hard_address
= 0;
4283 bcopy((caddr_t
)&port_statep
->sp_p_wwn
,
4284 (caddr_t
)&buf
->port_wwn
, sizeof (buf
->port_wwn
));
4285 bcopy((caddr_t
)&socalp
->socal_n_wwn
,
4286 (caddr_t
)&buf
->node_wwn
, sizeof (buf
->node_wwn
));
4287 buf
->nport_id
= fcalpkt
->fcal_socal_request
.sr_fc_frame_hdr
.s_id
;
4288 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4290 retval
= socal_doit(fcalpkt
, port_statep
, 0, socal_adisc_done
,
4291 SOCAL_ADISC_TIMEOUT
, PORT_ADISC_PENDING
, NULL
);
4292 if (retval
== FCAL_SUCCESS
) {
4293 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4294 DDI_DMA_SYNC_FORKERNEL
);
4295 bcopy(privp
->rsp
, (caddr_t
)payload
, sizeof (la_els_adisc_t
));
4297 privp
->fapktp
= NULL
;
4298 socal_els_free(privp
);
4303 socal_issue_lbf(socal_state_t
*socalp
, uint32_t port
,
4304 uchar_t
*payload
, size_t length
, uint32_t polled
)
4307 fcal_packet_t
*fcalpkt
;
4308 socal_port_t
*port_statep
;
4309 socal_priv_cmd_t
*privp
;
4311 port_statep
= &socalp
->port_state
[port
];
4313 if ((fcalpkt
= socal_lbf_alloc(socalp
, port
, length
, length
,
4314 (caddr_t
*)&privp
, polled
)) == (fcal_packet_t
*)NULL
)
4315 return (FCAL_ALLOC_FAILED
);
4317 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4318 bcopy((caddr_t
)payload
, privp
->cmd
, length
);
4319 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4321 retval
= socal_doit(fcalpkt
, port_statep
, polled
, socal_lbf_done
,
4322 SOCAL_LBF_TIMEOUT
, PORT_LBF_PENDING
, NULL
);
4324 if (retval
== FCAL_SUCCESS
) {
4325 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4326 DDI_DMA_SYNC_FORKERNEL
);
4327 bcopy(privp
->rsp
, (caddr_t
)payload
, length
);
4329 privp
->fapktp
= NULL
;
4330 socal_lbf_free(privp
);
4335 socal_issue_rls(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4336 la_els_rls_reply_t
*payload
, uint32_t polled
)
4340 fcal_packet_t
*fcalpkt
;
4341 socal_port_t
*port_statep
;
4342 socal_priv_cmd_t
*privp
;
4345 port_statep
= &socalp
->port_state
[port
];
4347 if (dest
== socal_getmap(socalp
, port
, NULL
, 0, 0)) {
4348 /* load up the the struct with the local lesb */
4349 struct la_els_rjt
*rsp
= (struct la_els_rjt
*)payload
;
4351 rsp
->ls_code
= LA_ELS_RJT
;
4355 rsp
->reason_code
= RJT_UNSUPPORTED
;
4357 rsp
->explanation
= 0;
4359 return (FCAL_SUCCESS
);
4363 socal_els_alloc(socalp
, port
, dest
, sizeof (la_els_rls_t
),
4364 sizeof (la_els_rls_reply_t
), (caddr_t
*)&privp
, polled
))
4365 == (fcal_packet_t
*)NULL
)
4366 return (FCAL_ALLOC_FAILED
);
4368 privp
= (socal_priv_cmd_t
*)fcalpkt
->fcal_pkt_private
;
4370 if (payload
->link_failure
& 0xff000000)
4371 arg
= payload
->link_failure
;
4375 buf
= (la_els_rls_t
*)privp
->cmd
;
4376 buf
->ls_code
= LA_ELS_RLS
;
4381 buf
->nport_id
[0] = (arg
>> 16) & 0xff;
4382 buf
->nport_id
[1] = (arg
>> 8) & 0xff;
4383 buf
->nport_id
[2] = arg
& 0xff;
4384 (void) ddi_dma_sync(privp
->cmd_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
4386 retval
= socal_doit(fcalpkt
, port_statep
, 0, socal_rls_done
,
4387 SOCAL_RLS_TIMEOUT
, PORT_RLS_PENDING
, NULL
);
4388 if (retval
== FCAL_SUCCESS
) {
4389 (void) ddi_dma_sync(privp
->rsp_handle
, 0, 0,
4390 DDI_DMA_SYNC_FORKERNEL
);
4391 bcopy(privp
->rsp
, (caddr_t
)payload
,
4392 sizeof (la_els_rls_reply_t
));
4394 privp
->fapktp
= NULL
;
4395 socal_els_free(privp
);
4400 socal_els_alloc(socal_state_t
*socalp
, uint32_t port
, uint32_t dest
,
4401 uint32_t cmd_size
, uint32_t rsp_size
, caddr_t
*rprivp
, uint32_t polled
)
4403 struct fcal_packet
*fcalpkt
;
4404 ddi_dma_cookie_t ccookie
;
4405 ddi_dma_cookie_t rcookie
;
4406 socal_priv_cmd_t
*privp
;
4407 ddi_dma_handle_t chandle
= NULL
;
4408 ddi_dma_handle_t rhandle
= NULL
;
4409 ddi_acc_handle_t cacchandle
;
4410 ddi_acc_handle_t racchandle
;
4412 fc_frame_header_t
*fhp
;
4413 uint_t ccount
, cmd_bound
= 0, rsp_bound
= 0;
4420 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4421 == (fcal_packet_t
*)NULL
)
4425 (socal_priv_cmd_t
*)kmem_zalloc(sizeof (socal_priv_cmd_t
),
4426 polled
? KM_NOSLEEP
: KM_SLEEP
)) == (socal_priv_cmd_t
*)NULL
) {
4430 rprivp
= (caddr_t
*)&privp
;
4432 fcalpkt
->fcal_pkt_private
= (caddr_t
)privp
;
4433 privp
->fapktp
= (void *)fcalpkt
;
4435 if ((ouralpa
= socal_getmap(socalp
, port
, NULL
, 0, 0)) == -1)
4438 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4439 DDI_DMA_DONTWAIT
, NULL
, &chandle
) != DDI_SUCCESS
)
4441 privp
->cmd_handle
= chandle
;
4443 if (ddi_dma_mem_alloc(chandle
, cmd_size
, &socal_acc_attr
,
4444 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4445 (caddr_t
*)&cmd
, &real_len
, &cacchandle
) != DDI_SUCCESS
)
4448 privp
->cmd_acchandle
= cacchandle
;
4450 if (real_len
< cmd_size
)
4453 if (ddi_dma_addr_bind_handle(chandle
, NULL
,
4454 (caddr_t
)cmd
, cmd_size
,
4455 DDI_DMA_WRITE
| DDI_DMA_CONSISTENT
,
4456 DDI_DMA_DONTWAIT
, NULL
, &ccookie
, &ccount
)
4464 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4465 DDI_DMA_DONTWAIT
, NULL
, &rhandle
) != DDI_SUCCESS
)
4468 privp
->rsp_handle
= rhandle
;
4469 if (ddi_dma_mem_alloc(rhandle
, rsp_size
, &socal_acc_attr
,
4470 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4471 &rsp
, &real_len
, &racchandle
) != DDI_SUCCESS
)
4474 privp
->rsp_acchandle
= racchandle
;
4475 if (real_len
< rsp_size
)
4478 if (ddi_dma_addr_bind_handle(rhandle
, NULL
,
4480 DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4481 DDI_DMA_DONTWAIT
, NULL
, &rcookie
, &ccount
)
4490 srp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
4491 srp
->sr_soc_hdr
.sh_flags
= SOC_FC_HEADER
;
4493 srp
->sr_soc_hdr
.sh_flags
|= SOC_PORT_B
;
4494 srp
->sr_soc_hdr
.sh_class
= 3;
4495 srp
->sr_soc_hdr
.sh_byte_cnt
= cmd_size
;
4496 srp
->sr_dataseg
[0].fc_base
= (uint32_t)ccookie
.dmac_address
;
4497 srp
->sr_dataseg
[0].fc_count
= cmd_size
;
4498 if (rsp_size
== 0) {
4499 srp
->sr_soc_hdr
.sh_seg_cnt
= 1;
4501 srp
->sr_soc_hdr
.sh_seg_cnt
= 2;
4502 srp
->sr_dataseg
[1].fc_base
= (uint32_t)rcookie
.dmac_address
;
4503 srp
->sr_dataseg
[1].fc_count
= rsp_size
;
4505 srp
->sr_cqhdr
.cq_hdr_count
= 1;
4506 /* this will potentially be overwritten by the calling function */
4507 srp
->sr_cqhdr
.cq_hdr_type
= CQ_TYPE_SIMPLE
;
4509 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4511 /* Fill in the Fabric Channel Header */
4512 fhp
= &srp
->sr_fc_frame_hdr
;
4513 fhp
->r_ctl
= R_CTL_ELS_REQ
;
4515 fhp
->s_id
= ouralpa
;
4516 fhp
->type
= TYPE_EXTENDED_LS
;
4517 fhp
->f_ctl
= F_CTL_SEQ_INITIATIVE
| F_CTL_FIRST_SEQ
;
4521 fhp
->ox_id
= 0xffff;
4522 fhp
->rx_id
= 0xffff;
4526 socal_packet_free(fcalpkt
);
4528 if (privp
->cmd_handle
) {
4530 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4531 ddi_dma_free_handle(&privp
->cmd_handle
);
4534 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4535 if (privp
->rsp_handle
) {
4537 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4538 ddi_dma_free_handle(&privp
->rsp_handle
);
4541 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4543 kmem_free(privp
, sizeof (*privp
));
4549 socal_lbf_alloc(socal_state_t
*socalp
, uint32_t port
,
4550 uint32_t cmd_size
, uint32_t rsp_size
, caddr_t
*rprivp
,
4553 struct fcal_packet
*fcalpkt
;
4554 ddi_dma_cookie_t ccookie
;
4555 ddi_dma_cookie_t rcookie
;
4556 socal_priv_cmd_t
*privp
;
4557 ddi_dma_handle_t chandle
= NULL
;
4558 ddi_dma_handle_t rhandle
= NULL
;
4559 ddi_acc_handle_t cacchandle
;
4560 ddi_acc_handle_t racchandle
;
4562 fc_frame_header_t
*fhp
;
4563 uint_t ccount
, cmd_bound
= 0, rsp_bound
= 0;
4569 socal_packet_alloc(socalp
, polled
? FCAL_NOSLEEP
: FCAL_SLEEP
))
4570 == (fcal_packet_t
*)NULL
)
4574 (socal_priv_cmd_t
*)kmem_zalloc(sizeof (socal_priv_cmd_t
),
4575 polled
? KM_NOSLEEP
: KM_SLEEP
)) == (socal_priv_cmd_t
*)NULL
) {
4579 rprivp
= (caddr_t
*)&privp
;
4581 fcalpkt
->fcal_pkt_private
= (caddr_t
)privp
;
4582 privp
->fapktp
= (void *)fcalpkt
;
4584 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4585 DDI_DMA_DONTWAIT
, NULL
, &chandle
) != DDI_SUCCESS
)
4587 privp
->cmd_handle
= chandle
;
4589 if (ddi_dma_mem_alloc(chandle
, cmd_size
, &socal_acc_attr
,
4590 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4591 (caddr_t
*)&cmd
, &real_len
, &cacchandle
) != DDI_SUCCESS
)
4594 privp
->cmd_acchandle
= cacchandle
;
4596 if (real_len
< cmd_size
)
4599 if (ddi_dma_addr_bind_handle(chandle
, NULL
,
4600 (caddr_t
)cmd
, cmd_size
,
4601 DDI_DMA_WRITE
| DDI_DMA_CONSISTENT
,
4602 DDI_DMA_DONTWAIT
, NULL
, &ccookie
, &ccount
)
4610 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4611 DDI_DMA_DONTWAIT
, NULL
, &rhandle
) != DDI_SUCCESS
)
4614 privp
->rsp_handle
= rhandle
;
4615 if (ddi_dma_mem_alloc(rhandle
, rsp_size
, &socal_acc_attr
,
4616 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4617 &rsp
, &real_len
, &racchandle
) != DDI_SUCCESS
)
4621 privp
->rsp_acchandle
= racchandle
;
4622 if (real_len
< rsp_size
)
4625 if (ddi_dma_addr_bind_handle(rhandle
, NULL
,
4627 DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4628 DDI_DMA_DONTWAIT
, NULL
, &rcookie
, &ccount
)
4637 srp
= (soc_request_t
*)&fcalpkt
->fcal_socal_request
;
4638 srp
->sr_soc_hdr
.sh_flags
= SOC_FC_HEADER
;
4640 srp
->sr_soc_hdr
.sh_flags
|= SOC_PORT_B
;
4641 srp
->sr_soc_hdr
.sh_class
= 3;
4642 srp
->sr_soc_hdr
.sh_byte_cnt
= cmd_size
;
4643 srp
->sr_dataseg
[0].fc_base
= (uint32_t)ccookie
.dmac_address
;
4644 srp
->sr_dataseg
[0].fc_count
= cmd_size
;
4645 if (rsp_size
== 0) {
4646 srp
->sr_soc_hdr
.sh_seg_cnt
= 1;
4648 srp
->sr_soc_hdr
.sh_seg_cnt
= 2;
4649 srp
->sr_dataseg
[1].fc_base
= (uint32_t)rcookie
.dmac_address
;
4650 srp
->sr_dataseg
[1].fc_count
= rsp_size
;
4652 srp
->sr_cqhdr
.cq_hdr_count
= 1;
4653 /* this will potentially be overwritten by the calling function */
4654 srp
->sr_cqhdr
.cq_hdr_type
= CQ_TYPE_SIMPLE
;
4656 fcalpkt
->fcal_pkt_cookie
= (void *)socalp
;
4658 /* Fill in the Fabric Channel Header */
4659 fhp
= &srp
->sr_fc_frame_hdr
;
4660 fhp
->r_ctl
= R_CTL_SOLICITED_DATA
;
4661 fhp
->d_id
= socalp
->port_state
[port
].sp_src_id
;
4662 fhp
->s_id
= socalp
->port_state
[port
].sp_src_id
;
4663 fhp
->type
= TYPE_SCSI_FCP
;
4664 fhp
->f_ctl
= F_CTL_SEQ_INITIATIVE
| F_CTL_FIRST_SEQ
| F_CTL_LAST_SEQ
;
4668 fhp
->ox_id
= 0xffff;
4669 fhp
->rx_id
= 0xffff;
4673 socal_packet_free(fcalpkt
);
4675 if (privp
->cmd_handle
) {
4677 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4678 ddi_dma_free_handle(&privp
->cmd_handle
);
4681 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4682 if (privp
->rsp_handle
) {
4684 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4685 ddi_dma_free_handle(&privp
->rsp_handle
);
4688 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4690 kmem_free(privp
, sizeof (*privp
));
4696 socal_els_free(socal_priv_cmd_t
*privp
)
4698 fcal_packet_t
*fcalpkt
;
4701 fcalpkt
= (fcal_packet_t
*)privp
->fapktp
;
4705 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4706 ddi_dma_free_handle(&privp
->cmd_handle
);
4707 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4709 if (privp
->rsp_handle
) {
4710 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4711 ddi_dma_free_handle(&privp
->rsp_handle
);
4714 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4716 kmem_free(privp
, sizeof (*privp
));
4717 if (fcalpkt
!= NULL
)
4718 socal_packet_free(fcalpkt
);
4722 socal_lbf_free(socal_priv_cmd_t
*privp
)
4724 fcal_packet_t
*fcalpkt
;
4727 fcalpkt
= (fcal_packet_t
*)privp
->fapktp
;
4731 (void) ddi_dma_unbind_handle(privp
->cmd_handle
);
4732 ddi_dma_free_handle(&privp
->cmd_handle
);
4733 ddi_dma_mem_free(&privp
->cmd_acchandle
);
4735 if (privp
->rsp_handle
) {
4736 (void) ddi_dma_unbind_handle(privp
->rsp_handle
);
4737 ddi_dma_free_handle(&privp
->rsp_handle
);
4741 ddi_dma_mem_free(&privp
->rsp_acchandle
);
4743 kmem_free(privp
, sizeof (*privp
));
4744 if (fcalpkt
!= NULL
)
4745 socal_packet_free(fcalpkt
);
4749 socal_getmap(socal_state_t
*socalp
, uint32_t port
, caddr_t arg
,
4750 uint32_t polled
, int flags
)
4752 ddi_dma_cookie_t dcookie
;
4753 ddi_dma_handle_t dhandle
= NULL
;
4754 ddi_acc_handle_t acchandle
;
4757 fcal_lilp_map_t
*buf
= NULL
;
4758 int retval
, bound
= 0;
4759 socal_port_t
*port_statep
;
4761 port_statep
= &socalp
->port_state
[port
];
4763 if (port_statep
->sp_lilpmap_valid
) {
4765 buf
= &port_statep
->sp_lilpmap
; /* give from cache */
4768 if (ddi_copyout(buf
, (caddr_t
)arg
,
4769 sizeof (struct lilpmap
), flags
) == -1)
4773 return (buf
->lilp_myalpa
);
4776 if (ddi_dma_alloc_handle(socalp
->dip
, &socal_dma_attr
,
4777 DDI_DMA_DONTWAIT
, NULL
, &dhandle
) != DDI_SUCCESS
)
4780 i
= sizeof (struct fcal_lilp_map
);
4782 if (ddi_dma_mem_alloc(dhandle
, i
, &socal_acc_attr
,
4783 DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
4784 (caddr_t
*)&buf
, &real_len
, &acchandle
) != DDI_SUCCESS
)
4790 if (ddi_dma_addr_bind_handle(dhandle
, NULL
,
4791 (caddr_t
)buf
, i
, DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
4792 DDI_DMA_DONTWAIT
, NULL
, &dcookie
, &ccount
) != DDI_DMA_MAPPED
)
4799 retval
= socal_lilp_map((void *)socalp
, port
,
4800 (uint32_t)dcookie
.dmac_address
, polled
);
4802 (void) ddi_dma_sync(dhandle
, 0, 0, DDI_DMA_SYNC_FORKERNEL
);
4804 if (retval
== FCAL_SUCCESS
) {
4805 bcopy(buf
, &port_statep
->sp_lilpmap
, sizeof (fcal_lilp_map_t
));
4807 mutex_enter(&port_statep
->sp_mtx
);
4808 port_statep
->sp_src_id
= buf
->lilp_myalpa
;
4809 port_statep
->sp_lilpmap_valid
= 1; /* cached */
4810 mutex_exit(&port_statep
->sp_mtx
);
4813 if (ddi_copyout(buf
, (caddr_t
)arg
,
4814 sizeof (struct lilpmap
), flags
) == -1)
4818 retval
= buf
->lilp_myalpa
;
4823 (void) ddi_dma_unbind_handle(dhandle
);
4824 ddi_dma_mem_free(&acchandle
);
4825 ddi_dma_free_handle(&dhandle
);
4831 (void) ddi_dma_unbind_handle(dhandle
);
4832 ddi_dma_free_handle(&dhandle
);
4835 ddi_dma_mem_free(&acchandle
);
4840 socal_wcopy(uint_t
*h_src
, uint_t
*h_dest
, int len
)
4843 for (i
= 0; i
< len
/4; i
++) {
4844 *h_dest
++ = *h_src
++;
4849 socal_flush_overflowq(socal_state_t
*socalp
, int port
, int q_no
)
4852 fcal_packet_t
*fpkt1
, *fpkt2
, *head
= NULL
, *tmp
;
4854 kcq
= &socalp
->request
[q_no
];
4855 mutex_enter(&kcq
->skc_mtx
);
4856 fpkt2
= kcq
->skc_overflowh
;
4858 while (fpkt2
!= NULL
) {
4859 if ((((soc_request_t
*)&fpkt2
->fcal_socal_request
)
4860 ->sr_soc_hdr
.sh_flags
& SOC_PORT_B
) == port
) {
4862 kcq
->skc_overflowh
= fpkt2
->fcal_pkt_next
;
4864 fpkt1
->fcal_pkt_next
= fpkt2
->fcal_pkt_next
;
4865 if (kcq
->skc_overflowt
== fpkt2
)
4866 kcq
->skc_overflowt
= fpkt1
;
4868 tmp
= fpkt2
->fcal_pkt_next
;
4869 fpkt2
->fcal_pkt_next
= head
;
4872 SOCAL_ID_FREE(head
->fcal_socal_request
.
4873 sr_soc_hdr
.sh_request_token
);
4876 fpkt2
= fpkt2
->fcal_pkt_next
;
4879 mutex_exit(&kcq
->skc_mtx
);
4881 while (fpkt2
!= NULL
) {
4882 fpkt2
->fcal_pkt_status
= FCAL_STATUS_ERR_OFFLINE
;
4883 fpkt2
->fcal_cmd_state
|= FCAL_CMD_COMPLETE
;
4884 fpkt2
->fcal_pkt_flags
|= FCFLAG_COMPLETE
;
4885 tmp
= fpkt2
->fcal_pkt_next
;
4886 if (fpkt2
->fcal_pkt_comp
!= NULL
)
4887 (*fpkt2
->fcal_pkt_comp
)(fpkt2
);
4893 socal_deferred_intr(void *arg
)
4895 socal_kcq_t
*kcq
= (socal_kcq_t
*)arg
;
4896 socal_state_t
*socalp
= kcq
->skc_socalp
;
4898 ASSERT((socalp
!= NULL
));
4900 mutex_enter(&kcq
->skc_mtx
);
4902 if ((kcq
->skc_out
!= kcq
->skc_saved_out
) ||
4903 (kcq
->skc_seqno
!= kcq
->skc_saved_seqno
)) {
4904 kcq
->deferred_intr_timeoutid
= 0;
4905 mutex_exit(&kcq
->skc_mtx
);
4909 if (socalp
->socal_on_intr
) {
4910 mutex_exit(&kcq
->skc_mtx
);
4911 kcq
->deferred_intr_timeoutid
= timeout(socal_deferred_intr
,
4912 (caddr_t
)kcq
, drv_usectohz(10000));
4916 kcq
->deferred_intr_timeoutid
= 0;
4917 mutex_exit(&kcq
->skc_mtx
);
4918 socal_intr_solicited(socalp
, 0);
4922 socal_take_core(void *arg
)
4924 socal_state_t
*socalp
= (socal_state_t
*)arg
;
4927 socal_disable(socalp
);
4928 for (i
= 0; i
< SOCAL_N_CQS
; i
++) {
4929 mutex_enter(&socalp
->request
[i
].skc_mtx
);
4930 mutex_enter(&socalp
->response
[i
].skc_mtx
);
4932 for (i
= 0; i
< 4; i
++) {
4933 socalp
->socal_rp
->socal_cr
.w
&=
4934 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK
;
4935 socalp
->socal_rp
->socal_cr
.w
|= i
<<24;
4936 (void) bcopy((caddr_t
)socalp
->socal_xrp
,
4937 (caddr_t
)&socal_xrambuf
[i
*0x10000], 0x10000);
4939 for (i
= 3; i
>= 0; i
--) {
4940 mutex_exit(&socalp
->request
[i
].skc_mtx
);
4941 mutex_exit(&socalp
->response
[i
].skc_mtx
);
4943 instance
= ddi_get_instance(socalp
->dip
);
4945 "socal take core (socal instance %d)", instance
);
4949 * Preset AL_PA in hardware, if is told.
4952 socal_fix_harda(socal_state_t
*socalp
, int port
)
4954 socal_port_t
*portp
= &socalp
->port_state
[port
];
4955 uint_t
*xrp
= (uint_t
*)socalp
->socal_xrp
;
4956 uint_t accum
, harda
;
4958 harda
= portp
->sp_hard_alpa
;
4959 accum
= xrp
[SOCAL_XRAM_PORTA_HRDA
/4];
4961 accum
&= 0x00FFFFFF;
4962 accum
|= ((harda
& 0xFF) << 24);
4964 accum
&= 0xFF00FFFF;
4965 accum
|= ((harda
& 0xFF) << 16);
4967 xrp
[SOCAL_XRAM_PORTA_HRDA
/4] = accum
;
4971 * Target-Mode attach function
4974 socal_sftm_attach(dev_t dev
, int loop_id
)
4976 int instance
= getminor(dev
) / 2;
4977 int port
= getminor(dev
) % 2;
4980 socal_state_t
*socalp
;
4983 * If the device is not a "socal" device, return
4985 if ((name
= ddi_major_to_name(getmajor(dev
))) == NULL
||
4986 strcmp(name
, "socal") != 0)
4990 * If no soft state structure, return
4992 socalp
= ddi_get_soft_state(socal_soft_state_p
, instance
);
4997 * If the port is already attached, return
4999 if (socalp
->port_state
[port
].sp_status
& PORT_CHILD_INIT
)
5002 if (loop_id
< 0 || loop_id
> 126)
5005 /* if this instance is detaching, don't attach */
5006 mutex_enter(&socalp
->board_mtx
);
5007 mutex_enter(&socalp
->port_state
[port
].sp_mtx
);
5008 if (socalp
->socal_busy
< 0) {
5009 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
5010 mutex_exit(&socalp
->board_mtx
);
5013 socalp
->socal_busy
++;
5014 socalp
->port_state
[port
].sp_status
|= PORT_CHILD_INIT
;
5015 mutex_exit(&socalp
->port_state
[port
].sp_mtx
);
5016 mutex_exit(&socalp
->board_mtx
);
5019 * Since we keep the Hard Loop-id in two config files, warn the
5020 * user if they don't match.
5022 hard_alpa
= socal_switch_to_alpa
[loop_id
];
5023 if (hard_alpa
!= socalp
->port_state
[port
].sp_hard_alpa
) {
5024 socalp
->port_state
[port
].sp_hard_alpa
= hard_alpa
;
5025 cmn_err(CE_WARN
, "socal%d: Hard Loop-id mismatch - "
5030 return (socalp
->port_state
[port
].sp_transport
);
5035 * Target-Mode detach function
5038 socal_sftm_detach(socal_state_t
*socalp
, int port
)
5040 mutex_enter(&socalp
->board_mtx
);
5041 socalp
->socal_busy
--;
5042 socalp
->port_state
[port
].sp_status
&= ~PORT_CHILD_INIT
;
5043 mutex_exit(&socalp
->board_mtx
);