kernel: remove unused utsname_set_machine()
[unleashed.git] / usr / src / uts / sun / io / socal.c
blob9ac56166e3468ae1aba7e4feb09d44590f9c0421
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
35 #include <sys/note.h>
36 #include <sys/devops.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/user.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42 #include <sys/uio.h>
43 #include <sys/fcntl.h>
45 #include <sys/cmn_err.h>
46 #include <sys/stropts.h>
47 #include <sys/kmem.h>
49 #include <sys/errno.h>
50 #include <sys/open.h>
51 #include <sys/varargs.h>
52 #include <sys/var.h>
53 #include <sys/thread.h>
54 #include <sys/debug.h>
55 #include <sys/cpu.h>
56 #include <sys/autoconf.h>
57 #include <sys/conf.h>
58 #include <sys/stat.h>
60 #include <sys/file.h>
61 #include <sys/syslog.h>
63 #include <sys/ddi.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>
80 * Local Macros
83 #ifdef DEBUG
84 #define SOCAL_DEBUG 1
85 #else
86 #define SOCAL_DEBUG 0
87 #endif
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;
97 #else
98 #define DEBUGF(level, args) /* Nothing */
99 #define SOCALDEBUG(level, args) /* Nothing */
100 #endif
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() */
108 #define RESET_PORT 1
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,
123 cred_t *cred_p);
124 static int socal_close(dev_t dev, int flag, int otyp,
125 cred_t *cred_p);
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);
202 * Utility functions
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 */
228 1, /* minxfer */
229 (unsigned long long)0xffffffff, /* maxxfer */
230 (unsigned long long)0xffffffff, /* seg */
231 1, /* sgllen */
232 4, /* granularity */
233 0 /* flags */
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 = {
243 socal_transport,
244 socal_transport_poll,
245 socal_lilp_map,
246 socal_force_lip,
247 socal_abort_cmd,
248 socal_els,
249 socal_bypass_dev,
250 socal_force_reset,
251 socal_add_ulp,
252 socal_remove_ulp,
253 socal_take_core
257 * Table used for setting the burst size in the soc+ config register
259 static int socal_burst32_table[] = {
260 SOCAL_CR_BURST_4,
261 SOCAL_CR_BURST_4,
262 SOCAL_CR_BURST_4,
263 SOCAL_CR_BURST_4,
264 SOCAL_CR_BURST_16,
265 SOCAL_CR_BURST_32,
266 SOCAL_CR_BURST_64
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 */
303 * Bus ops vector
306 static struct bus_ops socal_bus_ops = {
307 BUSO_REV, /* rev */
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)() */
314 ddi_dma_allochdl,
315 ddi_dma_freehdl,
316 ddi_dma_bindhdl,
317 ddi_dma_unbindhdl,
318 ddi_dma_flush,
319 ddi_dma_win,
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 */
341 CB_REV, /* rev */
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, */
352 0, /* refcnt */
353 socal_getinfo, /* get_dev_info */
354 nulldev, /* identify */
355 nulldev, /* probe */
356 socal_attach, /* attach */
357 socal_detach, /* detach */
358 nodev, /* reset */
359 &socal_cb_ops, /* driver operations */
360 &socal_bus_ops, /* bus operations */
361 NULL, /* power */
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 */
408 SOCAL_NAME,
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";
423 _init(void)
425 int stat;
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);
432 if (stat != 0)
433 return (stat);
435 /* Install the module */
436 stat = mod_install(&modlinkage);
437 if (stat != 0)
438 ddi_soft_state_fini(&socal_soft_state_p);
440 DEBUGF(4, (CE_CONT, "socal: _init: return=%d\n", stat));
441 return (stat);
445 _fini(void)
447 int stat;
449 if ((stat = mod_remove(&modlinkage)) != 0)
450 return (stat);
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));
457 return (stat);
461 _info(struct modinfo *modinfop)
463 return (mod_info(&modlinkage, modinfop));
468 socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
470 int instance;
471 socal_state_t *socalp;
472 struct ether_addr ourmacaddr;
473 socal_port_t *porta, *portb;
474 char buf[MAXPATHLEN];
475 char *cptr, *wwn;
476 int y;
477 int i, j;
478 int burstsize;
479 short s;
480 int loop_id;
482 int rval;
485 instance = ddi_get_instance(dip);
487 DEBUGF(4, (CE_CONT, "socal%d entering attach: cmd=%x\n", instance,
488 cmd));
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",
511 instance);
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) {
517 cmn_err(CE_WARN,
518 "socal%d attach failed: device in slave-only slot",
519 instance);
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
529 * fail the attach.
531 cmn_err(CE_WARN,
532 "socal%d attach failed: hilevel interrupt unsupported",
533 instance);
534 return (DDI_FAILURE);
537 /* Allocate soft state. */
538 if (ddi_soft_state_zalloc(socal_soft_state_p, instance)
539 != DDI_SUCCESS) {
540 cmn_err(CE_WARN, "socal%d attach failed: alloc soft state",
541 instance);
542 return (DDI_FAILURE);
544 DEBUGF(4, (CE_CONT, "socal%d attach: allocated soft state\n",
545 instance));
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",
553 instance);
554 return (DDI_FAILURE);
556 DEBUGF(4, (CE_CONT, "socal%d: attach: soc soft state ptr=0x%p\n",
557 instance, socalp));
559 socalp->dip = dip;
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;
570 porta->sp_port = 0;
571 portb->sp_port = 1;
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,
609 sizeof (uint_t));
610 socalp->socal_n_wwn.w.naa_id = NAA_ID_IEEE;
611 socalp->socal_n_wwn.w.nport_id = 0;
612 } else {
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,
627 sizeof (la_wwn_t));
628 bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&portb->sp_p_wwn,
629 sizeof (la_wwn_t));
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");
650 goto fail;
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");
657 goto fail;
659 DEBUGF(4, (CE_CONT, "socal%d attach: allocated transport structs\n",
660 instance));
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)) {
668 /* Map XRAM */
669 if (ddi_map_regs(dip, 0, &socalp->socal_xrp, 0, 0)
670 != DDI_SUCCESS) {
671 socalp->socal_xrp = NULL;
672 socal_disp_err(socalp, CE_WARN, "attach.4020",
673 "attach failed: unable to map XRAM");
674 goto fail;
676 /* Map registers */
677 socalp->socal_rp = (socal_reg_t *)(socalp->socal_xrp +
678 SOCAL_XRAM_SIZE);
679 } else {
680 /* Map EEPROM */
681 if (ddi_map_regs(dip, 0, &socalp->socal_eeprom, 0, 0) !=
682 DDI_SUCCESS) {
683 socalp->socal_eeprom = NULL;
684 socal_disp_err(socalp, CE_WARN, "attach.4010",
685 "attach failed: unable to map eeprom");
686 goto fail;
688 DEBUGF(4, (CE_CONT, "socal%d attach: mapped eeprom 0x%p\n",
689 instance, socalp->socal_eeprom));
690 /* Map XRAM */
691 if (ddi_map_regs(dip, 1, &socalp->socal_xrp, 0, 0) !=
692 DDI_SUCCESS) {
693 socalp->socal_xrp = NULL;
694 socal_disp_err(socalp, CE_WARN, "attach.4020",
695 "attach failed: unable to map XRAM");
696 goto fail;
698 DEBUGF(4, (CE_CONT, "socal%d attach: mapped xram 0x%p\n",
699 instance, socalp->socal_xrp));
700 /* Map registers */
701 if (ddi_map_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0) !=
702 DDI_SUCCESS) {
703 socalp->socal_rp = NULL;
704 socal_disp_err(socalp, CE_WARN, "attach.4030",
705 "attach failed: unable to map registers");
706 goto fail;
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");
718 goto fail;
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");
728 goto fail;
731 /* see if it stayed defaced */
732 if (ddi_peek32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
733 (int32_t *)&y)
734 != DDI_SUCCESS) {
735 socal_disp_err(socalp, CE_WARN, "attach.4051",
736 "attach failed: unable to access host adapter XRAM");
737 goto fail;
740 #ifdef DEBUG
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;
749 #endif
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");
756 goto fail;
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");
770 } else {
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,
784 (uint_t)0,
785 &socalp->iblkc,
786 &socalp->idevc,
787 socal_dummy_intr,
788 (caddr_t)socalp) != DDI_SUCCESS) {
789 socal_disp_err(socalp, CE_WARN, "attach.4060",
790 "attach failed: unable to install interrupt handler");
791 goto fail;
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);
810 DEBUGF(4, (CE_CONT,
811 "socal%d: attach: inited imr mutex, board mutex, board cv\n",
812 instance));
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",
820 instance));
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",
831 instance));
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) {
838 goto fail;
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) ==
859 DDI_SUCCESS) {
860 DEBUGF(4, (CE_CONT, "socal%d: enabled 64 bit sbus\n",
861 instance));
862 socalp->socal_cfg |= SOCAL_CR_SBUS_ENHANCED;
863 burstsize = ddi_dma_burstsizes(socalp->request[0].
864 skc_dhandle);
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++)
870 if (!(j >>= 1))
871 break;
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,
885 (uint_t)0,
886 &socalp->iblkc,
887 &socalp->idevc,
888 socal_intr,
889 (caddr_t)socalp) != DDI_SUCCESS) {
890 socal_disp_err(socalp, CE_WARN, "attach.4060",
891 "attach failed: unable to install interrupt handler");
892 goto fail;
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)
900 goto fail;
901 if (ddi_create_minor_node(dip, SOCAL_PORTB_NAME, S_IFCHR,
902 instance*N_SOCAL_NPORTS+1, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
903 goto fail;
905 if (socal_start(socalp) != FCAL_SUCCESS)
906 goto fail;
907 DEBUGF(4, (CE_CONT, "socal%d: attach: soc+ started\n", instance));
909 ddi_report_dev(dip);
911 DEBUGF(2, (CE_CONT, "socal%d: attach O.K.\n\n", instance));
913 return (DDI_SUCCESS);
915 fail:
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);
927 static int
928 socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
930 int resp;
931 socal_state_t *socalp;
932 int i;
935 switch (cmd) {
937 case DDI_SUSPEND:
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);
956 case DDI_DETACH:
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);
961 return (resp);
963 default:
964 return (DDI_FAILURE);
968 static int
969 socal_dodetach(dev_info_t *dip)
972 int instance = ddi_get_instance(dip);
973 int i;
974 socal_state_t *socalp;
975 socal_port_t *portp;
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
985 * detach.
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);
1004 DEBUGF(2, (CE_CONT,
1005 "socal%d: detach: Removed SOC+ interrupt from ddi\n",
1006 instance));
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;
1018 cb = cbn) {
1019 cbn = cb->next;
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);
1077 if (socalp->pool) {
1078 ddi_dma_mem_free(&socalp->pool_acchandle);
1081 /* release register maps */
1082 /* Unmap EEPROM */
1083 if (socalp->socal_eeprom != NULL) {
1084 ddi_unmap_regs(dip, 0, &socalp->socal_eeprom, 0, 0);
1087 /* Unmap XRAM */
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,
1112 void *a, void *v)
1114 int port;
1117 switch (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),
1129 port);
1130 break;
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);
1166 break;
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);
1194 break;
1197 case DDI_CTLOPS_IOMIN: {
1198 int val;
1200 val = *((int *)v);
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
1206 * what minxfer is).
1208 if ((int)(uintptr_t)a) {
1209 val = maxbit(val,
1210 1<<(ddi_fls(socallim->dlim_burstsizes)-1));
1211 } else {
1212 val = maxbit(val,
1213 1<<(ddi_ffs(socallim->dlim_burstsizes)-1));
1216 *((int *)v) = val;
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:
1235 default:
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);
1249 /*ARGSUSED*/
1251 * int
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,
1258 void **result)
1260 int instance;
1261 socal_state_t *socalp;
1263 instance = getminor((dev_t)arg) / 2;
1265 switch (cmd) {
1266 case DDI_INFO_DEVT2DEVINFO:
1267 socalp = ddi_get_soft_state(socal_soft_state_p, instance);
1268 if (socalp)
1269 *result = socalp->dip;
1270 else
1271 *result = NULL;
1272 break;
1274 case DDI_INFO_DEVT2INSTANCE:
1275 *result = (void *)(uintptr_t)instance;
1276 break;
1278 default:
1279 return (DDI_FAILURE);
1282 return (DDI_SUCCESS);
1285 /*ARGSUSED*/
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;
1293 int port;
1295 if (socalp == NULL)
1296 return (ENXIO);
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);
1304 DEBUGF(2, (CE_CONT,
1305 "socal%d: open of port %d\n", instance, port));
1306 return (0);
1309 /*ARGSUSED*/
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;
1317 int port;
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);
1325 DEBUGF(2, (CE_CONT,
1326 "socal%d: clsoe of port %d\n", instance, port));
1327 return (0);
1330 /*ARGSUSED*/
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);
1338 int port;
1339 socal_port_t *port_statep;
1340 int i;
1341 uint_t r;
1342 int offset;
1343 int retval = FCAL_SUCCESS;
1344 la_els_adisc_t *adisc_pl;
1345 la_els_rls_reply_t *rls_pl;
1346 dev_info_t *dip;
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;
1356 caddr32_t prom_ver;
1357 } ver32;
1358 uint_t dm32 = 0;
1359 #endif
1361 uchar_t *flb_pl;
1362 flb_hdr_t *flb_hdr;
1363 uint_t flb_size;
1365 if (socalp == NULL)
1366 return (ENXIO);
1368 DEBUGF(4, (CE_CONT, "socal%d ioctl: got command %x\n", instance, cmd));
1369 port = getminor(dev)%2;
1371 switch (cmd) {
1372 case FCIO_FCODE_MCODE_VERSION:
1373 #ifdef _MULTI_DATAMODEL
1374 switch (ddi_model_convert_from(mode & FMODELS)) {
1375 case DDI_MODEL_ILP32:
1376 dm32 = 1;
1377 if (ddi_copyin((caddr_t)arg,
1378 (caddr_t)&ver32, sizeof (ver32),
1379 mode) == -1)
1380 return (EFAULT);
1381 ver.fcode_ver_len =
1382 ver32.fcode_ver_len;
1383 ver.mcode_ver_len =
1384 ver32.mcode_ver_len;
1385 ver.prom_ver_len =
1386 ver32.prom_ver_len;
1387 ver.fcode_ver =
1388 (caddr_t)(uintptr_t)ver32.fcode_ver;
1389 ver.mcode_ver =
1390 (caddr_t)(uintptr_t)ver32.mcode_ver;
1391 ver.prom_ver =
1392 (caddr_t)(uintptr_t)ver32.prom_ver;
1393 break;
1394 case DDI_MODEL_NONE:
1395 if (ddi_copyin((caddr_t)arg,
1396 (caddr_t)&ver, sizeof (ver),
1397 mode) == -1)
1398 return (EFAULT);
1400 #else /* _MULTI_DATAMODEL */
1401 if (ddi_copyin((caddr_t)arg, (caddr_t)&ver,
1402 sizeof (ver), mode) == -1)
1403 return (EFAULT);
1404 #endif /* _MULTI_DATAMODEL */
1405 dip = socalp->dip;
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)
1410 return (EIO);
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,
1415 mode) == -1) {
1416 kmem_free((caddr_t)buffer, i);
1417 return (EFAULT);
1419 kmem_free((caddr_t)buffer, i);
1420 if (socalp->socal_eeprom) {
1421 for (i = 0; i < SOCAL_N_CQS; i++) {
1422 mutex_enter(
1423 &socalp->request[i].skc_mtx);
1424 mutex_enter(
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)
1434 0xfff6, tmp, 10);
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);
1438 mutex_exit(
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)
1444 return (EFAULT);
1445 } else {
1446 ver.prom_ver_len = 0;
1448 ver.mcode_ver_len = 0;
1449 #ifdef _MULTI_DATAMODEL
1450 if (dm32) {
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)
1455 ver.fcode_ver;
1456 ver32.mcode_ver = (caddr32_t)(uintptr_t)
1457 ver.mcode_ver;
1458 ver32.prom_ver = (caddr32_t)(uintptr_t)
1459 ver.prom_ver;
1460 if (ddi_copyout((caddr_t)&ver32,
1461 (caddr_t)arg, sizeof (ver32),
1462 mode) == -1)
1463 return (EFAULT);
1464 } else
1465 #endif /* _MULTI_DATAMODEL */
1466 if (ddi_copyout((caddr_t)&ver, (caddr_t)arg,
1467 sizeof (struct socal_fm_version), mode) == -1)
1468 return (EFAULT);
1469 break;
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)
1475 == -1)
1476 return (EFAULT);
1477 /* restart socal after resetting */
1478 (void) socal_force_reset((void *)socalp, 0,
1479 RESET_PORT);
1480 break;
1481 case FCIO_DUMPXRAM:
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);
1500 break;
1501 #ifdef DEBUG
1502 case FCIO_DUMPXRAMBUF:
1503 (void) copyout((caddr_t)socal_xrambuf, (caddr_t)arg,
1504 0x40000);
1505 break;
1506 #endif
1507 case FCIO_GETMAP:
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);
1513 break;
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);
1518 break;
1519 case FCIO_FORCE_LIP:
1520 mutex_enter(&socalp->ioctl_mtx);
1521 retval = socal_force_lip((void *)socalp, port, 0,
1522 FCAL_FORCE_LIP);
1523 mutex_exit(&socalp->ioctl_mtx);
1524 break;
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);
1529 break;
1530 case FCIO_ADISC_ELS:
1532 if ((adisc_pl =
1533 (la_els_adisc_t *)kmem_zalloc(
1534 sizeof (la_els_adisc_t),
1535 KM_NOSLEEP)) == NULL)
1536 return (ENOMEM);
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));
1542 return (EFAULT);
1544 mutex_enter(&socalp->ioctl_mtx);
1545 retval = socal_issue_adisc(socalp, port,
1546 adisc_pl->nport_id,
1547 adisc_pl, 0);
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));
1555 return (EFAULT);
1559 kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
1560 break;
1562 case FCIO_LINKSTATUS:
1564 int dest;
1565 if ((rls_pl =
1566 (la_els_rls_reply_t *)
1567 kmem_zalloc(sizeof (la_els_rls_reply_t),
1568 KM_NOSLEEP)) == NULL)
1569 return (ENOMEM);
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));
1575 return (EFAULT);
1577 dest = (rls_pl->mbz[0] << 16) + (rls_pl->mbz[1] << 8) +
1578 rls_pl->mbz[2];
1579 mutex_enter(&socalp->ioctl_mtx);
1580 retval = socal_issue_rls(socalp, port, dest,
1581 rls_pl, 0);
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));
1589 return (EFAULT);
1592 kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
1593 break;
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);
1602 if (arg == 0) {
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);
1609 return (EALREADY);
1611 port_statep->sp_status |= PORT_DISABLED;
1612 mutex_exit(&port_statep->sp_mtx);
1614 retval = socal_diag_request((void *)socalp, port, &r,
1615 SOC_DIAG_INT_LOOP);
1616 mutex_exit(&socalp->ioctl_mtx);
1617 if (arg == 0) break;
1618 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1619 == -1)
1620 return (EFAULT);
1621 break;
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);
1629 return (EBUSY);
1631 mutex_exit(&port_statep->sp_mtx);
1632 retval = socal_diag_request((void *)socalp, port, &r,
1633 SOC_DIAG_EXT_LOOP);
1634 mutex_exit(&socalp->ioctl_mtx);
1635 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1636 == -1)
1637 return (EFAULT);
1638 break;
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) {
1645 if (arg != 0) {
1646 mutex_exit(&port_statep->sp_mtx);
1647 mutex_exit(&socalp->ioctl_mtx);
1649 * It's permanently disabled -- Need to
1650 * enable it first
1652 return (EBUSY);
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,
1659 SOC_DIAG_REM_LOOP);
1660 mutex_exit(&socalp->ioctl_mtx);
1661 if (arg == 0) break;
1662 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1663 == -1)
1664 return (EFAULT);
1665 break;
1666 case FCIO_DIAG_NOP:
1667 mutex_enter(&socalp->ioctl_mtx);
1668 retval = socal_diag_request((void *)socalp, port, &r,
1669 SOC_DIAG_NOP);
1670 mutex_exit(&socalp->ioctl_mtx);
1671 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1672 == -1)
1673 return (EFAULT);
1674 break;
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))
1681 == -1)
1682 return (EFAULT);
1683 break;
1684 case FCIO_DIAG_SOC:
1685 mutex_enter(&socalp->ioctl_mtx);
1686 retval = socal_diag_request((void *)socalp, port, &r,
1687 SOC_DIAG_SOC_TEST);
1688 mutex_exit(&socalp->ioctl_mtx);
1689 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1690 == -1)
1691 return (EFAULT);
1692 break;
1693 case FCIO_DIAG_HCB:
1694 mutex_enter(&socalp->ioctl_mtx);
1695 retval = socal_diag_request((void *)socalp, port, &r,
1696 SOC_DIAG_HCB_TEST);
1697 mutex_exit(&socalp->ioctl_mtx);
1698 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1699 == -1)
1700 return (EFAULT);
1701 break;
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))
1708 == -1)
1709 return (EFAULT);
1710 break;
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))
1717 == -1)
1718 return (EFAULT);
1719 break;
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))
1726 == -1)
1727 return (EFAULT);
1728 break;
1729 case FCIO_DIAG_RAW:
1730 if (copyin((caddr_t)arg, (caddr_t)&i, sizeof (uint_t))
1731 == -1)
1732 return (EFAULT);
1733 mutex_enter(&socalp->ioctl_mtx);
1734 retval = socal_diag_request((void *)socalp, port, &r,
1735 (uint_t)i);
1736 mutex_exit(&socalp->ioctl_mtx);
1737 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1738 == -1)
1739 return (EFAULT);
1740 break;
1741 case FCIO_LOOPBACK_FRAME:
1742 if ((flb_hdr = (flb_hdr_t *)kmem_zalloc(sizeof (flb_hdr_t),
1743 KM_NOSLEEP)) == NULL)
1744 return (ENOMEM);
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));
1749 return (EFAULT);
1752 flb_size = flb_hdr->length;
1754 if ((flb_pl =
1755 (uchar_t *)kmem_zalloc(flb_size, KM_NOSLEEP)) == NULL)
1756 return (ENOMEM);
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);
1761 return (EFAULT);
1763 mutex_enter(&socalp->ioctl_mtx);
1764 retval = socal_issue_lbf(socalp, port, flb_pl,
1765 flb_size, 1);
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));
1774 return (EFAULT);
1778 kmem_free((void *)flb_pl, flb_size);
1779 kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1780 break;
1781 default:
1782 return (ENOTTY);
1785 switch (retval) {
1786 case FCAL_SUCCESS:
1787 return (0);
1788 case FCAL_ALLOC_FAILED:
1789 return (ENOMEM);
1790 case FCAL_STATUS_DIAG_BUSY:
1791 return (EALREADY);
1792 case FCAL_STATUS_DIAG_INVALID:
1793 return (EINVAL);
1794 default:
1795 return (EIO);
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
1812 * the hardware.
1814 static void
1815 socal_disable(socal_state_t *socalp)
1817 int i;
1818 /* Don't touch the hardware if the registers aren't mapped */
1819 if (!socalp->socal_rp)
1820 return;
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
1838 static void
1839 socal_init_transport_interface(socal_state_t *socalp)
1841 int i;
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;
1868 * static int
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.
1876 static int
1877 socal_cqalloc_init(socal_state_t *socalp, uint32_t index)
1879 uint32_t cq_size;
1880 size_t real_len;
1881 uint_t ccount;
1882 socal_kcq_t *cqp;
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);
1898 if (cq_size) {
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");
1906 goto fail;
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");
1916 goto fail;
1919 if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
1920 socal_disp_err(socalp, CE_WARN, "driver.4035",
1921 "!alloc of dma space failed");
1922 goto fail;
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");
1934 goto fail;
1937 req_bound = 1;
1938 if (ccount != 1) {
1939 socal_disp_err(socalp, CE_WARN, "driver.4045",
1940 "!bind of dma handle failed");
1941 goto fail;
1944 } else {
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);
1952 if (cq_size) {
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");
1960 goto fail;
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");
1970 goto fail;
1973 if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
1974 socal_disp_err(socalp, CE_WARN, "driver.4065",
1975 "!alloc of dma space failed");
1976 goto fail;
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");
1989 goto fail;
1992 rsp_bound = 1;
1993 if (ccount != 1) {
1994 socal_disp_err(socalp, CE_WARN, "driver.4075",
1995 "!bind of dma handle failed");
1996 goto fail;
1999 } else {
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);
2011 fail:
2012 if (socalp->request[index].skc_dhandle) {
2013 if (req_bound)
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) {
2022 if (rsp_bound)
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.
2048 static void
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));
2085 static int
2086 socal_start(socal_state_t *socalp)
2088 uint_t r;
2090 if (!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,
2113 SOC_DIAG_INT_LOOP);
2114 if (socalp->port_state[1].sp_status & PORT_DISABLED)
2115 (void) socal_diag_request((void *)socalp, 1, &r,
2116 SOC_DIAG_INT_LOOP);
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);
2136 static void
2137 socal_doreset(socal_state_t *socalp)
2139 int i;
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);
2156 if (socalp->pool)
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 |
2172 PORT_ELS_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;
2185 scbp = scbp->next)
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 ()
2212 * Return Values :
2214 * Description : Copies firmware from code that has been linked into
2215 * the socal module into the soc+'s XRAM. Prints the date
2216 * string
2219 static void
2220 socal_download_ucode(socal_state_t *socalp)
2222 uint_t fw_len = 0;
2223 uint_t date_str[16];
2224 auto char buf[256];
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') {
2241 (void) sprintf(buf,
2242 "!Downloading host adapter, fw date code: %s\n",
2243 (caddr_t)date_str);
2244 socal_disp_err(socalp, CE_CONT, "driver.1010", buf);
2245 (void) strcpy(socalp->socal_stats.fw_revision,
2246 (char *)date_str);
2247 } else {
2248 (void) sprintf(buf,
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,
2253 "<Not Available>");
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
2265 static void
2266 socal_disp_err(
2267 socal_state_t *socalp,
2268 uint_t level,
2269 char *mid,
2270 char *msg)
2272 char c;
2273 int instance;
2275 instance = ddi_get_instance(socalp->dip);
2277 c = *msg;
2279 if (c == '!') /* log only */
2280 cmn_err(level,
2281 "!ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
2282 else if (c == '?') /* boot message - log && maybe console */
2283 cmn_err(level,
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,
2290 instance, msg);
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.
2305 static void
2306 socal_init_cq_desc(socal_state_t *socalp)
2308 soc_cq_t que_desc[SOCAL_N_CQS];
2309 uint32_t i;
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.
2319 * Do request queues
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;
2327 } else {
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 */
2336 /* copy to XRAM */
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;
2351 } else {
2352 que_desc[i].cq_address = 0;
2353 que_desc[i].cq_last_index = 0;
2357 /* copy to XRAM */
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));
2363 static void
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),
2374 sizeof (la_wwn_t));
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),
2379 sizeof (la_wwn_t));
2382 * need to avoid deadlock by assuring no other thread grabs both of
2383 * these at once
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);
2394 static void
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;
2409 * static int
2410 * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
2411 * to place LINK ctl application data as it arrives.
2413 * Returns:
2414 * FCAL_SUCCESS, upon establishing the pool.
2415 * FCAL_FAILURE, if unable to establish the pool.
2418 static int
2419 socal_establish_pool(socal_state_t *socalp, uint32_t poolid)
2421 soc_pool_request_t *prq;
2422 int result;
2424 if ((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 |
2433 SOC_NO_RESPONSE;
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));
2464 return (result);
2470 * static int
2471 * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
2472 * to an established pool of buffers
2474 * Returns:
2475 * DDI_SUCCESS, upon establishing the pool.
2476 * DDI_FAILURE, if unable to establish the pool.
2479 static int
2480 socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid)
2482 soc_data_request_t *drq;
2483 int result;
2484 size_t real_len;
2485 int bound = 0;
2486 uint_t ccount;
2488 if ((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)
2496 goto fail;
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)
2501 != DDI_SUCCESS)
2502 goto fail;
2504 if (real_len < SOCAL_POOL_SIZE)
2505 goto fail;
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)
2511 goto fail;
2513 bound = 1;
2514 if (ccount != 1)
2515 goto fail;
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));
2549 return (result);
2551 fail:
2552 socal_disp_err(socalp, CE_WARN, "driver.4110",
2553 "!Buffer pool DVMA alloc failed");
2554 if (socalp->pool_dhandle) {
2555 if (bound)
2556 (void) ddi_dma_unbind_handle(socalp->pool_dhandle);
2557 ddi_dma_free_handle(&socalp->pool_dhandle);
2559 if (socalp->pool)
2560 ddi_dma_mem_free(&socalp->pool_acchandle);
2561 socalp->pool_dhandle = NULL;
2562 return (FCAL_FAILURE);
2565 static uint_t
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);
2572 #endif
2573 int port;
2574 soc_request_t *sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
2576 if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
2577 port = 1;
2578 else
2579 port = 0;
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()
2595 * Return Values :
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
2601 * queue
2603 * Context :
2606 /*ARGSUSED*/
2607 static int
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,
2610 int mtxheld)
2612 #if defined(DEBUG) && !defined(lint)
2613 int instance = ddi_get_instance(socalp->dip);
2614 #endif
2615 socal_kcq_t *kcq;
2616 cqe_t *sp;
2617 uint_t bitmask, wmask;
2618 uchar_t out;
2619 uchar_t s_out;
2620 longlong_t *p, *q;
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.
2638 if (to_queue) {
2639 if ((to_queue->fcal_socal_request.sr_soc_hdr.sh_request_token =
2640 SOCAL_ID_GET(to_queue, mtxheld ? FCAL_NOSLEEP :
2641 sleep)) == NULL) {
2642 return (FCAL_TRANSPORT_QFULL);
2646 * Grab lock for request queue.
2649 if (!mtxheld)
2650 mutex_enter(&kcq->skc_mtx);
2653 * Determine if the queue is full
2656 do {
2658 if (kcq->skc_full) {
2660 * If soc's queue full, then we wait for an interrupt
2661 * telling us we are not full.
2664 if (to_queue) {
2665 to_queue->fcal_pkt_next = NULL;
2666 if (!kcq->skc_overflowh) {
2667 DEBUGF(2, (CE_CONT,
2668 "socal%d: cq_enque: request "
2669 "que %d is full\n",
2670 instance, rqix));
2671 kcq->skc_overflowh = to_queue;
2672 socalp->socal_stats.qfulls++;
2673 } else
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;
2682 if (!mtxheld)
2683 mutex_exit(&kcq->skc_mtx);
2684 return (FCAL_TRANSPORT_SUCCESS);
2687 if (!mtxheld)
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
2697 s_out =
2698 SOCAL_REQUESTQ_INDEX(rqix, socalp->socal_rp->socal_reqp.w);
2699 DEBUGF(2, (CE_CONT,
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;
2717 *q++ = *p++;
2718 *q++ = *p++;
2719 *q++ = *p++;
2720 *q++ = *p++;
2721 *q++ = *p++;
2722 *q++ = *p++;
2723 *q++ = *p++;
2724 *q = *p;
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);
2727 if (to_queue)
2728 to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
2731 * Update circular queue and ring SOC's doorbell.
2733 kcq->skc_in++;
2734 if ((kcq->skc_in & kcq->skc_last_index) == 0) {
2735 kcq->skc_in = 0;
2736 kcq->skc_seqno++;
2739 socalp->socal_rp->socal_csr.w = wmask | (kcq->skc_in << 24);
2740 /* Let lock go for request queue. */
2741 if (!mtxheld)
2742 mutex_exit(&kcq->skc_mtx);
2744 return (FCAL_TRANSPORT_SUCCESS);
2747 static uint_t
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;
2752 uint_t csr;
2753 socal_port_t *port_statep;
2754 int port;
2755 soc_request_t *sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
2756 uint32_t retval;
2757 clock_t ticker, t;
2759 /* make the timeout meaningful */
2760 timeout = drv_usectohz(timeout);
2761 if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
2762 port = 1;
2763 else
2764 port = 0;
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) {
2774 return (retval);
2775 } else {
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);
2791 static uint_t
2792 socal_doit(fcal_packet_t *fcalpkt, socal_port_t *port_statep, int polled,
2793 void (*func)(), int timo, int flag, uint_t *diagcode)
2795 clock_t lb;
2796 uint32_t retval, status;
2797 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
2799 if (polled) {
2800 fcalpkt->fcal_pkt_comp = NULL;
2801 status = socal_transport_poll(fcalpkt, timo, CQ_REQUEST_0);
2802 } else {
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;
2814 break;
2818 port_statep->sp_status &= ~flag;
2819 mutex_exit(&port_statep->sp_mtx);
2822 switch (status) {
2823 case FCAL_TRANSPORT_SUCCESS:
2824 status = fcalpkt->fcal_pkt_status;
2825 if (diagcode)
2826 *diagcode = fcalpkt->fcal_diag_status;
2827 switch (status) {
2828 case FCAL_STATUS_ABORT_FAILED:
2829 if (flag == PORT_ABORT_PENDING)
2830 retval = FCAL_ABORT_FAILED;
2831 break;
2832 case FCAL_STATUS_OK:
2833 if (flag == PORT_ABORT_PENDING)
2834 retval = FCAL_ABORT_FAILED;
2835 else
2836 retval = FCAL_SUCCESS;
2837 break;
2838 case FCAL_STATUS_OLD_PORT:
2839 retval = FCAL_OLD_PORT;
2840 break;
2841 case FCAL_STATUS_ERR_OFFLINE:
2842 retval = FCAL_OFFLINE;
2843 break;
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++;
2849 break;
2850 case FCAL_STATUS_BAD_XID:
2851 retval = FCAL_BAD_ABORT;
2852 break;
2853 case FCAL_STATUS_BAD_DID:
2854 retval = FCAL_BAD_PARAMS;
2855 break;
2856 case FCAL_STATUS_DIAG_BUSY:
2857 case FCAL_STATUS_DIAG_INVALID:
2858 retval = status;
2859 break;
2860 default:
2861 retval = FCAL_LINK_ERROR;
2863 break;
2864 case FCAL_TRANSPORT_TIMEOUT:
2865 if (flag == PORT_LIP_PENDING ||
2866 flag == PORT_LILP_PENDING) {
2867 if (socal_core &&
2868 (socal_core & SOCAL_FAILED_LIP)) {
2869 socal_core = 0;
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);
2878 else
2879 (void) socal_force_lip(port_statep->sp_board,
2880 port_statep->sp_port, polled,
2881 FCAL_FORCE_LIP);
2882 retval = FCAL_TIMEOUT;
2883 break;
2884 case FCAL_TRANSPORT_FAILURE:
2885 case FCAL_BAD_PACKET:
2886 case FCAL_TRANSPORT_UNAVAIL:
2887 case FCAL_TRANSPORT_QFULL:
2888 retval = status;
2889 break;
2890 default:
2891 retval = FCAL_LINK_ERROR;
2893 socal_packet_free(fcalpkt);
2894 return (retval);
2897 static uint_t
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];
2905 if ((fcalpkt =
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;
2911 if (port)
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));
2925 static uint_t
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);
2944 } else
2945 mutex_exit(&port_statep->sp_mtx);
2947 socalp->socal_stats.pstats[port].lips++;
2948 if ((fcalpkt =
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;
2954 if (port)
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));
2964 static uint_t
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];
2971 socal_kcq_t *kcq;
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;
2977 fpkt = NULL;
2978 while (fcalpkt2 != NULL) {
2979 if (fcalpkt2 == fcalpkt) {
2980 if (fpkt == NULL)
2981 kcq->skc_overflowh = fcalpkt->fcal_pkt_next;
2982 else {
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);
2992 } else {
2993 fpkt = fcalpkt2;
2994 fcalpkt2 = fcalpkt2->fcal_pkt_next;
2997 mutex_exit(&kcq->skc_mtx);
2998 if ((fcalpkt2 =
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);
3004 /* Too late? */
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;
3019 if (port)
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));
3028 /*ARGSUSED*/
3029 static uint_t
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,
3032 uint_t sleep)
3034 return (FCAL_TRANSPORT_FAILURE);
3037 static uint_t
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];
3045 if ((fcalpkt =
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;
3051 if (port)
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));
3061 /*ARGSUSED*/
3062 static void
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);
3070 return;
3071 } else {
3072 socalp->socal_shutdown = 1;
3073 mutex_exit(&socalp->k_imr_mtx);
3075 socalp->socal_stats.resets++;
3076 socal_doreset(socalp);
3077 if (restart) {
3078 if (socal_start(socalp) != FCAL_SUCCESS) {
3079 cmn_err(CE_WARN, "socal: start failed.\n");
3085 static void
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;
3101 cbentry->arg = arg;
3102 mutex_exit(&port_statep->sp_mtx);
3103 return;
3106 mutex_exit(&port_statep->sp_mtx);
3107 if ((cbentry =
3108 (socal_unsol_cb_t *)kmem_zalloc(sizeof (socal_unsol_cb_t),
3109 KM_SLEEP)) == (socal_unsol_cb_t *)NULL) {
3110 return;
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;
3116 cbentry->arg = arg;
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
3128 static void
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);
3143 p_cbentry = NULL;
3144 for (cbentry = port_statep->sp_unsol_cb;
3145 cbentry != NULL;
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;
3154 } else {
3155 /* remove other entry in list */
3156 if (p_cbentry)
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));
3161 break;
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.
3173 static unsigned int
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;
3178 unsigned csr;
3179 int cause = 0;
3180 int instance = ddi_get_instance(socalp->dip);
3181 int i, j, request;
3182 char full;
3183 struct fcal_packet *fpkt, *nfpkt;
3185 csr = socalreg->socal_csr.w;
3186 cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
3188 DEBUGF(2, (CE_CONT,
3189 "socal%d: intr: csr: 0x%x cause: 0x%x\n",
3190 instance, csr, cause));
3192 if (!cause) {
3193 socalp->socal_on_intr = 0;
3194 return (DDI_INTR_UNCLAIMED);
3197 socalp->socal_on_intr = 1;
3199 while (cause) {
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
3229 * another command.
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;
3234 j++, i <<= 1) {
3235 if (request & i) {
3236 socal_kcq_t *kcq = &socalp->request[j];
3238 if (kcq->skc_full) {
3239 mutex_enter(&kcq->skc_mtx);
3240 full = kcq->skc_full;
3241 kcq->skc_full = 0;
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) {
3251 break;
3254 if (!kcq->skc_overflowh) {
3255 if (full & SOCAL_SKC_SLEEP)
3256 cv_broadcast(&kcq->skc_cv);
3258 /* Disable this queue's intrs */
3259 DEBUGF(2, (CE_CONT,
3260 "socal%d: req que %d overflow cleared\n",
3261 instance, j));
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);
3282 static void
3283 socal_intr_solicited(socal_state_t *socalp, uint32_t srq)
3285 socal_kcq_t *kcq;
3286 volatile socal_kcq_t *kcqv;
3287 soc_response_t *srp;
3288 cqe_t *cqe;
3289 uint_t status, i;
3290 fcal_packet_t *fcalpkt = NULL;
3291 soc_header_t *shp;
3292 register volatile socal_reg_t *socalreg = socalp->socal_rp;
3293 caddr_t src, dst;
3294 uchar_t index_in;
3295 cq_hdr_t *cq_hdr;
3296 char val;
3297 int port;
3299 #if defined(DEBUG) && !defined(lint)
3300 int instance = ddi_get_instance(socalp->dip);
3301 #endif
3302 auto char buf[80];
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++;
3352 #endif
3353 if (kcq->deferred_intr_timeoutid) {
3354 mutex_exit(&kcq->skc_mtx);
3355 return;
3356 } else {
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);
3363 return;
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);
3383 DEBUGF(4, (CE_CONT,
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.
3392 kcqv->skc_out++;
3393 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3394 kcqv->skc_out = 0;
3395 kcqv->skc_seqno++;
3398 } else {
3400 DEBUGF(2, (CE_CONT, "packet 0x%p complete\n",
3401 fcalpkt));
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)
3411 == 0);
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
3422 * xRAM.
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 ?
3433 1 : 0;
3434 if ((status != FCAL_STATUS_OK) &&
3435 (status <= FCAL_STATUS_MAX_STATUS)) {
3436 socalp->socal_stats.pstats[i].
3437 resp_status[status]++;
3438 } else {
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 =
3445 shp->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.
3454 kcqv->skc_out++;
3455 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3456 kcqv->skc_out = 0;
3457 kcqv->skc_seqno++;
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;
3464 uint_t r;
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 &
3475 PORT_DISABLED) {
3476 /* Already disabled */
3477 mutex_exit(&port_statep->sp_mtx);
3478 } else {
3479 port_statep->sp_status |=
3480 PORT_DISABLED;
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 |=
3503 FCAL_CMD_COMPLETE;
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);
3512 /* callback */
3513 (*fcalpkt->fcal_pkt_comp)(fcalpkt);
3515 /* reacquire mutex */
3516 mutex_enter(&kcq->skc_mtx);
3517 } else {
3518 fcalpkt->fcal_cmd_state |=
3519 FCAL_CMD_COMPLETE;
3520 mutex_exit(&socalp->abort_mtx);
3522 } else {
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.
3541 break;
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
3585 * queue
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
3597 static void
3598 socal_intr_unsolicited(socal_state_t *socalp, uint32_t urq)
3600 socal_kcq_t *kcq;
3601 volatile socal_kcq_t *kcqv;
3602 soc_response_t *srp;
3603 volatile cqe_t *cqe;
3604 int port;
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;
3608 uint_t i;
3609 int hdr_count;
3610 int status;
3611 ushort_t flags;
3612 auto char buf[256];
3613 socal_port_t *port_statep;
3614 #if defined(DEBUG) && !defined(lint)
3615 int instance = ddi_get_instance(socalp->dip);
3616 #endif
3617 uchar_t index_in;
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;
3644 i = index_in;
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
3652 if (i < t_index) {
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
3672 * arrived
3674 if (i < t_index)
3675 break;
3678 if (t_index > kcq->skc_last_index) {
3679 t_seqno++;
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");
3697 DEBUGF(4, (CE_CONT,
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) {
3702 t_index = 0;
3703 t_seqno++;
3705 kcqv->skc_out = t_index;
3706 kcqv->skc_seqno = t_seqno;
3708 cqe = &(kcq->skc_cq[kcqv->skc_out]);
3709 cqe_cont = NULL;
3710 continue;
3715 * Update unsolicited response queue ptrs
3717 kcqv->skc_out++;
3718 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3719 kcqv->skc_out = 0;
3720 kcqv->skc_seqno++;
3723 if (cqe_cont != NULL) {
3724 kcqv->skc_out++;
3725 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3726 kcqv->skc_out = 0;
3727 kcqv->skc_seqno++;
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,
3768 (cqe_t *)cqe,
3769 (caddr_t)cqe_cont);
3770 mutex_enter(&kcq->skc_mtx);
3771 mutex_enter(&port_statep->sp_mtx);
3774 mutex_exit(&port_statep->sp_mtx);
3775 break;
3776 case R_CTL_BASIC_SVC:
3777 (void) sprintf(buf,
3778 "!unsupported Link Service command: 0x%x",
3779 srp->sr_fc_frame_hdr.type);
3780 socal_disp_err(socalp, CE_WARN, "link.4020", buf);
3781 break;
3782 case R_CTL_DEVICE_DATA:
3783 switch (srp->sr_fc_frame_hdr.type) {
3784 default:
3785 mutex_enter(&port_statep->sp_mtx);
3786 status = 1;
3787 for (cblist = port_statep->sp_unsol_cb; cblist;
3788 cblist = cblist->next) {
3789 if (cblist->data_cb &&
3790 (cblist->type ==
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);
3798 status = 0;
3801 mutex_exit(&port_statep->sp_mtx);
3803 if (status == 0)
3804 break;
3806 (void) sprintf(buf,
3807 "!unknown FC-4 command: 0x%x",
3808 srp->sr_fc_frame_hdr.type);
3809 socal_disp_err(socalp, CE_WARN,
3810 "link.4030", buf);
3811 break;
3813 break;
3814 default:
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);
3818 break;
3820 break;
3822 case SOC_STATUS: {
3825 * Note that only the lsbyte of the status has
3826 * interesting information...
3828 status = srp->sr_soc_status;
3830 switch (status) {
3832 case FCAL_STATUS_ONLINE:
3833 (void) sprintf(buf,
3834 "!port %d: Fibre Channel is ONLINE\n", port);
3835 socal_disp_err(socalp, CE_CONT, "link.6010",
3836 buf);
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++;
3842 DEBUGF(4, (CE_CONT,
3843 "socal%d intr_unsol: ONLINE intr\n",
3844 instance));
3845 break;
3847 case FCAL_STATUS_LOOP_ONLINE:
3848 (void) sprintf(buf,
3849 "!port %d: Fibre Channel Loop is ONLINE\n",
3850 port);
3851 socal_disp_err(socalp, CE_CONT, "link.6010",
3852 buf);
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++;
3858 DEBUGF(4, (CE_CONT,
3859 "socal%d intr_unsol: ONLINE-LOOP intr\n",
3860 instance));
3861 break;
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.
3870 (void) sprintf(buf,
3871 "!port %d: Fibre Channel is OFFLINE\n", port);
3872 socal_disp_err(socalp, CE_CONT, "link.5010",
3873 buf);
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++;
3881 DEBUGF(4, (CE_CONT,
3882 "socal%d intr_unsol: OFFLINE intr\n",
3883 instance));
3885 break;
3886 default:
3887 (void) sprintf(buf, "!unknown status: 0x%x\n",
3888 status);
3889 socal_disp_err(socalp, CE_WARN, "link.3020",
3890 buf);
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,
3899 status);
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,
3906 CQ_REQUEST_0);
3907 socal_flush_overflowq(socalp, port,
3908 CQ_REQUEST_1);
3910 mutex_enter(&kcq->skc_mtx);
3911 break;
3913 default:
3914 (void) sprintf(buf, "!unexpected state: flags: 0x%x\n",
3915 flags);
3916 socal_disp_err(socalp, CE_WARN, "link.4050", buf);
3917 DEBUGF(4, (CE_CONT,
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.
3939 break;
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);
3949 cqe_cont = NULL;
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
3969 index_in =
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.
3987 static void
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;
3992 int i;
3993 char *bp;
3994 auto char buf[256];
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");
4003 return;
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);
4023 break;
4025 default:
4026 DEBUGF(3, (CE_CONT, "!unknown LS_Command, %x\n",
4027 els->els_cmd.i));
4028 break;
4033 /*ARGSUSED*/
4034 static fcal_packet_t *
4035 socal_packet_alloc(socal_state_t *socalp, fcal_sleep_t sleep)
4037 int flag;
4038 fcal_packet_t *pkt;
4040 if (sleep == FCAL_SLEEP)
4041 flag = KM_SLEEP;
4042 else
4043 flag = KM_NOSLEEP;
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;
4050 return (pkt);
4053 static void
4054 socal_packet_free(fcal_packet_t *fcalpkt)
4056 kmem_free((void *)fcalpkt, sizeof (fcal_packet_t));
4059 static void
4060 socal_lilp_map_done(fcal_packet_t *fcalpkt)
4062 uint32_t port;
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)
4066 port = 1;
4067 else
4068 port = 0;
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);
4075 static void
4076 socal_force_lip_done(fcal_packet_t *fcalpkt)
4078 uint32_t port;
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)
4082 port = 1;
4083 else
4084 port = 0;
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);
4091 static void
4092 socal_adisc_done(fcal_packet_t *fcalpkt)
4094 uint32_t port;
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)
4098 port = 1;
4099 else
4100 port = 0;
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);
4107 static void
4108 socal_lbf_done(fcal_packet_t *fcalpkt)
4110 uint32_t port;
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)
4114 port = 1;
4115 else
4116 port = 0;
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);
4123 static void
4124 socal_rls_done(fcal_packet_t *fcalpkt)
4126 uint32_t port;
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)
4130 port = 1;
4131 else
4132 port = 0;
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);
4139 static void
4140 socal_force_offline_done(fcal_packet_t *fcalpkt)
4142 uint32_t port;
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)
4146 port = 1;
4147 else
4148 port = 0;
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);
4155 static void
4156 socal_abort_done(fcal_packet_t *fcalpkt)
4158 uint32_t port;
4159 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4160 soc_header_t *shp =
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)
4172 port = 1;
4173 else
4174 port = 0;
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);
4181 static void
4182 socal_bypass_dev_done(fcal_packet_t *fcalpkt)
4184 uint32_t port;
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)
4187 port = 1;
4188 else
4189 port = 0;
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);
4196 /*ARGSUSED*/
4197 static unsigned int
4198 socal_dummy_intr(caddr_t arg)
4200 return (DDI_INTR_UNCLAIMED);
4203 static int
4204 socal_diag_request(socal_state_t *socalp, uint32_t port, uint_t *diagcode,
4205 uint32_t cmd)
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)
4215 != -1) {
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;
4225 if (port)
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));
4235 static uint_t
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];
4243 if ((fcalpkt =
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;
4249 if (port)
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));
4258 static int
4259 socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t dest,
4260 la_els_adisc_t *payload, uint32_t polled)
4262 int retval;
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];
4270 if ((fcalpkt =
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;
4279 buf->mbz[0] = 0;
4280 buf->mbz[1] = 0;
4281 buf->mbz[2] = 0;
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);
4299 return (retval);
4302 static int
4303 socal_issue_lbf(socal_state_t *socalp, uint32_t port,
4304 uchar_t *payload, size_t length, uint32_t polled)
4306 int retval;
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);
4331 return (retval);
4334 static int
4335 socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t dest,
4336 la_els_rls_reply_t *payload, uint32_t polled)
4338 int retval;
4339 la_els_rls_t *buf;
4340 fcal_packet_t *fcalpkt;
4341 socal_port_t *port_statep;
4342 socal_priv_cmd_t *privp;
4343 uint32_t arg;
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;
4352 rsp->mbz[0] = 0;
4353 rsp->mbz[1] = 0;
4354 rsp->mbz[2] = 0;
4355 rsp->reason_code = RJT_UNSUPPORTED;
4356 rsp->reserved = 0;
4357 rsp->explanation = 0;
4358 rsp->vendor = 0;
4359 return (FCAL_SUCCESS);
4362 if ((fcalpkt =
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;
4372 else
4373 arg = dest;
4375 buf = (la_els_rls_t *)privp->cmd;
4376 buf->ls_code = LA_ELS_RLS;
4377 buf->mbz[0] = 0;
4378 buf->mbz[1] = 0;
4379 buf->mbz[2] = 0;
4380 buf->reserved = 0;
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);
4396 return (retval);
4399 fcal_packet_t *
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;
4411 soc_request_t *srp;
4412 fc_frame_header_t *fhp;
4413 uint_t ccount, cmd_bound = 0, rsp_bound = 0;
4414 size_t real_len;
4415 caddr_t cmd;
4416 caddr_t rsp;
4417 uint32_t ouralpa;
4419 if ((fcalpkt =
4420 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
4421 == (fcal_packet_t *)NULL)
4422 return (NULL);
4424 if ((privp =
4425 (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
4426 polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
4427 goto fail;
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)
4436 goto fail;
4438 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4439 DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
4440 goto fail;
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)
4446 goto fail;
4447 privp->cmd = cmd;
4448 privp->cmd_acchandle = cacchandle;
4450 if (real_len < cmd_size)
4451 goto fail;
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)
4457 != DDI_DMA_MAPPED)
4458 goto fail;
4459 cmd_bound = 1;
4460 if (ccount != 1)
4461 goto fail;
4463 if (rsp_size) {
4464 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4465 DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
4466 goto fail;
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)
4472 goto fail;
4473 privp->rsp = rsp;
4474 privp->rsp_acchandle = racchandle;
4475 if (real_len < rsp_size)
4476 goto fail;
4478 if (ddi_dma_addr_bind_handle(rhandle, NULL,
4479 rsp, rsp_size,
4480 DDI_DMA_READ | DDI_DMA_CONSISTENT,
4481 DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4482 != DDI_DMA_MAPPED)
4483 goto fail;
4485 rsp_bound = 1;
4486 if (ccount != 1)
4487 goto fail;
4490 srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
4491 srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
4492 if (port)
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;
4500 } else {
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;
4514 fhp->d_id = dest;
4515 fhp->s_id = ouralpa;
4516 fhp->type = TYPE_EXTENDED_LS;
4517 fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4518 fhp->seq_id = 0;
4519 fhp->df_ctl = 0;
4520 fhp->seq_cnt = 0;
4521 fhp->ox_id = 0xffff;
4522 fhp->rx_id = 0xffff;
4523 fhp->ro = 0;
4524 return (fcalpkt);
4525 fail:
4526 socal_packet_free(fcalpkt);
4527 if (privp) {
4528 if (privp->cmd_handle) {
4529 if (cmd_bound)
4530 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4531 ddi_dma_free_handle(&privp->cmd_handle);
4533 if (privp->cmd)
4534 ddi_dma_mem_free(&privp->cmd_acchandle);
4535 if (privp->rsp_handle) {
4536 if (rsp_bound)
4537 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4538 ddi_dma_free_handle(&privp->rsp_handle);
4540 if (privp->rsp)
4541 ddi_dma_mem_free(&privp->rsp_acchandle);
4543 kmem_free(privp, sizeof (*privp));
4545 return (NULL);
4548 fcal_packet_t *
4549 socal_lbf_alloc(socal_state_t *socalp, uint32_t port,
4550 uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp,
4551 uint32_t polled)
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;
4561 soc_request_t *srp;
4562 fc_frame_header_t *fhp;
4563 uint_t ccount, cmd_bound = 0, rsp_bound = 0;
4564 size_t real_len;
4565 caddr_t cmd;
4566 caddr_t rsp;
4568 if ((fcalpkt =
4569 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
4570 == (fcal_packet_t *)NULL)
4571 return (NULL);
4573 if ((privp =
4574 (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
4575 polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
4576 goto fail;
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)
4586 goto fail;
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)
4592 goto fail;
4593 privp->cmd = cmd;
4594 privp->cmd_acchandle = cacchandle;
4596 if (real_len < cmd_size)
4597 goto fail;
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)
4603 != DDI_DMA_MAPPED)
4604 goto fail;
4605 cmd_bound = 1;
4606 if (ccount != 1)
4607 goto fail;
4609 if (rsp_size) {
4610 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4611 DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
4612 goto fail;
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)
4618 goto fail;
4620 privp->rsp = rsp;
4621 privp->rsp_acchandle = racchandle;
4622 if (real_len < rsp_size)
4623 goto fail;
4625 if (ddi_dma_addr_bind_handle(rhandle, NULL,
4626 rsp, rsp_size,
4627 DDI_DMA_READ | DDI_DMA_CONSISTENT,
4628 DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4629 != DDI_DMA_MAPPED)
4630 goto fail;
4632 rsp_bound = 1;
4633 if (ccount != 1)
4634 goto fail;
4637 srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
4638 srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
4639 if (port)
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;
4647 } else {
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;
4665 fhp->seq_id = 0;
4666 fhp->df_ctl = 0;
4667 fhp->seq_cnt = 0;
4668 fhp->ox_id = 0xffff;
4669 fhp->rx_id = 0xffff;
4670 fhp->ro = 0;
4671 return (fcalpkt);
4672 fail:
4673 socal_packet_free(fcalpkt);
4674 if (privp) {
4675 if (privp->cmd_handle) {
4676 if (cmd_bound)
4677 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4678 ddi_dma_free_handle(&privp->cmd_handle);
4680 if (privp->cmd)
4681 ddi_dma_mem_free(&privp->cmd_acchandle);
4682 if (privp->rsp_handle) {
4683 if (rsp_bound)
4684 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4685 ddi_dma_free_handle(&privp->rsp_handle);
4687 if (privp->rsp)
4688 ddi_dma_mem_free(&privp->rsp_acchandle);
4690 kmem_free(privp, sizeof (*privp));
4692 return (NULL);
4695 void
4696 socal_els_free(socal_priv_cmd_t *privp)
4698 fcal_packet_t *fcalpkt;
4700 if (privp)
4701 fcalpkt = (fcal_packet_t *)privp->fapktp;
4702 else
4703 return;
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);
4713 if (privp->rsp)
4714 ddi_dma_mem_free(&privp->rsp_acchandle);
4716 kmem_free(privp, sizeof (*privp));
4717 if (fcalpkt != NULL)
4718 socal_packet_free(fcalpkt);
4721 void
4722 socal_lbf_free(socal_priv_cmd_t *privp)
4724 fcal_packet_t *fcalpkt;
4726 if (privp)
4727 fcalpkt = (fcal_packet_t *)privp->fapktp;
4728 else
4729 return;
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);
4740 if (privp->rsp)
4741 ddi_dma_mem_free(&privp->rsp_acchandle);
4743 kmem_free(privp, sizeof (*privp));
4744 if (fcalpkt != NULL)
4745 socal_packet_free(fcalpkt);
4748 static int
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;
4755 size_t real_len, i;
4756 uint_t ccount;
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 */
4767 if (arg) {
4768 if (ddi_copyout(buf, (caddr_t)arg,
4769 sizeof (struct lilpmap), flags) == -1)
4770 return (-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)
4778 goto getmap_fail;
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)
4785 goto getmap_fail;
4787 if (real_len < i)
4788 goto getmap_fail;
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)
4793 goto getmap_fail;
4795 bound = 1;
4796 if (ccount != 1)
4797 goto getmap_fail;
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);
4812 if (arg) {
4813 if (ddi_copyout(buf, (caddr_t)arg,
4814 sizeof (struct lilpmap), flags) == -1)
4815 goto getmap_fail;
4818 retval = buf->lilp_myalpa;
4820 else
4821 retval = -1;
4823 (void) ddi_dma_unbind_handle(dhandle);
4824 ddi_dma_mem_free(&acchandle);
4825 ddi_dma_free_handle(&dhandle);
4826 return (retval);
4828 getmap_fail:
4829 if (dhandle) {
4830 if (bound)
4831 (void) ddi_dma_unbind_handle(dhandle);
4832 ddi_dma_free_handle(&dhandle);
4834 if (buf)
4835 ddi_dma_mem_free(&acchandle);
4836 return (-1);
4839 static void
4840 socal_wcopy(uint_t *h_src, uint_t *h_dest, int len)
4842 int i;
4843 for (i = 0; i < len/4; i++) {
4844 *h_dest++ = *h_src++;
4848 static void
4849 socal_flush_overflowq(socal_state_t *socalp, int port, int q_no)
4851 socal_kcq_t *kcq;
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;
4857 fpkt1 = NULL;
4858 while (fpkt2 != NULL) {
4859 if ((((soc_request_t *)&fpkt2->fcal_socal_request)
4860 ->sr_soc_hdr.sh_flags & SOC_PORT_B) == port) {
4861 if (fpkt1 == NULL)
4862 kcq->skc_overflowh = fpkt2->fcal_pkt_next;
4863 else {
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;
4870 head = fpkt2;
4871 fpkt2 = tmp;
4872 SOCAL_ID_FREE(head->fcal_socal_request.
4873 sr_soc_hdr.sh_request_token);
4874 } else {
4875 fpkt1 = fpkt2;
4876 fpkt2 = fpkt2->fcal_pkt_next;
4879 mutex_exit(&kcq->skc_mtx);
4880 fpkt2 = head;
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);
4888 fpkt2 = tmp;
4892 static void
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);
4906 return;
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));
4913 return;
4916 kcq->deferred_intr_timeoutid = 0;
4917 mutex_exit(&kcq->skc_mtx);
4918 socal_intr_solicited(socalp, 0);
4921 static void
4922 socal_take_core(void *arg)
4924 socal_state_t *socalp = (socal_state_t *)arg;
4925 int i, instance;
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);
4944 cmn_err(CE_PANIC,
4945 "socal take core (socal instance %d)", instance);
4949 * Preset AL_PA in hardware, if is told.
4951 static void
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];
4960 if (port == 0) {
4961 accum &= 0x00FFFFFF;
4962 accum |= ((harda & 0xFF) << 24);
4963 } else {
4964 accum &= 0xFF00FFFF;
4965 accum |= ((harda & 0xFF) << 16);
4967 xrp[SOCAL_XRAM_PORTA_HRDA/4] = accum;
4971 * Target-Mode attach function
4973 fcal_transport_t *
4974 socal_sftm_attach(dev_t dev, int loop_id)
4976 int instance = getminor(dev) / 2;
4977 int port = getminor(dev) % 2;
4978 int hard_alpa;
4979 char *name;
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)
4987 return (NULL);
4990 * If no soft state structure, return
4992 socalp = ddi_get_soft_state(socal_soft_state_p, instance);
4993 if (socalp == NULL)
4994 return (NULL);
4997 * If the port is already attached, return
4999 if (socalp->port_state[port].sp_status & PORT_CHILD_INIT)
5000 return (NULL);
5002 if (loop_id < 0 || loop_id > 126)
5003 return (NULL);
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);
5011 return (NULL);
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 - "
5026 "using Loop-id %d",
5027 instance, loop_id);
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);
5045 return (0);