1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /*
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
28 */
29
30 /*
31 * socal - Serial Optical Channel Arbitrated Loop host adapter driver.
32 */
33
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>
44
45 #include <sys/cmn_err.h>
46 #include <sys/stropts.h>
47 #include <sys/kmem.h>
48
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>
59
60 #include <sys/file.h>
61 #include <sys/syslog.h>
62
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>
78
79 /*
80 * Local Macros
81 */
82
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
101
102
103 /* defines for properties */
104 #define SOCAL_PORT_NO_PROP "socal_port"
105 #define SOCAL_ALT_PORT_NO_PROP "port#"
106
107 /* for socal_force_reset() */
108 #define RESET_PORT 1
109 #define DONT_RESET_PORT 0
110
111 /*
112 * Driver Entry points.
113 */
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);
128
129 /*
130 * FC_AL transport functions.
131 */
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 *);
148
149 /*
150 * Driver internal functions.
151 */
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);
194
195 /*
196 * SOC+ Circular Queue Management routines.
197 */
198 static int socal_cq_enque(socal_state_t *, socal_port_t *, cqe_t *, int,
199 fcal_sleep_t, fcal_packet_t *, int);
200
201 /*
202 * Utility functions
203 */
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);
206
207 /*
208 * Set this bit to enable 64-bit sus mode
209 */
210 static int socal_64bitsbus = 1;
211
212 /*
213 * Default soc dma limits
214 */
215
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)
219 };
220
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 */
234 };
235
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 */
240 };
241
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
254 };
255
256 /*
257 * Table used for setting the burst size in the soc+ config register
258 */
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
267 };
268
269 /*
270 * Table for setting the burst size for 64-bit sbus mode in soc+'s CR
271 */
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)
281 };
282
283 /*
284 * Tables used to define the sizes of the Circular Queues
285 *
286 * To conserve DVMA/IOPB space, we make some of these queues small...
287 */
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 */
293 };
294
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 */
300 };
301
302 /*
303 * Bus ops vector
304 */
305
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*)() */
323 };
324
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)() */
344 };
345
346 /*
347 * Soc driver ops structure.
348 */
349
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 */
363 };
364
365 /*
366 * Driver private variables.
367 */
368
369 static void *socal_soft_state_p = NULL;
370 static ddi_dma_lim_t *socallim = NULL;
371
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
386 };
387
388 /*
389 * Firmware related externs
390 */
391 extern uint32_t socal_ucode[];
392 extern size_t socal_ucode_size;
393
394 /*
395 * This is the loadable module wrapper: "module configuration section".
396 */
397
398 #include <sys/modctl.h>
399 extern struct mod_ops mod_driverops;
400
401 /*
402 * Module linkage information for the kernel.
403 */
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 */
410 };
411
412 static struct modlinkage modlinkage = {
413 MODREV_1, (void *)&modldrv, NULL
414 };
415
416 /*
417 * This is the module initialization/completion routines
418 */
419
420 #if !defined(lint)
421 static char socal_initmsg[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
422 #endif
423
424 int
_init(void)425 _init(void)
426 {
427 int stat;
428
429 DEBUGF(4, (CE_CONT, socal_initmsg));
430
431 /* Allocate soft state. */
432 stat = ddi_soft_state_init(&socal_soft_state_p,
433 sizeof (socal_state_t), SOCAL_INIT_ITEMS);
434 if (stat != 0)
435 return (stat);
436
437 /* Install the module */
438 stat = mod_install(&modlinkage);
439 if (stat != 0)
440 ddi_soft_state_fini(&socal_soft_state_p);
441
442 DEBUGF(4, (CE_CONT, "socal: _init: return=%d\n", stat));
443 return (stat);
444 }
445
446 int
_fini(void)447 _fini(void)
448 {
449 int stat;
450
451 if ((stat = mod_remove(&modlinkage)) != 0)
452 return (stat);
453
454 DEBUGF(4, (CE_CONT, "socal: _fini: \n"));
455
456 ddi_soft_state_fini(&socal_soft_state_p);
457
458 DEBUGF(4, (CE_CONT, "socal: _fini: return=%d\n", stat));
459 return (stat);
460 }
461
462 int
_info(struct modinfo * modinfop)463 _info(struct modinfo *modinfop)
464 {
465 return (mod_info(&modlinkage, modinfop));
466 }
467
468
469 int
socal_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)470 socal_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
471 {
472 int instance;
473 socal_state_t *socalp;
474 struct ether_addr ourmacaddr;
475 socal_port_t *porta, *portb;
476 char buf[MAXPATHLEN];
477 char *cptr, *wwn;
478 int y;
479 int i, j;
480 int burstsize;
481 short s;
482 int loop_id;
483
484 int rval;
485
486
487 instance = ddi_get_instance(dip);
488
489 DEBUGF(4, (CE_CONT, "socal%d entering attach: cmd=%x\n", instance,
490 cmd));
491
492 if (cmd == DDI_RESUME) {
493 if ((socalp = ddi_get_driver_private(dip)) == NULL)
494 return (DDI_FAILURE);
495
496 if (!socalp->socal_shutdown) {
497 /* our work is already done */
498 return (DDI_SUCCESS);
499 }
500 if (socal_start(socalp) != FCAL_SUCCESS) {
501 return (DDI_FAILURE);
502 }
503 DEBUGF(4, (CE_CONT, "socal%d resumed\n", instance));
504 return (DDI_SUCCESS);
505 }
506
507 if (cmd != DDI_ATTACH) {
508 return (DDI_FAILURE);
509 }
510
511 if (ddi_dev_is_sid(dip) != DDI_SUCCESS) {
512 cmn_err(CE_WARN, "socal%d probe: Not self-identifying",
513 instance);
514 return (DDI_FAILURE);
515 }
516
517 /* If we are in a slave-slot, then we can't be used. */
518 if (ddi_slaveonly(dip) == DDI_SUCCESS) {
519 cmn_err(CE_WARN,
520 "socal%d attach failed: device in slave-only slot",
521 instance);
522 return (DDI_FAILURE);
523 }
524
525 if (ddi_intr_hilevel(dip, 0)) {
526 /*
527 * Interrupt number '0' is a high-level interrupt.
528 * At this point you either add a special interrupt
529 * handler that triggers a soft interrupt at a lower level,
530 * or - more simply and appropriately here - you just
531 * fail the attach.
532 */
533 cmn_err(CE_WARN,
534 "socal%d attach failed: hilevel interrupt unsupported",
535 instance);
536 return (DDI_FAILURE);
537 }
538
539 /* Allocate soft state. */
540 if (ddi_soft_state_zalloc(socal_soft_state_p, instance)
541 != DDI_SUCCESS) {
542 cmn_err(CE_WARN, "socal%d attach failed: alloc soft state",
543 instance);
544 return (DDI_FAILURE);
545 }
546 DEBUGF(4, (CE_CONT, "socal%d attach: allocated soft state\n",
547 instance));
548
549 /*
550 * Initialize the state structure.
551 */
552 socalp = ddi_get_soft_state(socal_soft_state_p, instance);
553 if (socalp == (socal_state_t *)NULL) {
554 cmn_err(CE_WARN, "socal%d attach failed: bad soft state",
555 instance);
556 return (DDI_FAILURE);
557 }
558 DEBUGF(4, (CE_CONT, "socal%d: attach: soc soft state ptr=0x%p\n",
559 instance, socalp));
560
561 socalp->dip = dip;
562 socallim = &default_socallim;
563 porta = &socalp->port_state[0];
564 portb = &socalp->port_state[1];
565
566 /* Get the full path name for displaying error messages */
567 cptr = ddi_pathname(dip, buf);
568 (void) strcpy(socalp->socal_name, cptr);
569
570 porta->sp_unsol_cb = NULL;
571 portb->sp_unsol_cb = NULL;
572 porta->sp_port = 0;
573 portb->sp_port = 1;
574 porta->sp_board = socalp;
575 portb->sp_board = socalp;
576
577 porta->sp_lilpmap_valid = 0;
578 portb->sp_lilpmap_valid = 0;
579
580 /*
581 * If an hard loop-id property is present, then the port is going
582 * to be used in target-mode so set the target-mode flag.
583 */
584 loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
585 "port0-loop-id", 127);
586 if (loop_id >= 0 && loop_id <= 126) {
587 porta->sp_status |= PORT_TARGET_MODE;
588 porta->sp_hard_alpa = socal_switch_to_alpa[loop_id];
589 } else porta->sp_hard_alpa = 0xfe;
590
591 loop_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
592 "port1-loop-id", 127);
593 if (loop_id >= 0 && loop_id <= 126) {
594 portb->sp_status |= PORT_TARGET_MODE;
595 portb->sp_hard_alpa = socal_switch_to_alpa[loop_id];
596 } else portb->sp_hard_alpa = 0xfe;
597
598 /* Get out Node wwn and calculate port wwns */
599 rval = ddi_prop_op(DDI_DEV_T_ANY, dip,
600 PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
601 DDI_PROP_CANSLEEP, "wwn", (caddr_t)&wwn, &i);
602
603 if ((rval != DDI_PROP_SUCCESS) || (i < FC_WWN_SIZE) ||
604 (bcmp(wwn, "00000000", FC_WWN_SIZE) == 0)) {
605 (void) localetheraddr((struct ether_addr *)NULL, &ourmacaddr);
606
607 bcopy((caddr_t)&ourmacaddr, (caddr_t)&s, sizeof (short));
608 socalp->socal_n_wwn.w.wwn_hi = s;
609 bcopy((caddr_t)&ourmacaddr+2,
610 (caddr_t)&socalp->socal_n_wwn.w.wwn_lo,
611 sizeof (uint_t));
612 socalp->socal_n_wwn.w.naa_id = NAA_ID_IEEE;
613 socalp->socal_n_wwn.w.nport_id = 0;
614 } else {
615 bcopy((caddr_t)wwn, (caddr_t)&socalp->socal_n_wwn, FC_WWN_SIZE);
616 }
617
618 if (rval == DDI_SUCCESS)
619 kmem_free((void *)wwn, i);
620
621 for (i = 0; i < FC_WWN_SIZE; i++) {
622 (void) sprintf(&socalp->socal_stats.node_wwn[i << 1],
623 "%02x", socalp->socal_n_wwn.raw_wwn[i]);
624 }
625 DEBUGF(4, (CE_CONT, "socal%d attach: node wwn: %s\n",
626 instance, socalp->socal_stats.node_wwn));
627
628 bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&porta->sp_p_wwn,
629 sizeof (la_wwn_t));
630 bcopy((caddr_t)&socalp->socal_n_wwn, (caddr_t)&portb->sp_p_wwn,
631 sizeof (la_wwn_t));
632 porta->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
633 portb->sp_p_wwn.w.naa_id = NAA_ID_IEEE_EXTENDED;
634 porta->sp_p_wwn.w.nport_id = instance*2;
635 portb->sp_p_wwn.w.nport_id = instance*2+1;
636
637 for (i = 0; i < FC_WWN_SIZE; i++) {
638 (void) sprintf(&socalp->socal_stats.port_wwn[0][i << 1],
639 "%02x", porta->sp_p_wwn.raw_wwn[i]);
640 (void) sprintf(&socalp->socal_stats.port_wwn[1][i << 1],
641 "%02x", portb->sp_p_wwn.raw_wwn[i]);
642 }
643 DEBUGF(4, (CE_CONT, "socal%d attach: porta wwn: %s\n",
644 instance, socalp->socal_stats.port_wwn[0]));
645 DEBUGF(4, (CE_CONT, "socal%d attach: portb wwn: %s\n",
646 instance, socalp->socal_stats.port_wwn[1]));
647
648 if ((porta->sp_transport = (fcal_transport_t *)
649 kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
650 socal_disp_err(socalp, CE_WARN, "attach.4011",
651 "attach failed: unable to alloc xport struct");
652 goto fail;
653 }
654
655 if ((portb->sp_transport = (fcal_transport_t *)
656 kmem_zalloc(sizeof (fcal_transport_t), KM_SLEEP)) == NULL) {
657 socal_disp_err(socalp, CE_WARN, "attach.4012",
658 "attach failed: unable to alloc xport struct");
659 goto fail;
660 }
661 DEBUGF(4, (CE_CONT, "socal%d attach: allocated transport structs\n",
662 instance));
663
664 /*
665 * Map the external ram and registers for SOC+.
666 * Note: Soc+ sbus host adapter provides 3 register definition
667 * but on-board Soc+'s may have only one register definition.
668 */
669 if ((ddi_dev_nregs(dip, &i) == DDI_SUCCESS) && (i == 1)) {
670 /* Map XRAM */
671 if (ddi_map_regs(dip, 0, &socalp->socal_xrp, 0, 0)
672 != DDI_SUCCESS) {
673 socalp->socal_xrp = NULL;
674 socal_disp_err(socalp, CE_WARN, "attach.4020",
675 "attach failed: unable to map XRAM");
676 goto fail;
677 }
678 /* Map registers */
679 socalp->socal_rp = (socal_reg_t *)(socalp->socal_xrp +
680 SOCAL_XRAM_SIZE);
681 } else {
682 /* Map EEPROM */
683 if (ddi_map_regs(dip, 0, &socalp->socal_eeprom, 0, 0) !=
684 DDI_SUCCESS) {
685 socalp->socal_eeprom = NULL;
686 socal_disp_err(socalp, CE_WARN, "attach.4010",
687 "attach failed: unable to map eeprom");
688 goto fail;
689 }
690 DEBUGF(4, (CE_CONT, "socal%d attach: mapped eeprom 0x%p\n",
691 instance, socalp->socal_eeprom));
692 /* Map XRAM */
693 if (ddi_map_regs(dip, 1, &socalp->socal_xrp, 0, 0) !=
694 DDI_SUCCESS) {
695 socalp->socal_xrp = NULL;
696 socal_disp_err(socalp, CE_WARN, "attach.4020",
697 "attach failed: unable to map XRAM");
698 goto fail;
699 }
700 DEBUGF(4, (CE_CONT, "socal%d attach: mapped xram 0x%p\n",
701 instance, socalp->socal_xrp));
702 /* Map registers */
703 if (ddi_map_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0) !=
704 DDI_SUCCESS) {
705 socalp->socal_rp = NULL;
706 socal_disp_err(socalp, CE_WARN, "attach.4030",
707 "attach failed: unable to map registers");
708 goto fail;
709 }
710 DEBUGF(4, (CE_CONT, "socal%d attach: mapped regs 0x%p\n",
711 instance, socalp->socal_rp));
712 }
713 /*
714 * Check to see we really have a SOC+ Host Adapter card installed
715 */
716 if (ddi_peek32(dip, (int32_t *)&socalp->socal_rp->socal_csr.w,
717 (int32_t *)NULL) != DDI_SUCCESS) {
718 socal_disp_err(socalp, CE_WARN, "attach.4040",
719 "attach failed: unable to access status register");
720 goto fail;
721 }
722 /* now that we have our registers mapped make sure soc+ reset */
723 socal_disable(socalp);
724
725 /* try defacing a spot in XRAM */
726 if (ddi_poke32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
727 0xdefaced) != DDI_SUCCESS) {
728 socal_disp_err(socalp, CE_WARN, "attach.4050",
729 "attach failed: unable to write host adapter XRAM");
730 goto fail;
731 }
732
733 /* see if it stayed defaced */
734 if (ddi_peek32(dip, (int32_t *)(socalp->socal_xrp + SOCAL_XRAM_UCODE),
735 (int32_t *)&y)
736 != DDI_SUCCESS) {
737 socal_disp_err(socalp, CE_WARN, "attach.4051",
738 "attach failed: unable to access host adapter XRAM");
739 goto fail;
740 }
741
742 #ifdef DEBUG
743 for (i = 0; i < 4; i++) {
744 socalp->socal_rp->socal_cr.w &=
745 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
746 socalp->socal_rp->socal_cr.w |= i<<24;
747 cptr = (char *)(socal_xrambuf + (i*0x10000));
748 bcopy((caddr_t)socalp->socal_xrp, (caddr_t)cptr, 0x10000);
749 }
750 socalp->socal_rp->socal_cr.w &= ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
751 #endif
752
753 DEBUGF(4, (CE_CONT, "socal%d attach: read xram\n", instance));
754
755 if (y != 0xdefaced) {
756 socal_disp_err(socalp, CE_WARN, "attach.4052",
757 "attach failed: read/write mismatch in XRAM");
758 goto fail;
759 }
760
761 /* Point to the SOC XRAM CQ Descriptor locations. */
762 socalp->xram_reqp = (soc_cq_t *)(socalp->socal_xrp +
763 SOCAL_XRAM_REQ_DESC);
764 socalp->xram_rspp = (soc_cq_t *)(socalp->socal_xrp +
765 SOCAL_XRAM_RSP_DESC);
766
767 if ((socalp->socal_ksp = kstat_create("socal", instance, "statistics",
768 "controller", KSTAT_TYPE_RAW, sizeof (struct socal_stats),
769 KSTAT_FLAG_VIRTUAL)) == NULL) {
770 socal_disp_err(socalp, CE_WARN, "attach.4053",
771 "unable to create kstats");
772 } else {
773 socalp->socal_stats.version = 2;
774 (void) sprintf(socalp->socal_stats.drvr_name,
775 "%s: %s", SOCAL_NAME, socal_version);
776 socalp->socal_stats.pstats[0].port = 0;
777 socalp->socal_stats.pstats[1].port = 1;
778 socalp->socal_ksp->ks_data = (void *)&socalp->socal_stats;
779 kstat_install(socalp->socal_ksp);
780 }
781
782 /*
783 * Install a dummy interrupt routine.
784 */
785 if (ddi_add_intr(dip,
786 (uint_t)0,
787 &socalp->iblkc,
788 &socalp->idevc,
789 socal_dummy_intr,
790 (caddr_t)socalp) != DDI_SUCCESS) {
791 socal_disp_err(socalp, CE_WARN, "attach.4060",
792 "attach failed: unable to install interrupt handler");
793 goto fail;
794 }
795
796 ddi_set_driver_private(dip, socalp);
797
798 /* initialize the interrupt mutex */
799 mutex_init(&socalp->k_imr_mtx, NULL, MUTEX_DRIVER,
800 (void *)socalp->iblkc);
801
802 mutex_init(&socalp->board_mtx, NULL, MUTEX_DRIVER,
803 (void *)socalp->iblkc);
804 mutex_init(&socalp->ioctl_mtx, NULL, MUTEX_DRIVER,
805 (void *)socalp->iblkc);
806
807 /* initialize the abort mutex */
808 mutex_init(&socalp->abort_mtx, NULL, MUTEX_DRIVER,
809 (void *)socalp->iblkc);
810
811 cv_init(&socalp->board_cv, NULL, CV_DRIVER, NULL);
812 DEBUGF(4, (CE_CONT,
813 "socal%d: attach: inited imr mutex, board mutex, board cv\n",
814 instance));
815
816 /* init the port mutexes */
817 mutex_init(&porta->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
818 cv_init(&porta->sp_cv, NULL, CV_DRIVER, NULL);
819 mutex_init(&portb->sp_mtx, NULL, MUTEX_DRIVER, socalp->iblkc);
820 cv_init(&portb->sp_cv, NULL, CV_DRIVER, NULL);
821 DEBUGF(4, (CE_CONT, "socal%d: attach: inited port mutexes and cvs\n",
822 instance));
823
824 /* get local copy of service params */
825 socal_wcopy((uint_t *)socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS,
826 (uint_t *)socalp->socal_service_params, SOCAL_SVC_LENGTH);
827 DEBUGF(4, (CE_CONT, "socal%d: attach: got service params\n", instance));
828 /*
829 * Initailize the FCAL transport interface.
830 */
831 socal_init_transport_interface(socalp);
832 DEBUGF(4, (CE_CONT, "socal%d: attach: initalized transport interface\n",
833 instance));
834
835 /*
836 * Allocate request and response queues and init their mutexs.
837 */
838 for (i = 0; i < SOCAL_N_CQS; i++) {
839 if (socal_cqalloc_init(socalp, i) != FCAL_SUCCESS) {
840 goto fail;
841 }
842 }
843 DEBUGF(4, (CE_CONT, "socal%d: attach: allocated cqs\n", instance));
844
845 /*
846 * Adjust the burst size we'll use.
847 */
848 burstsize = ddi_dma_burstsizes(socalp->request[0].skc_dhandle);
849 DEBUGF(4, (CE_CONT, "socal%d: attach: burstsize = 0x%x\n",
850 instance, burstsize));
851 j = burstsize & BURSTSIZE_MASK;
852 for (i = 0; socal_burst32_table[i] != SOCAL_CR_BURST_64; i++)
853 if (!(j >>= 1)) break;
854
855 socalp->socal_cfg = (socalp->socal_cfg & ~SOCAL_CR_SBUS_BURST_SIZE_MASK)
856 | socal_burst32_table[i];
857
858 if (socal_64bitsbus) {
859 if (ddi_dma_set_sbus64(socalp->request[0].skc_dhandle,
860 socal_dma_attr.dma_attr_burstsizes | BURST128) ==
861 DDI_SUCCESS) {
862 DEBUGF(4, (CE_CONT, "socal%d: enabled 64 bit sbus\n",
863 instance));
864 socalp->socal_cfg |= SOCAL_CR_SBUS_ENHANCED;
865 burstsize = ddi_dma_burstsizes(socalp->request[0].
866 skc_dhandle);
867 DEBUGF(4, (CE_CONT, "socal%d: attach: 64bit burstsize = 0x%x\n",
868 instance, burstsize));
869 j = burstsize & BURSTSIZE_MASK;
870 for (i = 0; socal_burst64_table[i] !=
871 (SOCAL_CR_BURST_128 << 8); i++)
872 if (!(j >>= 1))
873 break;
874
875 socalp->socal_cfg = (socalp->socal_cfg &
876 ~SOCAL_CR_SBUS_BURST_SIZE_64BIT_MASK) |
877 socal_burst64_table[i];
878 }
879 }
880
881 ddi_remove_intr(dip, 0, socalp->iblkc);
882 socalp->iblkc = (void *)NULL;
883 /*
884 * Install the interrupt routine.
885 */
886 if (ddi_add_intr(dip,
887 (uint_t)0,
888 &socalp->iblkc,
889 &socalp->idevc,
890 socal_intr,
891 (caddr_t)socalp) != DDI_SUCCESS) {
892 socal_disp_err(socalp, CE_WARN, "attach.4060",
893 "attach failed: unable to install interrupt handler");
894 goto fail;
895 }
896
897 DEBUGF(4, (CE_CONT, "socal%d: attach: set config reg %x\n",
898 instance, socalp->socal_cfg));
899
900 if (ddi_create_minor_node(dip, SOCAL_PORTA_NAME, S_IFCHR,
901 instance*N_SOCAL_NPORTS, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
902 goto fail;
903 if (ddi_create_minor_node(dip, SOCAL_PORTB_NAME, S_IFCHR,
904 instance*N_SOCAL_NPORTS+1, SOCAL_NT_PORT, 0) != DDI_SUCCESS)
905 goto fail;
906
907 if (socal_start(socalp) != FCAL_SUCCESS)
908 goto fail;
909 DEBUGF(4, (CE_CONT, "socal%d: attach: soc+ started\n", instance));
910
911 ddi_report_dev(dip);
912
913 DEBUGF(2, (CE_CONT, "socal%d: attach O.K.\n\n", instance));
914
915 return (DDI_SUCCESS);
916
917 fail:
918 DEBUGF(4, (CE_CONT, "socal%d: attach: DDI_FAILURE\n", instance));
919
920 /* Make sure soc reset */
921 socal_disable(socalp);
922
923 /* let detach do the dirty work */
924 (void) socal_dodetach(dip);
925
926 return (DDI_FAILURE);
927 }
928
929 static int
socal_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)930 socal_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
931 {
932 int resp;
933 socal_state_t *socalp;
934 int i;
935
936
937 switch (cmd) {
938
939 case DDI_SUSPEND:
940 DEBUGF(4, (CE_CONT, "socal: suspend called\n"));
941
942 if ((socalp = ddi_get_driver_private(dip)) == NULL)
943 return (DDI_FAILURE);
944
945 /*
946 * If any of the ports are in target-mode, don't suspend
947 */
948 for (i = 0; i < N_SOCAL_NPORTS; i++) {
949 if (socalp->port_state[i].sp_status & PORT_TARGET_MODE)
950 return (DDI_FAILURE);
951 }
952
953 /* do not restart socal after reset */
954 socal_force_reset((void *)socalp, 0, DONT_RESET_PORT);
955
956 return (DDI_SUCCESS);
957
958 case DDI_DETACH:
959 DEBUGF(4, (CE_CONT, "socal: detach called\n"));
960 resp = socal_dodetach(dip);
961 if (resp == DDI_SUCCESS)
962 ddi_set_driver_private(dip, NULL);
963 return (resp);
964
965 default:
966 return (DDI_FAILURE);
967 }
968 }
969
970 static int
socal_dodetach(dev_info_t * dip)971 socal_dodetach(dev_info_t *dip)
972 {
973
974 int instance = ddi_get_instance(dip);
975 int i;
976 socal_state_t *socalp;
977 socal_port_t *portp;
978 socal_unsol_cb_t *cb, *cbn = NULL;
979
980 /* Get the soft state struct. */
981 if ((socalp = ddi_get_soft_state(socal_soft_state_p, instance)) == 0) {
982 return (DDI_FAILURE);
983 }
984
985 /*
986 * If somebody is still attached to us from above fail
987 * detach.
988 */
989 mutex_enter(&socalp->board_mtx);
990 if (socalp->socal_busy > 0) {
991 mutex_exit(&socalp->board_mtx);
992 return (DDI_FAILURE);
993 }
994 /* mark socal_busy = -1 to disallow sftm attach */
995 socalp->socal_busy = -1;
996 mutex_exit(&socalp->board_mtx);
997
998 /* Make sure soc+ reset */
999 mutex_enter(&socalp->k_imr_mtx);
1000 socal_disable(socalp);
1001 mutex_exit(&socalp->k_imr_mtx);
1002
1003 /* remove soc+ interrupt */
1004 if (socalp->iblkc != (void *)NULL) {
1005 ddi_remove_intr(dip, (uint_t)0, socalp->iblkc);
1006 DEBUGF(2, (CE_CONT,
1007 "socal%d: detach: Removed SOC+ interrupt from ddi\n",
1008 instance));
1009 }
1010
1011 for (i = 0; i < N_SOCAL_NPORTS; i++) {
1012 portp = &socalp->port_state[i];
1013 mutex_destroy(&portp->sp_mtx);
1014 cv_destroy(&portp->sp_cv);
1015 mutex_destroy(&portp->sp_transport->fcal_mtx);
1016 cv_destroy(&portp->sp_transport->fcal_cv);
1017 kmem_free((void *)portp->sp_transport,
1018 sizeof (fcal_transport_t));
1019 for (cb = portp->sp_unsol_cb; cb != (socal_unsol_cb_t *)NULL;
1020 cb = cbn) {
1021 cbn = cb->next;
1022 kmem_free((void *)cb, sizeof (socal_unsol_cb_t));
1023 }
1024 portp->sp_unsol_cb = (socal_unsol_cb_t *)NULL;
1025 }
1026
1027 /*
1028 * Free request queues, if allocated
1029 */
1030 for (i = 0; i < SOCAL_N_CQS; i++) {
1031 /* Free the queues and destroy their mutexes. */
1032 mutex_destroy(&socalp->request[i].skc_mtx);
1033 mutex_destroy(&socalp->response[i].skc_mtx);
1034 cv_destroy(&socalp->request[i].skc_cv);
1035 cv_destroy(&socalp->response[i].skc_cv);
1036
1037 if (socalp->request[i].skc_dhandle) {
1038 (void) ddi_dma_unbind_handle(socalp->
1039 request[i].skc_dhandle);
1040 ddi_dma_free_handle(&socalp->request[i].skc_dhandle);
1041 }
1042 if (socalp->request[i].skc_cq_raw) {
1043 ddi_dma_mem_free(&socalp->request[i].skc_acchandle);
1044 socalp->request[i].skc_cq_raw = NULL;
1045 socalp->request[i].skc_cq = NULL;
1046 }
1047 if (socalp->response[i].skc_dhandle) {
1048 (void) ddi_dma_unbind_handle(socalp->
1049 response[i].skc_dhandle);
1050 ddi_dma_free_handle(&socalp->response[i].skc_dhandle);
1051 }
1052 if (socalp->response[i].skc_cq_raw) {
1053 ddi_dma_mem_free(&socalp->response[i].skc_acchandle);
1054 socalp->response[i].skc_cq_raw = NULL;
1055 socalp->response[i].skc_cq = NULL;
1056 }
1057 if (socalp->request[i].deferred_intr_timeoutid) {
1058 (void) untimeout(socalp->
1059 request[i].deferred_intr_timeoutid);
1060 }
1061 if (socalp->response[i].deferred_intr_timeoutid) {
1062 (void) untimeout(socalp->
1063 response[i].deferred_intr_timeoutid);
1064 }
1065 }
1066
1067 mutex_destroy(&socalp->abort_mtx);
1068 mutex_destroy(&socalp->board_mtx);
1069 mutex_destroy(&socalp->ioctl_mtx);
1070 cv_destroy(&socalp->board_cv);
1071
1072 /*
1073 * Free soc data buffer pool
1074 */
1075 if (socalp->pool_dhandle) {
1076 (void) ddi_dma_unbind_handle(socalp->pool_dhandle);
1077 ddi_dma_free_handle(&socalp->pool_dhandle);
1078 }
1079 if (socalp->pool) {
1080 ddi_dma_mem_free(&socalp->pool_acchandle);
1081 }
1082
1083 /* release register maps */
1084 /* Unmap EEPROM */
1085 if (socalp->socal_eeprom != NULL) {
1086 ddi_unmap_regs(dip, 0, &socalp->socal_eeprom, 0, 0);
1087 }
1088
1089 /* Unmap XRAM */
1090 if (socalp->socal_xrp != NULL) {
1091 ddi_unmap_regs(dip, 1, &socalp->socal_xrp, 0, 0);
1092 }
1093
1094 /* Unmap registers */
1095 if (socalp->socal_rp != NULL) {
1096 ddi_unmap_regs(dip, 2, (caddr_t *)&socalp->socal_rp, 0, 0);
1097 }
1098
1099 if (socalp->socal_ksp != NULL)
1100 kstat_delete(socalp->socal_ksp);
1101
1102 mutex_destroy(&socalp->k_imr_mtx);
1103
1104 ddi_remove_minor_node(dip, NULL);
1105
1106 ddi_soft_state_free(socal_soft_state_p, instance);
1107
1108 return (DDI_SUCCESS);
1109 }
1110
1111
1112 int
socal_bus_ctl(dev_info_t * dip,dev_info_t * rip,ddi_ctl_enum_t op,void * a,void * v)1113 socal_bus_ctl(dev_info_t *dip, dev_info_t *rip, ddi_ctl_enum_t op,
1114 void *a, void *v)
1115 {
1116 int port;
1117
1118
1119 switch (op) {
1120 case DDI_CTLOPS_REPORTDEV:
1121 port = ddi_getprop(DDI_DEV_T_ANY, rip, DDI_PROP_DONTPASS,
1122 SOCAL_PORT_NO_PROP, -1);
1123 if ((port < 0) || (port > 1)) {
1124 port = ddi_getprop(DDI_DEV_T_ANY, rip,
1125 DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
1126 }
1127 /* log text identifying this driver (d) & its child (r) */
1128 cmn_err(CE_CONT, "?%s%d at %s%d: socal_port %d\n",
1129 ddi_driver_name(rip), ddi_get_instance(rip),
1130 ddi_driver_name(dip), ddi_get_instance(dip),
1131 port);
1132 break;
1133
1134 case DDI_CTLOPS_INITCHILD: {
1135 dev_info_t *child_dip = (dev_info_t *)a;
1136 char name[MAXNAMELEN];
1137 socal_state_t *socalp;
1138
1139 if ((socalp = ddi_get_driver_private(dip)) == NULL)
1140 return (DDI_FAILURE);
1141
1142 port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1143 DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
1144
1145 if ((port < 0) || (port > 1)) {
1146 port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1147 DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
1148 if ((port < 0) || (port > 1)) {
1149 return (DDI_NOT_WELL_FORMED);
1150 }
1151 }
1152 mutex_enter(&socalp->board_mtx);
1153 mutex_enter(&socalp->port_state[port].sp_mtx);
1154 if (socalp->port_state[port].sp_status &
1155 (PORT_CHILD_INIT | PORT_TARGET_MODE)) {
1156 mutex_exit(&socalp->port_state[port].sp_mtx);
1157 mutex_exit(&socalp->board_mtx);
1158 return (DDI_FAILURE);
1159 }
1160 socalp->socal_busy++;
1161 socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
1162 mutex_exit(&socalp->port_state[port].sp_mtx);
1163 mutex_exit(&socalp->board_mtx);
1164 ddi_set_parent_data(child_dip,
1165 socalp->port_state[port].sp_transport);
1166 (void) sprintf((char *)name, "%x,0", port);
1167 ddi_set_name_addr(child_dip, name);
1168 break;
1169 }
1170
1171 case DDI_CTLOPS_UNINITCHILD: {
1172 dev_info_t *child_dip = (dev_info_t *)a;
1173 socal_state_t *socalp;
1174
1175 socalp = ddi_get_driver_private(dip);
1176 port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1177 DDI_PROP_DONTPASS, SOCAL_PORT_NO_PROP, -1);
1178
1179 if ((port < 0) || (port > 1)) {
1180 port = ddi_getprop(DDI_DEV_T_ANY, child_dip,
1181 DDI_PROP_DONTPASS, SOCAL_ALT_PORT_NO_PROP, -1);
1182 if ((port < 0) || (port > 1)) {
1183 return (DDI_NOT_WELL_FORMED);
1184 }
1185 }
1186
1187 ddi_set_parent_data(child_dip, NULL);
1188 (void) ddi_set_name_addr(child_dip, NULL);
1189 mutex_enter(&socalp->board_mtx);
1190 mutex_enter(&socalp->port_state[port].sp_mtx);
1191 socalp->socal_busy--;
1192 socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
1193 mutex_exit(&socalp->port_state[port].sp_mtx);
1194 mutex_exit(&socalp->board_mtx);
1195
1196 break;
1197 }
1198
1199 case DDI_CTLOPS_IOMIN: {
1200 int val;
1201
1202 val = *((int *)v);
1203 val = maxbit(val, socallim->dlim_minxfer);
1204 /*
1205 * The 'arg' value of nonzero indicates 'streaming' mode.
1206 * If in streaming mode, pick the largest of our burstsizes
1207 * available and say that that is our minimum value (modulo
1208 * what minxfer is).
1209 */
1210 if ((int)(uintptr_t)a) {
1211 val = maxbit(val,
1212 1<<(ddi_fls(socallim->dlim_burstsizes)-1));
1213 } else {
1214 val = maxbit(val,
1215 1<<(ddi_ffs(socallim->dlim_burstsizes)-1));
1216 }
1217
1218 *((int *)v) = val;
1219 return (ddi_ctlops(dip, rip, op, a, v));
1220 }
1221
1222 /*
1223 * These ops are not available on this nexus.
1224 */
1225
1226 case DDI_CTLOPS_DMAPMAPC:
1227 case DDI_CTLOPS_REGSIZE:
1228 case DDI_CTLOPS_NREGS:
1229 case DDI_CTLOPS_AFFINITY:
1230 case DDI_CTLOPS_SIDDEV:
1231 case DDI_CTLOPS_POKE:
1232 case DDI_CTLOPS_PEEK:
1233 return (DDI_FAILURE);
1234
1235 case DDI_CTLOPS_SLAVEONLY:
1236 case DDI_CTLOPS_REPORTINT:
1237 default:
1238 /*
1239 * Remaining requests get passed up to our parent
1240 */
1241 DEBUGF(2, (CE_CONT, "%s%d: op (%d) from %s%d\n",
1242 ddi_get_name(dip), ddi_get_instance(dip),
1243 op, ddi_get_name(rip), ddi_get_instance(rip)));
1244 return (ddi_ctlops(dip, rip, op, a, v));
1245 }
1246
1247 return (DDI_SUCCESS);
1248 }
1249
1250
1251 /*ARGSUSED*/
1252 /*
1253 * int
1254 * socal_getinfo() - Given the device number, return the devinfo
1255 * pointer or the instance number. Note: this routine must be
1256 * successful on DDI_INFO_DEVT2INSTANCE even before attach.
1257 */
1258 int
socal_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)1259 socal_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
1260 void **result)
1261 {
1262 int instance;
1263 socal_state_t *socalp;
1264
1265 instance = getminor((dev_t)arg) / 2;
1266
1267 switch (cmd) {
1268 case DDI_INFO_DEVT2DEVINFO:
1269 socalp = ddi_get_soft_state(socal_soft_state_p, instance);
1270 if (socalp)
1271 *result = socalp->dip;
1272 else
1273 *result = NULL;
1274 break;
1275
1276 case DDI_INFO_DEVT2INSTANCE:
1277 *result = (void *)(uintptr_t)instance;
1278 break;
1279
1280 default:
1281 return (DDI_FAILURE);
1282 }
1283
1284 return (DDI_SUCCESS);
1285 }
1286
1287 /*ARGSUSED*/
1288 int
socal_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)1289 socal_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1290 {
1291 int instance = getminor(*devp)/2;
1292 socal_state_t *socalp =
1293 ddi_get_soft_state(socal_soft_state_p, instance);
1294 socal_port_t *port_statep;
1295 int port;
1296
1297 if (socalp == NULL)
1298 return (ENXIO);
1299
1300 port = getminor(*devp)%2;
1301 port_statep = &socalp->port_state[port];
1302
1303 mutex_enter(&port_statep->sp_mtx);
1304 port_statep->sp_status |= PORT_OPEN;
1305 mutex_exit(&port_statep->sp_mtx);
1306 DEBUGF(2, (CE_CONT,
1307 "socal%d: open of port %d\n", instance, port));
1308 return (0);
1309 }
1310
1311 /*ARGSUSED*/
1312 int
socal_close(dev_t dev,int flag,int otyp,cred_t * cred_p)1313 socal_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1314 {
1315 int instance = getminor(dev)/2;
1316 socal_state_t *socalp =
1317 ddi_get_soft_state(socal_soft_state_p, instance);
1318 socal_port_t *port_statep;
1319 int port;
1320
1321 port = getminor(dev)%2;
1322 port_statep = &socalp->port_state[port];
1323
1324 mutex_enter(&port_statep->sp_mtx);
1325 port_statep->sp_status &= ~PORT_OPEN;
1326 mutex_exit(&port_statep->sp_mtx);
1327 DEBUGF(2, (CE_CONT,
1328 "socal%d: clsoe of port %d\n", instance, port));
1329 return (0);
1330 }
1331
1332 /*ARGSUSED*/
1333 int
socal_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)1334 socal_ioctl(dev_t dev,
1335 int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
1336 {
1337 int instance = getminor(dev)/2;
1338 socal_state_t *socalp =
1339 ddi_get_soft_state(socal_soft_state_p, instance);
1340 int port;
1341 socal_port_t *port_statep;
1342 int i;
1343 uint_t r;
1344 int offset;
1345 int retval = FCAL_SUCCESS;
1346 la_els_adisc_t *adisc_pl;
1347 la_els_rls_reply_t *rls_pl;
1348 dev_info_t *dip;
1349 char *buffer, tmp[10];
1350 struct socal_fm_version ver;
1351 #ifdef _MULTI_DATAMODEL
1352 struct socal_fm_version32 {
1353 uint_t fcode_ver_len;
1354 uint_t mcode_ver_len;
1355 uint_t prom_ver_len;
1356 caddr32_t fcode_ver;
1357 caddr32_t mcode_ver;
1358 caddr32_t prom_ver;
1359 } ver32;
1360 uint_t dm32 = 0;
1361 #endif
1362
1363 uchar_t *flb_pl;
1364 flb_hdr_t *flb_hdr;
1365 uint_t flb_size;
1366
1367 if (socalp == NULL)
1368 return (ENXIO);
1369
1370 DEBUGF(4, (CE_CONT, "socal%d ioctl: got command %x\n", instance, cmd));
1371 port = getminor(dev)%2;
1372
1373 switch (cmd) {
1374 case FCIO_FCODE_MCODE_VERSION:
1375 #ifdef _MULTI_DATAMODEL
1376 switch (ddi_model_convert_from(mode & FMODELS)) {
1377 case DDI_MODEL_ILP32:
1378 dm32 = 1;
1379 if (ddi_copyin((caddr_t)arg,
1380 (caddr_t)&ver32, sizeof (ver32),
1381 mode) == -1)
1382 return (EFAULT);
1383 ver.fcode_ver_len =
1384 ver32.fcode_ver_len;
1385 ver.mcode_ver_len =
1386 ver32.mcode_ver_len;
1387 ver.prom_ver_len =
1388 ver32.prom_ver_len;
1389 ver.fcode_ver =
1390 (caddr_t)(uintptr_t)ver32.fcode_ver;
1391 ver.mcode_ver =
1392 (caddr_t)(uintptr_t)ver32.mcode_ver;
1393 ver.prom_ver =
1394 (caddr_t)(uintptr_t)ver32.prom_ver;
1395 break;
1396 case DDI_MODEL_NONE:
1397 if (ddi_copyin((caddr_t)arg,
1398 (caddr_t)&ver, sizeof (ver),
1399 mode) == -1)
1400 return (EFAULT);
1401 }
1402 #else /* _MULTI_DATAMODEL */
1403 if (ddi_copyin((caddr_t)arg, (caddr_t)&ver,
1404 sizeof (ver), mode) == -1)
1405 return (EFAULT);
1406 #endif /* _MULTI_DATAMODEL */
1407 dip = socalp->dip;
1408 if (ddi_prop_op(DDI_DEV_T_ANY, dip,
1409 PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS |
1410 DDI_PROP_CANSLEEP, "version", (caddr_t)&buffer,
1411 &i) != DDI_PROP_SUCCESS)
1412 return (EIO);
1413 if (i < ver.fcode_ver_len)
1414 ver.fcode_ver_len = i;
1415 if (ddi_copyout((caddr_t)buffer,
1416 (caddr_t)ver.fcode_ver, ver.fcode_ver_len,
1417 mode) == -1) {
1418 kmem_free((caddr_t)buffer, i);
1419 return (EFAULT);
1420 }
1421 kmem_free((caddr_t)buffer, i);
1422 if (socalp->socal_eeprom) {
1423 for (i = 0; i < SOCAL_N_CQS; i++) {
1424 mutex_enter(
1425 &socalp->request[i].skc_mtx);
1426 mutex_enter(
1427 &socalp->response[i].skc_mtx);
1428 }
1429 i = socalp->socal_rp->socal_cr.w;
1430 socalp->socal_rp->socal_cr.w &=
1431 ~SOCAL_CR_EEPROM_BANK_MASK;
1432 socalp->socal_rp->socal_cr.w |= 3 << 16;
1433 if (ver.prom_ver_len > 10)
1434 ver.prom_ver_len = 10;
1435 bcopy((caddr_t)socalp->socal_eeprom + (unsigned)
1436 0xfff6, tmp, 10);
1437 socalp->socal_rp->socal_cr.w = i;
1438 for (i = SOCAL_N_CQS-1; i >= 0; i--) {
1439 mutex_exit(&socalp->request[i].skc_mtx);
1440 mutex_exit(
1441 &socalp->response[i].skc_mtx);
1442 }
1443 if (ddi_copyout((caddr_t)tmp,
1444 (caddr_t)ver.prom_ver,
1445 ver.prom_ver_len, mode) == -1)
1446 return (EFAULT);
1447 } else {
1448 ver.prom_ver_len = 0;
1449 }
1450 ver.mcode_ver_len = 0;
1451 #ifdef _MULTI_DATAMODEL
1452 if (dm32) {
1453 ver32.fcode_ver_len = ver.fcode_ver_len;
1454 ver32.mcode_ver_len = ver.mcode_ver_len;
1455 ver32.prom_ver_len = ver.prom_ver_len;
1456 ver32.fcode_ver = (caddr32_t)(uintptr_t)
1457 ver.fcode_ver;
1458 ver32.mcode_ver = (caddr32_t)(uintptr_t)
1459 ver.mcode_ver;
1460 ver32.prom_ver = (caddr32_t)(uintptr_t)
1461 ver.prom_ver;
1462 if (ddi_copyout((caddr_t)&ver32,
1463 (caddr_t)arg, sizeof (ver32),
1464 mode) == -1)
1465 return (EFAULT);
1466 } else
1467 #endif /* _MULTI_DATAMODEL */
1468 if (ddi_copyout((caddr_t)&ver, (caddr_t)arg,
1469 sizeof (struct socal_fm_version), mode) == -1)
1470 return (EFAULT);
1471 break;
1472 case FCIO_LOADUCODE:
1473 mutex_enter(&socalp->k_imr_mtx);
1474 socal_disable(socalp);
1475 mutex_exit(&socalp->k_imr_mtx);
1476 if (copyin((caddr_t)arg, (caddr_t)socal_ucode, 0x10000)
1477 == -1)
1478 return (EFAULT);
1479 /* restart socal after resetting */
1480 (void) socal_force_reset((void *)socalp, 0,
1481 RESET_PORT);
1482 break;
1483 case FCIO_DUMPXRAM:
1484 for (i = 0; i < SOCAL_N_CQS; i++) {
1485 mutex_enter(&socalp->request[i].skc_mtx);
1486 mutex_enter(&socalp->response[i].skc_mtx);
1487 }
1488 for (i = 0; i < 4; i++) {
1489 offset = arg+(0x10000 * i);
1490 socalp->socal_rp->socal_cr.w &=
1491 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
1492 socalp->socal_rp->socal_cr.w |= i<<24;
1493 (void) copyout((caddr_t)socalp->socal_xrp,
1494 (caddr_t)(uintptr_t)offset, 0x10000);
1495 }
1496 socalp->socal_rp->socal_cr.w &=
1497 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
1498 for (i = SOCAL_N_CQS-1; i >= 0; i--) {
1499 mutex_exit(&socalp->request[i].skc_mtx);
1500 mutex_exit(&socalp->response[i].skc_mtx);
1501 }
1502 break;
1503 #ifdef DEBUG
1504 case FCIO_DUMPXRAMBUF:
1505 (void) copyout((caddr_t)socal_xrambuf, (caddr_t)arg,
1506 0x40000);
1507 break;
1508 #endif
1509 case FCIO_GETMAP:
1510 mutex_enter(&socalp->ioctl_mtx);
1511 if (socal_getmap(socalp, port, (caddr_t)arg, 0, 0) ==
1512 -1)
1513 retval = FCAL_ALLOC_FAILED;
1514 mutex_exit(&socalp->ioctl_mtx);
1515 break;
1516 case FCIO_BYPASS_DEV:
1517 mutex_enter(&socalp->ioctl_mtx);
1518 retval = socal_bypass_dev((void *)socalp, port, arg);
1519 mutex_exit(&socalp->ioctl_mtx);
1520 break;
1521 case FCIO_FORCE_LIP:
1522 mutex_enter(&socalp->ioctl_mtx);
1523 retval = socal_force_lip((void *)socalp, port, 0,
1524 FCAL_FORCE_LIP);
1525 mutex_exit(&socalp->ioctl_mtx);
1526 break;
1527 case FCIO_FORCE_OFFLINE:
1528 mutex_enter(&socalp->ioctl_mtx);
1529 retval = socal_force_offline((void *)socalp, port, 0);
1530 mutex_exit(&socalp->ioctl_mtx);
1531 break;
1532 case FCIO_ADISC_ELS:
1533 {
1534 if ((adisc_pl =
1535 (la_els_adisc_t *)kmem_zalloc(
1536 sizeof (la_els_adisc_t),
1537 KM_NOSLEEP)) == NULL)
1538 return (ENOMEM);
1539
1540 if (copyin((caddr_t)arg, (caddr_t)adisc_pl,
1541 sizeof (la_els_adisc_t)) == -1) {
1542 kmem_free((void *)adisc_pl,
1543 sizeof (la_els_adisc_t));
1544 return (EFAULT);
1545 }
1546 mutex_enter(&socalp->ioctl_mtx);
1547 retval = socal_issue_adisc(socalp, port,
1548 adisc_pl->nport_id,
1549 adisc_pl, 0);
1550 mutex_exit(&socalp->ioctl_mtx);
1551
1552 if (retval == FCAL_SUCCESS) {
1553 if (copyout((caddr_t)adisc_pl, (caddr_t)arg,
1554 sizeof (la_els_adisc_t)) == -1) {
1555 kmem_free((void *)adisc_pl,
1556 sizeof (la_els_adisc_t));
1557 return (EFAULT);
1558 }
1559 }
1560
1561 kmem_free((void *)adisc_pl, sizeof (la_els_adisc_t));
1562 break;
1563 }
1564 case FCIO_LINKSTATUS:
1565 {
1566 int dest;
1567 if ((rls_pl =
1568 (la_els_rls_reply_t *)
1569 kmem_zalloc(sizeof (la_els_rls_reply_t),
1570 KM_NOSLEEP)) == NULL)
1571 return (ENOMEM);
1572
1573 if (copyin((caddr_t)arg, (caddr_t)rls_pl,
1574 sizeof (la_els_rls_reply_t)) == -1) {
1575 kmem_free((void *)rls_pl,
1576 sizeof (la_els_rls_reply_t));
1577 return (EFAULT);
1578 }
1579 dest = (rls_pl->mbz[0] << 16) + (rls_pl->mbz[1] << 8) +
1580 rls_pl->mbz[2];
1581 mutex_enter(&socalp->ioctl_mtx);
1582 retval = socal_issue_rls(socalp, port, dest,
1583 rls_pl, 0);
1584 mutex_exit(&socalp->ioctl_mtx);
1585
1586 if (retval == FCAL_SUCCESS) {
1587 if (copyout((caddr_t)rls_pl, (caddr_t)arg,
1588 sizeof (la_els_rls_reply_t)) == -1) {
1589 kmem_free((void *)rls_pl,
1590 sizeof (la_els_rls_reply_t));
1591 return (EFAULT);
1592 }
1593 }
1594 kmem_free((void *)rls_pl, sizeof (la_els_rls_reply_t));
1595 break;
1596 }
1597 case FCIO_LOOPBACK_INTERNAL:
1598 /*
1599 * If userland doesn't provide a location for a return
1600 * value the driver will permanently offline the port,
1601 * ignoring any checks for devices on the loop.
1602 */
1603 mutex_enter(&socalp->ioctl_mtx);
1604 if (arg == 0) {
1605 port_statep = &socalp->port_state[port];
1606 mutex_enter(&port_statep->sp_mtx);
1607 if (port_statep->sp_status & PORT_DISABLED) {
1608 /* Already disabled */
1609 mutex_exit(&port_statep->sp_mtx);
1610 mutex_exit(&socalp->ioctl_mtx);
1611 return (EALREADY);
1612 }
1613 port_statep->sp_status |= PORT_DISABLED;
1614 mutex_exit(&port_statep->sp_mtx);
1615 }
1616 retval = socal_diag_request((void *)socalp, port, &r,
1617 SOC_DIAG_INT_LOOP);
1618 mutex_exit(&socalp->ioctl_mtx);
1619 if (arg == 0) break;
1620 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1621 == -1)
1622 return (EFAULT);
1623 break;
1624 case FCIO_LOOPBACK_MANUAL:
1625 mutex_enter(&socalp->ioctl_mtx);
1626 port_statep = &socalp->port_state[port];
1627 mutex_enter(&port_statep->sp_mtx);
1628 if (port_statep->sp_status & PORT_DISABLED) {
1629 mutex_exit(&port_statep->sp_mtx);
1630 mutex_exit(&socalp->ioctl_mtx);
1631 return (EBUSY);
1632 }
1633 mutex_exit(&port_statep->sp_mtx);
1634 retval = socal_diag_request((void *)socalp, port, &r,
1635 SOC_DIAG_EXT_LOOP);
1636 mutex_exit(&socalp->ioctl_mtx);
1637 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1638 == -1)
1639 return (EFAULT);
1640 break;
1641 case FCIO_NO_LOOPBACK:
1642 mutex_enter(&socalp->ioctl_mtx);
1643 port_statep = &socalp->port_state[port];
1644 mutex_enter(&port_statep->sp_mtx);
1645 /* Do not allow online if we're disabled */
1646 if (port_statep->sp_status & PORT_DISABLED) {
1647 if (arg != 0) {
1648 mutex_exit(&port_statep->sp_mtx);
1649 mutex_exit(&socalp->ioctl_mtx);
1650 /*
1651 * It's permanently disabled -- Need to
1652 * enable it first
1653 */
1654 return (EBUSY);
1655 }
1656 /* This was a request to online. */
1657 port_statep->sp_status &= ~PORT_DISABLED;
1658 }
1659 mutex_exit(&port_statep->sp_mtx);
1660 retval = socal_diag_request((void *)socalp, port, &r,
1661 SOC_DIAG_REM_LOOP);
1662 mutex_exit(&socalp->ioctl_mtx);
1663 if (arg == 0) break;
1664 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1665 == -1)
1666 return (EFAULT);
1667 break;
1668 case FCIO_DIAG_NOP:
1669 mutex_enter(&socalp->ioctl_mtx);
1670 retval = socal_diag_request((void *)socalp, port, &r,
1671 SOC_DIAG_NOP);
1672 mutex_exit(&socalp->ioctl_mtx);
1673 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1674 == -1)
1675 return (EFAULT);
1676 break;
1677 case FCIO_DIAG_XRAM:
1678 mutex_enter(&socalp->ioctl_mtx);
1679 retval = socal_diag_request((void *)socalp, port, &r,
1680 SOC_DIAG_XRAM_TEST);
1681 mutex_exit(&socalp->ioctl_mtx);
1682 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1683 == -1)
1684 return (EFAULT);
1685 break;
1686 case FCIO_DIAG_SOC:
1687 mutex_enter(&socalp->ioctl_mtx);
1688 retval = socal_diag_request((void *)socalp, port, &r,
1689 SOC_DIAG_SOC_TEST);
1690 mutex_exit(&socalp->ioctl_mtx);
1691 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1692 == -1)
1693 return (EFAULT);
1694 break;
1695 case FCIO_DIAG_HCB:
1696 mutex_enter(&socalp->ioctl_mtx);
1697 retval = socal_diag_request((void *)socalp, port, &r,
1698 SOC_DIAG_HCB_TEST);
1699 mutex_exit(&socalp->ioctl_mtx);
1700 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1701 == -1)
1702 return (EFAULT);
1703 break;
1704 case FCIO_DIAG_SOCLB:
1705 mutex_enter(&socalp->ioctl_mtx);
1706 retval = socal_diag_request((void *)socalp, port, &r,
1707 SOC_DIAG_SOCLB_TEST);
1708 mutex_exit(&socalp->ioctl_mtx);
1709 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1710 == -1)
1711 return (EFAULT);
1712 break;
1713 case FCIO_DIAG_SRDSLB:
1714 mutex_enter(&socalp->ioctl_mtx);
1715 retval = socal_diag_request((void *)socalp, port, &r,
1716 SOC_DIAG_SRDSLB_TEST);
1717 mutex_exit(&socalp->ioctl_mtx);
1718 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1719 == -1)
1720 return (EFAULT);
1721 break;
1722 case FCIO_DIAG_EXTLB:
1723 mutex_enter(&socalp->ioctl_mtx);
1724 retval = socal_diag_request((void *)socalp, port, &r,
1725 SOC_DIAG_EXTOE_TEST);
1726 mutex_exit(&socalp->ioctl_mtx);
1727 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1728 == -1)
1729 return (EFAULT);
1730 break;
1731 case FCIO_DIAG_RAW:
1732 if (copyin((caddr_t)arg, (caddr_t)&i, sizeof (uint_t))
1733 == -1)
1734 return (EFAULT);
1735 mutex_enter(&socalp->ioctl_mtx);
1736 retval = socal_diag_request((void *)socalp, port, &r,
1737 (uint_t)i);
1738 mutex_exit(&socalp->ioctl_mtx);
1739 if (copyout((caddr_t)&r, (caddr_t)arg, sizeof (uint_t))
1740 == -1)
1741 return (EFAULT);
1742 break;
1743 case FCIO_LOOPBACK_FRAME:
1744 if ((flb_hdr = (flb_hdr_t *)kmem_zalloc(sizeof (flb_hdr_t),
1745 KM_NOSLEEP)) == NULL)
1746 return (ENOMEM);
1747
1748 if (copyin((caddr_t)arg,
1749 (caddr_t)flb_hdr, sizeof (flb_hdr_t)) == -1) {
1750 kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1751 return (EFAULT);
1752 }
1753
1754 flb_size = flb_hdr->length;
1755
1756 if ((flb_pl =
1757 (uchar_t *)kmem_zalloc(flb_size, KM_NOSLEEP)) == NULL)
1758 return (ENOMEM);
1759
1760 if (copyin((caddr_t)(arg + sizeof (flb_hdr_t)),
1761 (caddr_t)flb_pl, flb_size) == -1) {
1762 kmem_free((void *)flb_pl, flb_size);
1763 return (EFAULT);
1764 }
1765 mutex_enter(&socalp->ioctl_mtx);
1766 retval = socal_issue_lbf(socalp, port, flb_pl,
1767 flb_size, 1);
1768 mutex_exit(&socalp->ioctl_mtx);
1769
1770 if (retval == FCAL_SUCCESS) {
1771 if (copyout((caddr_t)flb_pl,
1772 (caddr_t)(arg + sizeof (flb_hdr_t) +
1773 flb_hdr->max_length), flb_size) == -1) {
1774 kmem_free((void *)flb_pl, flb_size);
1775 kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1776 return (EFAULT);
1777 }
1778 }
1779
1780 kmem_free((void *)flb_pl, flb_size);
1781 kmem_free((void *)flb_hdr, sizeof (flb_hdr_t));
1782 break;
1783 default:
1784 return (ENOTTY);
1785
1786 }
1787 switch (retval) {
1788 case FCAL_SUCCESS:
1789 return (0);
1790 case FCAL_ALLOC_FAILED:
1791 return (ENOMEM);
1792 case FCAL_STATUS_DIAG_BUSY:
1793 return (EALREADY);
1794 case FCAL_STATUS_DIAG_INVALID:
1795 return (EINVAL);
1796 default:
1797 return (EIO);
1798 }
1799
1800 }
1801
1802 /*
1803 * Function name : socal_disable()
1804 *
1805 * Return Values : none
1806 *
1807 * Description : Reset the soc+
1808 *
1809 * Context : Can be called from different kernel process threads.
1810 * Can be called by interrupt thread.
1811 *
1812 * Note: before calling this, the interface should be locked down
1813 * so that it is guaranteed that no other threads are accessing
1814 * the hardware.
1815 */
1816 static void
socal_disable(socal_state_t * socalp)1817 socal_disable(socal_state_t *socalp)
1818 {
1819 #if !defined(lint)
1820 int i;
1821 #endif
1822 /* Don't touch the hardware if the registers aren't mapped */
1823 if (!socalp->socal_rp)
1824 return;
1825
1826 socalp->socal_rp->socal_imr = socalp->socal_k_imr = 0;
1827 socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOFT_RESET;
1828 #if !defined(lint)
1829 i = socalp->socal_rp->socal_csr.w;
1830 #endif
1831 DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
1832 }
1833
1834 /*
1835 * Function name : socal_init_transport_interface()
1836 *
1837 * Return Values : none
1838 *
1839 * Description : Fill up the fcal_tranpsort struct for ULPs
1840 *
1841 *
1842 * Note: Only called during attach, so no protection
1843 */
1844 static void
socal_init_transport_interface(socal_state_t * socalp)1845 socal_init_transport_interface(socal_state_t *socalp)
1846 {
1847 int i;
1848 fcal_transport_t *xport;
1849
1850 for (i = 0; i < N_SOCAL_NPORTS; i++) {
1851 xport = socalp->port_state[i].sp_transport;
1852 mutex_init(&xport->fcal_mtx, NULL, MUTEX_DRIVER,
1853 (void *)(socalp->iblkc));
1854
1855 cv_init(&xport->fcal_cv, NULL, CV_DRIVER, NULL);
1856
1857 xport->fcal_handle = (void *)socalp;
1858 xport->fcal_dmalimp = socallim;
1859 xport->fcal_iblock = socalp->iblkc;
1860 xport->fcal_dmaattr = &socal_dma_attr;
1861 xport->fcal_accattr = &socal_acc_attr;
1862 xport->fcal_loginparms = socalp->socal_service_params;
1863 bcopy((caddr_t)&socalp->socal_n_wwn,
1864 (caddr_t)&xport->fcal_n_wwn, sizeof (la_wwn_t));
1865 bcopy((caddr_t)&socalp->port_state[i].sp_p_wwn,
1866 (caddr_t)&xport->fcal_p_wwn, sizeof (la_wwn_t));
1867 xport->fcal_portno = i;
1868 xport->fcal_cmdmax = SOCAL_MAX_XCHG;
1869 xport->fcal_ops = &socal_transport_ops;
1870 }
1871 }
1872
1873 /*
1874 * static int
1875 * socal_cqalloc_init() - Inialize the circular queue tables.
1876 * Also, init the locks that are associated with the tables.
1877 *
1878 * Returns: FCAL_SUCCESS, if able to init properly.
1879 * FCAL_FAILURE, if unable to init properly.
1880 */
1881
1882 static int
socal_cqalloc_init(socal_state_t * socalp,uint32_t index)1883 socal_cqalloc_init(socal_state_t *socalp, uint32_t index)
1884 {
1885 uint32_t cq_size;
1886 size_t real_len;
1887 uint_t ccount;
1888 socal_kcq_t *cqp;
1889 int req_bound = 0, rsp_bound = 0;
1890
1891 /*
1892 * Initialize the Request and Response Queue locks.
1893 */
1894
1895 mutex_init(&socalp->request[index].skc_mtx, NULL, MUTEX_DRIVER,
1896 (void *)socalp->iblkc);
1897 mutex_init(&socalp->response[index].skc_mtx, NULL, MUTEX_DRIVER,
1898 (void *)socalp->iblkc);
1899 cv_init(&socalp->request[index].skc_cv, NULL, CV_DRIVER, NULL);
1900 cv_init(&socalp->response[index].skc_cv, NULL, CV_DRIVER, NULL);
1901
1902 /* Allocate DVMA resources for the Request Queue. */
1903 cq_size = socal_req_entries[index] * sizeof (cqe_t);
1904 if (cq_size) {
1905 cqp = &socalp->request[index];
1906
1907 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
1908 DDI_DMA_DONTWAIT, NULL,
1909 &cqp->skc_dhandle) != DDI_SUCCESS) {
1910 socal_disp_err(socalp, CE_WARN, "driver.4020",
1911 "!alloc of dma handle failed");
1912 goto fail;
1913 }
1914
1915 if (ddi_dma_mem_alloc(cqp->skc_dhandle,
1916 cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
1917 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
1918 (caddr_t *)&cqp->skc_cq_raw, &real_len,
1919 &cqp->skc_acchandle) != DDI_SUCCESS) {
1920 socal_disp_err(socalp, CE_WARN, "driver.4030",
1921 "!alloc of dma space failed");
1922 goto fail;
1923 }
1924
1925 if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
1926 socal_disp_err(socalp, CE_WARN, "driver.4035",
1927 "!alloc of dma space failed");
1928 goto fail;
1929 }
1930 cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
1931 (uintptr_t)SOCAL_CQ_ALIGN - 1) &
1932 ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
1933
1934 if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
1935 (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
1936 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
1937 NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
1938 socal_disp_err(socalp, CE_WARN, "driver.4040",
1939 "!bind of dma handle failed");
1940 goto fail;
1941 }
1942
1943 req_bound = 1;
1944 if (ccount != 1) {
1945 socal_disp_err(socalp, CE_WARN, "driver.4045",
1946 "!bind of dma handle failed");
1947 goto fail;
1948 }
1949
1950 } else {
1951 socalp->request[index].skc_cq_raw = NULL;
1952 socalp->request[index].skc_cq = (cqe_t *)NULL;
1953 socalp->request[index].skc_dhandle = 0;
1954 }
1955
1956 /* Allocate DVMA resources for the response Queue. */
1957 cq_size = socal_rsp_entries[index] * sizeof (cqe_t);
1958 if (cq_size) {
1959 cqp = &socalp->response[index];
1960
1961 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
1962 DDI_DMA_DONTWAIT, NULL,
1963 &cqp->skc_dhandle) != DDI_SUCCESS) {
1964 socal_disp_err(socalp, CE_WARN, "driver.4050",
1965 "!alloc of dma handle failed");
1966 goto fail;
1967 }
1968
1969 if (ddi_dma_mem_alloc(cqp->skc_dhandle,
1970 cq_size + SOCAL_CQ_ALIGN, &socal_acc_attr,
1971 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
1972 (caddr_t *)&cqp->skc_cq_raw, &real_len,
1973 &cqp->skc_acchandle) != DDI_SUCCESS) {
1974 socal_disp_err(socalp, CE_WARN, "driver.4060",
1975 "!alloc of dma space failed");
1976 goto fail;
1977 }
1978
1979 if (real_len < (cq_size + SOCAL_CQ_ALIGN)) {
1980 socal_disp_err(socalp, CE_WARN, "driver.4065",
1981 "!alloc of dma space failed");
1982 goto fail;
1983 }
1984
1985 cqp->skc_cq = (cqe_t *)(((uintptr_t)cqp->skc_cq_raw +
1986 (uintptr_t)SOCAL_CQ_ALIGN - 1) &
1987 ((uintptr_t)(~(SOCAL_CQ_ALIGN-1))));
1988
1989 if (ddi_dma_addr_bind_handle(cqp->skc_dhandle,
1990 (struct as *)NULL, (caddr_t)cqp->skc_cq, cq_size,
1991 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
1992 NULL, &cqp->skc_dcookie, &ccount) != DDI_DMA_MAPPED) {
1993 socal_disp_err(socalp, CE_WARN, "driver.4070",
1994 "!bind of dma handle failed");
1995 goto fail;
1996 }
1997
1998 rsp_bound = 1;
1999 if (ccount != 1) {
2000 socal_disp_err(socalp, CE_WARN, "driver.4075",
2001 "!bind of dma handle failed");
2002 goto fail;
2003 }
2004
2005 } else {
2006 socalp->response[index].skc_cq_raw = NULL;
2007 socalp->response[index].skc_cq = (cqe_t *)NULL;
2008 socalp->response[index].skc_dhandle = 0;
2009 }
2010
2011 /*
2012 * Initialize the queue pointers
2013 */
2014 socal_cqinit(socalp, index);
2015
2016 return (FCAL_SUCCESS);
2017 fail:
2018 if (socalp->request[index].skc_dhandle) {
2019 if (req_bound)
2020 (void) ddi_dma_unbind_handle(socalp->
2021 request[index].skc_dhandle);
2022 ddi_dma_free_handle(&socalp->request[index].skc_dhandle);
2023 }
2024 if (socalp->request[index].skc_cq_raw)
2025 ddi_dma_mem_free(&socalp->request[index].skc_acchandle);
2026
2027 if (socalp->response[index].skc_dhandle) {
2028 if (rsp_bound)
2029 (void) ddi_dma_unbind_handle(socalp->
2030 response[index].skc_dhandle);
2031 ddi_dma_free_handle(&socalp->response[index].skc_dhandle);
2032 }
2033 if (socalp->response[index].skc_cq_raw)
2034 ddi_dma_mem_free(&socalp->response[index].skc_acchandle);
2035
2036 socalp->request[index].skc_dhandle = NULL;
2037 socalp->response[index].skc_dhandle = NULL;
2038 socalp->request[index].skc_cq_raw = NULL;
2039 socalp->request[index].skc_cq = NULL;
2040 socalp->response[index].skc_cq_raw = NULL;
2041 socalp->response[index].skc_cq = NULL;
2042 mutex_destroy(&socalp->request[index].skc_mtx);
2043 mutex_destroy(&socalp->response[index].skc_mtx);
2044 cv_destroy(&socalp->request[index].skc_cv);
2045 cv_destroy(&socalp->response[index].skc_cv);
2046 return (FCAL_FAILURE);
2047
2048 }
2049
2050 /*
2051 * socal_cqinit() - initializes the driver's circular queue pointers, etc.
2052 */
2053
2054 static void
socal_cqinit(socal_state_t * socalp,uint32_t index)2055 socal_cqinit(socal_state_t *socalp, uint32_t index)
2056 {
2057 socal_kcq_t *kcq_req = &socalp->request[index];
2058 socal_kcq_t *kcq_rsp = &socalp->response[index];
2059
2060 /*
2061 * Initialize the Request and Response Queue pointers
2062 */
2063 kcq_req->skc_seqno = 1;
2064 kcq_rsp->skc_seqno = 1;
2065 kcq_req->skc_in = 0;
2066 kcq_rsp->skc_in = 0;
2067 kcq_req->skc_out = 0;
2068 kcq_rsp->skc_out = 0;
2069 kcq_req->skc_last_index = socal_req_entries[index] - 1;
2070 kcq_rsp->skc_last_index = socal_rsp_entries[index] - 1;
2071 kcq_req->skc_full = 0;
2072 kcq_rsp->deferred_intr_timeoutid = 0;
2073 kcq_req->skc_socalp = socalp;
2074 kcq_rsp->skc_socalp = socalp;
2075
2076 kcq_req->skc_xram_cqdesc =
2077 (socalp->xram_reqp + (index * sizeof (struct cq))/8);
2078 kcq_rsp->skc_xram_cqdesc =
2079 (socalp->xram_rspp + (index * sizeof (struct cq))/8);
2080
2081 /* Clear out memory we have allocated */
2082 if (kcq_req->skc_cq != NULL)
2083 bzero((caddr_t)kcq_req->skc_cq,
2084 socal_req_entries[index] * sizeof (cqe_t));
2085 if (kcq_rsp->skc_cq != NULL)
2086 bzero((caddr_t)kcq_rsp->skc_cq,
2087 socal_rsp_entries[index] * sizeof (cqe_t));
2088 }
2089
2090
2091 static int
socal_start(socal_state_t * socalp)2092 socal_start(socal_state_t *socalp)
2093 {
2094 uint_t r;
2095
2096 if (!socalp)
2097 return (FCAL_FAILURE);
2098
2099 socal_download_ucode(socalp);
2100 socal_init_cq_desc(socalp);
2101 socal_init_wwn(socalp);
2102
2103 mutex_enter(&socalp->port_state[0].sp_mtx);
2104 socalp->port_state[0].sp_status
2105 &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
2106 socalp->port_state[0].sp_status |= PORT_OFFLINE;
2107 mutex_exit(&socalp->port_state[0].sp_mtx);
2108
2109 mutex_enter(&socalp->port_state[1].sp_mtx);
2110 socalp->port_state[1].sp_status
2111 &= (PORT_OPEN|PORT_CHILD_INIT|PORT_DISABLED|PORT_TARGET_MODE);
2112 socalp->port_state[1].sp_status |= PORT_OFFLINE;
2113 mutex_exit(&socalp->port_state[1].sp_mtx);
2114
2115 socal_enable(socalp);
2116 /* Make sure disabled ports stay disabled. */
2117 if (socalp->port_state[0].sp_status & PORT_DISABLED)
2118 (void) socal_diag_request((void *)socalp, 0, &r,
2119 SOC_DIAG_INT_LOOP);
2120 if (socalp->port_state[1].sp_status & PORT_DISABLED)
2121 (void) socal_diag_request((void *)socalp, 1, &r,
2122 SOC_DIAG_INT_LOOP);
2123
2124 mutex_enter(&socalp->k_imr_mtx);
2125 socalp->socal_shutdown = 0;
2126 mutex_exit(&socalp->k_imr_mtx);
2127
2128 mutex_enter(&socalp->board_mtx);
2129 if (socal_establish_pool(socalp, 1) != FCAL_SUCCESS) {
2130 mutex_exit(&socalp->board_mtx);
2131 return (FCAL_FAILURE);
2132 }
2133 if (socal_add_pool_buffer(socalp, 1) != FCAL_SUCCESS) {
2134 mutex_exit(&socalp->board_mtx);
2135 return (FCAL_FAILURE);
2136 }
2137
2138 mutex_exit(&socalp->board_mtx);
2139 return (FCAL_SUCCESS);
2140 }
2141
2142 static void
socal_doreset(socal_state_t * socalp)2143 socal_doreset(socal_state_t *socalp)
2144 {
2145 int i;
2146 socal_port_t *port_statep;
2147 socal_unsol_cb_t *scbp;
2148
2149 for (i = 0; i < SOCAL_N_CQS; i++) {
2150 mutex_enter(&socalp->request[i].skc_mtx);
2151 mutex_enter(&socalp->response[i].skc_mtx);
2152 }
2153
2154 mutex_enter(&socalp->k_imr_mtx);
2155 socal_disable(socalp);
2156
2157 if (socalp->pool_dhandle) {
2158 (void) ddi_dma_unbind_handle(socalp->pool_dhandle);
2159 ddi_dma_free_handle(&socalp->pool_dhandle);
2160 }
2161
2162 if (socalp->pool)
2163 ddi_dma_mem_free(&socalp->pool_acchandle);
2164
2165 socalp->pool_dhandle = NULL;
2166 socalp->pool = NULL;
2167
2168 for (i = 0; i < SOCAL_N_CQS; i++)
2169 socal_cqinit(socalp, i);
2170
2171 for (i = 0; i < N_SOCAL_NPORTS; i++) {
2172 port_statep = &socalp->port_state[i];
2173
2174 mutex_enter(&port_statep->sp_mtx);
2175 port_statep->sp_status &= ~ (PORT_STATUS_MASK |
2176 PORT_LILP_PENDING | PORT_LIP_PENDING |
2177 PORT_ABORT_PENDING | PORT_BYPASS_PENDING |
2178 PORT_ELS_PENDING);
2179 mutex_exit(&port_statep->sp_mtx);
2180 }
2181
2182 mutex_exit(&socalp->k_imr_mtx);
2183
2184 for (i = SOCAL_N_CQS-1; i >= 0; i--) {
2185 mutex_exit(&socalp->request[i].skc_mtx);
2186 mutex_exit(&socalp->response[i].skc_mtx);
2187 }
2188
2189 for (i = 0; i < N_SOCAL_NPORTS; i++) {
2190 for (scbp = socalp->port_state[i].sp_unsol_cb; scbp;
2191 scbp = scbp->next)
2192 (scbp->statec_cb)(scbp->arg, FCAL_STATE_RESET);
2193 }
2194
2195 for (i = 0; i < SOCAL_N_CQS; i++) {
2196 mutex_enter(&socalp->request[i].skc_mtx);
2197 mutex_enter(&socalp->response[i].skc_mtx);
2198 }
2199
2200
2201 for (i = 0; i < SOCAL_N_CQS; i++) {
2202 socalp->request[i].skc_overflowh = NULL;
2203 if (socalp->request[i].skc_full & SOCAL_SKC_SLEEP)
2204 cv_broadcast(&socalp->request[i].skc_cv);
2205 }
2206
2207 for (i = SOCAL_N_CQS-1; i >= 0; i--) {
2208 mutex_exit(&socalp->request[i].skc_mtx);
2209 mutex_exit(&socalp->response[i].skc_mtx);
2210 }
2211
2212 }
2213
2214
2215 /*
2216 * Function name : socal_download_ucode ()
2217 *
2218 * Return Values :
2219 *
2220 * Description : Copies firmware from code that has been linked into
2221 * the socal module into the soc+'s XRAM. Prints the date
2222 * string
2223 *
2224 */
2225 static void
socal_download_ucode(socal_state_t * socalp)2226 socal_download_ucode(socal_state_t *socalp)
2227 {
2228 uint_t fw_len = 0;
2229 uint_t date_str[16];
2230 auto char buf[256];
2231
2232 fw_len = (uint_t)socal_ucode_size;
2233
2234 /* Copy the firmware image */
2235 socal_wcopy((uint_t *)&socal_ucode,
2236 (uint_t *)socalp->socal_xrp, fw_len);
2237
2238 socal_fix_harda(socalp, 0);
2239 socal_fix_harda(socalp, 1);
2240
2241 /* Get the date string from the firmware image */
2242 socal_wcopy((uint_t *)(socalp->socal_xrp+SOCAL_XRAM_FW_DATE_STR),
2243 date_str, sizeof (date_str));
2244 date_str[sizeof (date_str) / sizeof (uint_t) - 1] = 0;
2245
2246 if (*(caddr_t)date_str != '\0') {
2247 (void) sprintf(buf,
2248 "!Downloading host adapter, fw date code: %s\n",
2249 (caddr_t)date_str);
2250 socal_disp_err(socalp, CE_CONT, "driver.1010", buf);
2251 (void) strcpy(socalp->socal_stats.fw_revision,
2252 (char *)date_str);
2253 } else {
2254 (void) sprintf(buf,
2255 "!Downloading host adapter fw, "
2256 "date code: <not available>\n");
2257 socal_disp_err(socalp, CE_CONT, "driver.3010", buf);
2258 (void) strcpy(socalp->socal_stats.fw_revision,
2259 "<Not Available>");
2260 }
2261 }
2262
2263 /*
2264 * Function name : socal_disp_err()
2265 *
2266 * Return Values : none
2267 *
2268 * Description : displays an error message on the system console
2269 * with the full device pathname displayed
2270 */
2271 static void
socal_disp_err(socal_state_t * socalp,uint_t level,char * mid,char * msg)2272 socal_disp_err(
2273 socal_state_t *socalp,
2274 uint_t level,
2275 char *mid,
2276 char *msg)
2277 {
2278 char c;
2279 int instance;
2280
2281 instance = ddi_get_instance(socalp->dip);
2282
2283 c = *msg;
2284
2285 if (c == '!') /* log only */
2286 cmn_err(level,
2287 "!ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
2288 else if (c == '?') /* boot message - log && maybe console */
2289 cmn_err(level,
2290 "?ID[SUNWssa.socal.%s] socal%d: %s", mid, instance, msg+1);
2291 else if (c == '^') /* console only */
2292 cmn_err(level, "^socal%d: %s", instance, msg+1);
2293 else { /* log and console */
2294 cmn_err(level, "^socal%d: %s", instance, msg);
2295 cmn_err(level, "!ID[SUNWssa.socal.%s] socal%d: %s", mid,
2296 instance, msg);
2297 }
2298 }
2299
2300 /*
2301 * Function name : socal_init_cq_desc()
2302 *
2303 * Return Values : none
2304 *
2305 * Description : Initializes the request and response queue
2306 * descriptors in the SOC+'s XRAM
2307 *
2308 * Context : Should only be called during initialiation when
2309 * the SOC+ is reset.
2310 */
2311 static void
socal_init_cq_desc(socal_state_t * socalp)2312 socal_init_cq_desc(socal_state_t *socalp)
2313 {
2314 soc_cq_t que_desc[SOCAL_N_CQS];
2315 uint32_t i;
2316
2317 /*
2318 * Finish CQ table initialization and give the descriptor
2319 * table to the soc+. Note that we don't use all of the queues
2320 * provided by the hardware, but we make sure we initialize the
2321 * quantities in the unused fields in the hardware to zeroes.
2322 */
2323
2324 /*
2325 * Do request queues
2326 */
2327 for (i = 0; i < SOCAL_N_CQS; i++) {
2328 if (socal_req_entries[i]) {
2329 que_desc[i].cq_address =
2330 (uint32_t)socalp->request[i].
2331 skc_dcookie.dmac_address;
2332 que_desc[i].cq_last_index = socal_req_entries[i] - 1;
2333 } else {
2334 que_desc[i].cq_address = (uint32_t)0;
2335 que_desc[i].cq_last_index = 0;
2336 }
2337 que_desc[i].cq_in = 0;
2338 que_desc[i].cq_out = 0;
2339 que_desc[i].cq_seqno = 1; /* required by SOC+ microcode */
2340 }
2341
2342 /* copy to XRAM */
2343 socal_wcopy((uint_t *)que_desc, /* pointer to kernel copy */
2344 (uint_t *)socalp->xram_reqp, /* pointer to xram location */
2345 SOCAL_N_CQS * sizeof (soc_cq_t));
2346
2347 /*
2348 * Do response queues
2349 */
2350 for (i = 0; i < SOCAL_N_CQS; i++) {
2351 if (socal_rsp_entries[i]) {
2352 que_desc[i].cq_last_index = socal_rsp_entries[i] - 1;
2353 que_desc[i].cq_address =
2354 (uint32_t)socalp->response[i].
2355 skc_dcookie.dmac_address;
2356
2357 } else {
2358 que_desc[i].cq_address = 0;
2359 que_desc[i].cq_last_index = 0;
2360 }
2361 }
2362
2363 /* copy to XRAM */
2364 socal_wcopy((uint_t *)que_desc, /* pointer to kernel copy */
2365 (uint_t *)socalp->xram_rspp, /* pointer to xram location */
2366 SOCAL_N_CQS * sizeof (soc_cq_t));
2367 }
2368
2369 static void
socal_init_wwn(socal_state_t * socalp)2370 socal_init_wwn(socal_state_t *socalp)
2371 {
2372 /* copy the node wwn to xram */
2373 socal_wcopy((uint_t *)&socalp->socal_n_wwn,
2374 (uint_t *)(socalp->socal_xrp +
2375 SOCAL_XRAM_NODE_WWN), sizeof (la_wwn_t));
2376
2377 /* copy port a's wwn to xram */
2378 socal_wcopy((uint_t *)&socalp->port_state[0].sp_p_wwn,
2379 (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTA_WWN),
2380 sizeof (la_wwn_t));
2381
2382 /* copy port b's wwn to xram */
2383 socal_wcopy((uint_t *)&socalp->port_state[1].sp_p_wwn,
2384 (uint_t *)(socalp->socal_xrp + SOCAL_XRAM_PORTB_WWN),
2385 sizeof (la_wwn_t));
2386
2387 /*
2388 * need to avoid deadlock by assuring no other thread grabs both of
2389 * these at once
2390 */
2391 mutex_enter(&socalp->port_state[0].sp_transport->fcal_mtx);
2392 mutex_enter(&socalp->port_state[1].sp_transport->fcal_mtx);
2393
2394 socal_wcopy((uint_t *)(socalp->socal_xrp + SOCAL_XRAM_SERV_PARAMS),
2395 (uint_t *)&socalp->socal_service_params, SOCAL_SVC_LENGTH);
2396 mutex_exit(&socalp->port_state[1].sp_transport->fcal_mtx);
2397 mutex_exit(&socalp->port_state[0].sp_transport->fcal_mtx);
2398 }
2399
2400 static void
socal_enable(socal_state_t * socalp)2401 socal_enable(socal_state_t *socalp)
2402 {
2403 DEBUGF(2, (CE_CONT, "socal%d: enable:\n",
2404 ddi_get_instance(socalp->dip)));
2405
2406 socalp->socal_rp->socal_cr.w = socalp->socal_cfg;
2407 socalp->socal_rp->socal_csr.w = SOCAL_CSR_SOCAL_TO_HOST;
2408
2409 socalp->socal_k_imr = (uint32_t)SOCAL_CSR_SOCAL_TO_HOST |
2410 SOCAL_CSR_SLV_ACC_ERR;
2411 socalp->socal_rp->socal_imr = (uint32_t)socalp->socal_k_imr;
2412 }
2413
2414 /*
2415 * static int
2416 * socal_establish_pool() - this routine tells the SOC+ of a buffer pool
2417 * to place LINK ctl application data as it arrives.
2418 *
2419 * Returns:
2420 * FCAL_SUCCESS, upon establishing the pool.
2421 * FCAL_FAILURE, if unable to establish the pool.
2422 */
2423
2424 static int
socal_establish_pool(socal_state_t * socalp,uint32_t poolid)2425 socal_establish_pool(socal_state_t *socalp, uint32_t poolid)
2426 {
2427 soc_pool_request_t *prq;
2428 int result;
2429
2430 if ((prq =
2431 (soc_pool_request_t *)kmem_zalloc(sizeof (soc_pool_request_t),
2432 KM_NOSLEEP)) == NULL)
2433 return (FCAL_FAILURE);
2434 /*
2435 * Fill in the request structure.
2436 */
2437 prq->spr_soc_hdr.sh_request_token = 1;
2438 prq->spr_soc_hdr.sh_flags = SOC_FC_HEADER | SOC_UNSOLICITED |
2439 SOC_NO_RESPONSE;
2440 prq->spr_soc_hdr.sh_class = 0;
2441 prq->spr_soc_hdr.sh_seg_cnt = 1;
2442 prq->spr_soc_hdr.sh_byte_cnt = 0;
2443
2444 prq->spr_pool_id = poolid;
2445 prq->spr_header_mask = SOCPR_MASK_RCTL;
2446 prq->spr_buf_size = SOCAL_POOL_SIZE;
2447 prq->spr_n_entries = 0;
2448
2449 prq->spr_fc_frame_hdr.r_ctl = R_CTL_ELS_REQ;
2450 prq->spr_fc_frame_hdr.d_id = 0;
2451 prq->spr_fc_frame_hdr.s_id = 0;
2452 prq->spr_fc_frame_hdr.type = 0;
2453 prq->spr_fc_frame_hdr.f_ctl = 0;
2454 prq->spr_fc_frame_hdr.seq_id = 0;
2455 prq->spr_fc_frame_hdr.df_ctl = 0;
2456 prq->spr_fc_frame_hdr.seq_cnt = 0;
2457 prq->spr_fc_frame_hdr.ox_id = 0;
2458 prq->spr_fc_frame_hdr.rx_id = 0;
2459 prq->spr_fc_frame_hdr.ro = 0;
2460
2461 prq->spr_cqhdr.cq_hdr_count = 1;
2462 prq->spr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_POOL;
2463 prq->spr_cqhdr.cq_hdr_flags = 0;
2464 prq->spr_cqhdr.cq_hdr_seqno = 0;
2465
2466 /* Enque the request. */
2467 result = socal_cq_enque(socalp, NULL, (cqe_t *)prq, CQ_REQUEST_1,
2468 FCAL_NOSLEEP, NULL, 0);
2469 kmem_free((void *)prq, sizeof (soc_pool_request_t));
2470 return (result);
2471
2472 }
2473
2474
2475 /*
2476 * static int
2477 * soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
2478 * to an established pool of buffers
2479 *
2480 * Returns:
2481 * DDI_SUCCESS, upon establishing the pool.
2482 * DDI_FAILURE, if unable to establish the pool.
2483 */
2484
2485 static int
socal_add_pool_buffer(socal_state_t * socalp,uint32_t poolid)2486 socal_add_pool_buffer(socal_state_t *socalp, uint32_t poolid)
2487 {
2488 soc_data_request_t *drq;
2489 int result;
2490 size_t real_len;
2491 int bound = 0;
2492 uint_t ccount;
2493
2494 if ((drq =
2495 (soc_data_request_t *)kmem_zalloc(sizeof (soc_data_request_t),
2496 KM_NOSLEEP)) == NULL)
2497 return (FCAL_FAILURE);
2498
2499 /* Allocate DVMA resources for the buffer pool */
2500 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
2501 DDI_DMA_DONTWAIT, NULL, &socalp->pool_dhandle) != DDI_SUCCESS)
2502 goto fail;
2503
2504 if (ddi_dma_mem_alloc(socalp->pool_dhandle, SOCAL_POOL_SIZE,
2505 &socal_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
2506 (caddr_t *)&socalp->pool, &real_len, &socalp->pool_acchandle)
2507 != DDI_SUCCESS)
2508 goto fail;
2509
2510 if (real_len < SOCAL_POOL_SIZE)
2511 goto fail;
2512
2513 if (ddi_dma_addr_bind_handle(socalp->pool_dhandle, (struct as *)NULL,
2514 (caddr_t)socalp->pool, SOCAL_POOL_SIZE,
2515 DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
2516 NULL, &socalp->pool_dcookie, &ccount) != DDI_DMA_MAPPED)
2517 goto fail;
2518
2519 bound = 1;
2520 if (ccount != 1)
2521 goto fail;
2522
2523 /*
2524 * Fill in the request structure.
2525 */
2526 drq->sdr_soc_hdr.sh_request_token = poolid;
2527 drq->sdr_soc_hdr.sh_flags = SOC_UNSOLICITED | SOC_NO_RESPONSE;
2528 drq->sdr_soc_hdr.sh_class = 0;
2529 drq->sdr_soc_hdr.sh_seg_cnt = 1;
2530 drq->sdr_soc_hdr.sh_byte_cnt = 0;
2531
2532 drq->sdr_dataseg[0].fc_base =
2533 (uint32_t)socalp->pool_dcookie.dmac_address;
2534 drq->sdr_dataseg[0].fc_count = SOCAL_POOL_SIZE;
2535 drq->sdr_dataseg[1].fc_base = 0;
2536 drq->sdr_dataseg[1].fc_count = 0;
2537 drq->sdr_dataseg[2].fc_base = 0;
2538 drq->sdr_dataseg[2].fc_count = 0;
2539 drq->sdr_dataseg[3].fc_base = 0;
2540 drq->sdr_dataseg[3].fc_count = 0;
2541 drq->sdr_dataseg[4].fc_base = 0;
2542 drq->sdr_dataseg[4].fc_count = 0;
2543 drq->sdr_dataseg[5].fc_base = 0;
2544 drq->sdr_dataseg[5].fc_count = 0;
2545
2546 drq->sdr_cqhdr.cq_hdr_count = 1;
2547 drq->sdr_cqhdr.cq_hdr_type = CQ_TYPE_ADD_BUFFER;
2548 drq->sdr_cqhdr.cq_hdr_flags = 0;
2549 drq->sdr_cqhdr.cq_hdr_seqno = 0;
2550
2551 /* Transport the request. */
2552 result = socal_cq_enque(socalp, NULL, (cqe_t *)drq, CQ_REQUEST_1,
2553 FCAL_NOSLEEP, NULL, 0);
2554 kmem_free((void *)drq, sizeof (soc_data_request_t));
2555 return (result);
2556
2557 fail:
2558 socal_disp_err(socalp, CE_WARN, "driver.4110",
2559 "!Buffer pool DVMA alloc failed");
2560 if (socalp->pool_dhandle) {
2561 if (bound)
2562 (void) ddi_dma_unbind_handle(socalp->pool_dhandle);
2563 ddi_dma_free_handle(&socalp->pool_dhandle);
2564 }
2565 if (socalp->pool)
2566 ddi_dma_mem_free(&socalp->pool_acchandle);
2567 socalp->pool_dhandle = NULL;
2568 return (FCAL_FAILURE);
2569 }
2570
2571 static uint_t
socal_transport(fcal_packet_t * fcalpkt,fcal_sleep_t sleep,int req_q_no)2572 socal_transport(fcal_packet_t *fcalpkt, fcal_sleep_t sleep, int req_q_no)
2573 {
2574 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
2575 socal_port_t *port_statep;
2576 #if defined(DEBUG) && !defined(lint)
2577 int instance = ddi_get_instance(socalp->dip);
2578 #endif
2579 int port;
2580 soc_request_t *sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
2581
2582 if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
2583 port = 1;
2584 else
2585 port = 0;
2586 port_statep = &socalp->port_state[port];
2587
2588 DEBUGF(4, (CE_CONT, "socal%d: transport: packet, sleep = %p, %d\n",
2589 instance, fcalpkt, sleep));
2590
2591 fcalpkt->fcal_cmd_state = 0;
2592 fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
2593
2594 return (socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
2595 req_q_no, sleep, fcalpkt, 0));
2596 }
2597
2598 /*
2599 * Function name : socal_cq_enque()
2600 *
2601 * Return Values :
2602 * FCAL_TRANSPORT_SUCCESS, if able to que the entry.
2603 * FCAL_TRANSPORT_QFULL, if queue full & sleep not set
2604 * FCAL_TRANSPORT_UNAVAIL if this port down
2605 *
2606 * Description : Enqueues an entry into the solicited request
2607 * queue
2608 *
2609 * Context :
2610 */
2611
2612 /*ARGSUSED*/
2613 static int
socal_cq_enque(socal_state_t * socalp,socal_port_t * port_statep,cqe_t * cqe,int rqix,fcal_sleep_t sleep,fcal_packet_t * to_queue,int mtxheld)2614 socal_cq_enque(socal_state_t *socalp, socal_port_t *port_statep, cqe_t *cqe,
2615 int rqix, fcal_sleep_t sleep, fcal_packet_t *to_queue,
2616 int mtxheld)
2617 {
2618 #if defined(DEBUG) && !defined(lint)
2619 int instance = ddi_get_instance(socalp->dip);
2620 #endif
2621 socal_kcq_t *kcq;
2622 cqe_t *sp;
2623 uint_t bitmask, wmask;
2624 uchar_t out;
2625 uchar_t s_out;
2626 longlong_t *p, *q;
2627
2628 kcq = &socalp->request[rqix];
2629
2630 bitmask = SOCAL_CSR_1ST_H_TO_S << rqix;
2631 wmask = SOCAL_CSR_SOCAL_TO_HOST | bitmask;
2632 p = (longlong_t *)cqe;
2633
2634 /*
2635 * Since we're only reading we don't need a mutex.
2636 */
2637 if (socalp->socal_shutdown) {
2638 return (FCAL_TRANSPORT_UNAVAIL);
2639 }
2640 /*
2641 * Get a token early. That way we won't sleep
2642 * in id32_alloc() with a mutex held.
2643 */
2644 if (to_queue) {
2645 if ((to_queue->fcal_socal_request.sr_soc_hdr.sh_request_token =
2646 SOCAL_ID_GET(to_queue, mtxheld ? FCAL_NOSLEEP :
2647 sleep)) == NULL) {
2648 return (FCAL_TRANSPORT_QFULL);
2649 }
2650 }
2651 /*
2652 * Grab lock for request queue.
2653 */
2654
2655 if (!mtxheld)
2656 mutex_enter(&kcq->skc_mtx);
2657
2658 /*
2659 * Determine if the queue is full
2660 */
2661
2662 do {
2663
2664 if (kcq->skc_full) {
2665 /*
2666 * If soc's queue full, then we wait for an interrupt
2667 * telling us we are not full.
2668 */
2669
2670 if (to_queue) {
2671 to_queue->fcal_pkt_next = NULL;
2672 if (!kcq->skc_overflowh) {
2673 DEBUGF(2, (CE_CONT,
2674 "socal%d: cq_enque: request "
2675 "que %d is full\n",
2676 instance, rqix));
2677 kcq->skc_overflowh = to_queue;
2678 socalp->socal_stats.qfulls++;
2679 } else
2680 kcq->skc_overflowt->fcal_pkt_next = to_queue;
2681 kcq->skc_overflowt = to_queue;
2682
2683 mutex_enter(&socalp->k_imr_mtx);
2684 socalp->socal_rp->socal_imr =
2685 (socalp->socal_k_imr |= bitmask);
2686 mutex_exit(&socalp->k_imr_mtx);
2687 to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
2688 if (!mtxheld)
2689 mutex_exit(&kcq->skc_mtx);
2690 return (FCAL_TRANSPORT_SUCCESS);
2691 }
2692
2693 if (!mtxheld)
2694 mutex_exit(&kcq->skc_mtx);
2695 return (FCAL_TRANSPORT_QFULL);
2696 }
2697
2698 if (((kcq->skc_in + 1) & kcq->skc_last_index)
2699 == (out = kcq->skc_out)) {
2700 /*
2701 * get SOC+'s copy of out to update our copy of out
2702 */
2703 s_out =
2704 SOCAL_REQUESTQ_INDEX(rqix, socalp->socal_rp->socal_reqp.w);
2705 DEBUGF(2, (CE_CONT,
2706 "socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
2707 instance, &kcq->skc_xram_cqdesc->cq_in, s_out));
2708
2709 kcq->skc_out = out = s_out;
2710 /* if soc+'s que still full set flag */
2711 kcq->skc_full = ((((kcq->skc_in + 1) &
2712 kcq->skc_last_index) == out)) ? SOCAL_SKC_FULL : 0;
2713 }
2714
2715 } while (kcq->skc_full);
2716
2717 /* Now enque the entry. */
2718 sp = &(kcq->skc_cq[kcq->skc_in]);
2719 cqe->cqe_hdr.cq_hdr_seqno = kcq->skc_seqno;
2720
2721 /* Give the entry to the SOC. */
2722 q = (longlong_t *)sp;
2723 *q++ = *p++;
2724 *q++ = *p++;
2725 *q++ = *p++;
2726 *q++ = *p++;
2727 *q++ = *p++;
2728 *q++ = *p++;
2729 *q++ = *p++;
2730 *q = *p;
2731 (void) ddi_dma_sync(kcq->skc_dhandle, (int)((caddr_t)sp -
2732 (caddr_t)kcq->skc_cq), sizeof (cqe_t), DDI_DMA_SYNC_FORDEV);
2733 if (to_queue)
2734 to_queue->fcal_cmd_state |= FCAL_CMD_IN_TRANSPORT;
2735
2736 /*
2737 * Update circular queue and ring SOC's doorbell.
2738 */
2739 kcq->skc_in++;
2740 if ((kcq->skc_in & kcq->skc_last_index) == 0) {
2741 kcq->skc_in = 0;
2742 kcq->skc_seqno++;
2743 }
2744
2745 socalp->socal_rp->socal_csr.w = wmask | (kcq->skc_in << 24);
2746 /* Let lock go for request queue. */
2747 if (!mtxheld)
2748 mutex_exit(&kcq->skc_mtx);
2749
2750 return (FCAL_TRANSPORT_SUCCESS);
2751 }
2752
2753 static uint_t
socal_transport_poll(fcal_packet_t * fcalpkt,uint_t timeout,int req_q_no)2754 socal_transport_poll(fcal_packet_t *fcalpkt, uint_t timeout, int req_q_no)
2755 {
2756 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
2757 register volatile socal_reg_t *socalreg = socalp->socal_rp;
2758 uint_t csr;
2759 socal_port_t *port_statep;
2760 int port;
2761 soc_request_t *sp = (soc_request_t *)&fcalpkt->fcal_socal_request;
2762 uint32_t retval;
2763 clock_t ticker, t;
2764
2765 /* make the timeout meaningful */
2766 timeout = drv_usectohz(timeout);
2767 if (sp->sr_soc_hdr.sh_flags & SOC_PORT_B)
2768 port = 1;
2769 else
2770 port = 0;
2771 port_statep = &socalp->port_state[port];
2772
2773 fcalpkt->fcal_cmd_state = 0;
2774 fcalpkt->fcal_pkt_flags &= ~(FCFLAG_COMPLETE | FCFLAG_ABORTING);
2775
2776 ticker = ddi_get_lbolt();
2777
2778 if ((retval = socal_cq_enque(socalp, port_statep, (cqe_t *)sp,
2779 req_q_no, FCAL_NOSLEEP, fcalpkt, 0)) != FCAL_TRANSPORT_SUCCESS) {
2780 return (retval);
2781 } else {
2782 while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
2783 drv_usecwait(SOCAL_NOINTR_POLL_DELAY_TIME);
2784 t = ddi_get_lbolt();
2785 if ((ticker + timeout) < t)
2786 return (FCAL_TRANSPORT_TIMEOUT);
2787 csr = socalreg->socal_csr.w;
2788 if ((SOCAL_INTR_CAUSE(socalp, csr)) &
2789 SOCAL_CSR_RSP_QUE_0) {
2790 socal_intr_solicited(socalp, 0);
2791 }
2792 }
2793 }
2794 return (FCAL_TRANSPORT_SUCCESS);
2795 }
2796
2797 static uint_t
socal_doit(fcal_packet_t * fcalpkt,socal_port_t * port_statep,int polled,void (* func)(),int timo,int flag,uint_t * diagcode)2798 socal_doit(fcal_packet_t *fcalpkt, socal_port_t *port_statep, int polled,
2799 void (*func)(), int timo, int flag, uint_t *diagcode)
2800 {
2801 clock_t lb;
2802 uint32_t retval, status;
2803 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
2804
2805 if (polled) {
2806 fcalpkt->fcal_pkt_comp = NULL;
2807 status = socal_transport_poll(fcalpkt, timo, CQ_REQUEST_0);
2808 } else {
2809 fcalpkt->fcal_pkt_comp = func;
2810 mutex_enter(&port_statep->sp_mtx);
2811 port_statep->sp_status |= flag;
2812 if ((status = socal_transport(fcalpkt, FCAL_NOSLEEP,
2813 CQ_REQUEST_0)) == FCAL_TRANSPORT_SUCCESS) {
2814 lb = ddi_get_lbolt();
2815 while (!(fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) {
2816 if ((retval = cv_timedwait(&port_statep->sp_cv,
2817 &port_statep->sp_mtx,
2818 lb+drv_usectohz(timo))) == -1) {
2819 status = FCAL_TRANSPORT_TIMEOUT;
2820 break;
2821 }
2822 }
2823 }
2824 port_statep->sp_status &= ~flag;
2825 mutex_exit(&port_statep->sp_mtx);
2826 }
2827
2828 switch (status) {
2829 case FCAL_TRANSPORT_SUCCESS:
2830 status = fcalpkt->fcal_pkt_status;
2831 if (diagcode)
2832 *diagcode = fcalpkt->fcal_diag_status;
2833 switch (status) {
2834 case FCAL_STATUS_ABORT_FAILED:
2835 if (flag == PORT_ABORT_PENDING)
2836 retval = FCAL_ABORT_FAILED;
2837 break;
2838 case FCAL_STATUS_OK:
2839 if (flag == PORT_ABORT_PENDING)
2840 retval = FCAL_ABORT_FAILED;
2841 else
2842 retval = FCAL_SUCCESS;
2843 break;
2844 case FCAL_STATUS_OLD_PORT:
2845 retval = FCAL_OLD_PORT;
2846 break;
2847 case FCAL_STATUS_ERR_OFFLINE:
2848 retval = FCAL_OFFLINE;
2849 break;
2850 case FCAL_STATUS_ABORTED:
2851 retval = FCAL_ABORTED;
2852 port_statep->sp_board->
2853 socal_stats.pstats[port_statep
2854 ->sp_port].abts_ok++;
2855 break;
2856 case FCAL_STATUS_BAD_XID:
2857 retval = FCAL_BAD_ABORT;
2858 break;
2859 case FCAL_STATUS_BAD_DID:
2860 retval = FCAL_BAD_PARAMS;
2861 break;
2862 case FCAL_STATUS_DIAG_BUSY:
2863 case FCAL_STATUS_DIAG_INVALID:
2864 retval = status;
2865 break;
2866 default:
2867 retval = FCAL_LINK_ERROR;
2868 }
2869 break;
2870 case FCAL_TRANSPORT_TIMEOUT:
2871 if (flag == PORT_LIP_PENDING ||
2872 flag == PORT_LILP_PENDING) {
2873 if (socal_core &&
2874 (socal_core & SOCAL_FAILED_LIP)) {
2875 socal_core = 0;
2876 socal_take_core(socalp);
2877 }
2878 socal_disp_err(socalp, CE_WARN, "link.6040",
2879 "SOCAL:Forcing SOC+ reset as LIP timed out\n");
2880 /* restart socal after resetting */
2881 (void) socal_force_reset(port_statep->sp_board,
2882 polled, RESET_PORT);
2883 }
2884 else
2885 (void) socal_force_lip(port_statep->sp_board,
2886 port_statep->sp_port, polled,
2887 FCAL_FORCE_LIP);
2888 retval = FCAL_TIMEOUT;
2889 break;
2890 case FCAL_TRANSPORT_FAILURE:
2891 case FCAL_BAD_PACKET:
2892 case FCAL_TRANSPORT_UNAVAIL:
2893 case FCAL_TRANSPORT_QFULL:
2894 retval = status;
2895 break;
2896 default:
2897 retval = FCAL_LINK_ERROR;
2898 }
2899 socal_packet_free(fcalpkt);
2900 return (retval);
2901 }
2902
2903 static uint_t
socal_lilp_map(void * ssp,uint_t port,uint32_t bufid,uint_t polled)2904 socal_lilp_map(void *ssp, uint_t port, uint32_t bufid, uint_t polled)
2905 {
2906 fcal_packet_t *fcalpkt;
2907 soc_data_request_t *sdr;
2908 socal_state_t *socalp = (socal_state_t *)ssp;
2909 socal_port_t *port_statep = &socalp->port_state[port];
2910
2911 if ((fcalpkt =
2912 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
2913 == (fcal_packet_t *)NULL)
2914 return (FCAL_ALLOC_FAILED);
2915
2916 sdr = (soc_data_request_t *)&fcalpkt->fcal_socal_request;
2917 if (port)
2918 sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
2919 sdr->sdr_soc_hdr.sh_seg_cnt = 1;
2920 sdr->sdr_soc_hdr.sh_byte_cnt = 132;
2921 sdr->sdr_dataseg[0].fc_base = bufid;
2922 sdr->sdr_dataseg[0].fc_count = 132;
2923 sdr->sdr_cqhdr.cq_hdr_count = 1;
2924 sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_REPORT_MAP;
2925 fcalpkt->fcal_pkt_cookie = (void *)socalp;
2926
2927 return (socal_doit(fcalpkt, port_statep, polled, socal_lilp_map_done,
2928 SOCAL_LILP_TIMEOUT, PORT_LILP_PENDING, NULL));
2929 }
2930
2931 static uint_t
socal_force_lip(void * ssp,uint_t port,uint_t polled,uint_t lip_req)2932 socal_force_lip(void *ssp, uint_t port, uint_t polled, uint_t lip_req)
2933 {
2934 fcal_packet_t *fcalpkt;
2935 soc_cmdonly_request_t *scr;
2936 socal_state_t *socalp = (socal_state_t *)ssp;
2937 socal_port_t *port_statep = &socalp->port_state[port];
2938
2939
2940 if (lip_req == FCAL_NO_LIP) {
2941 mutex_enter(&port_statep->sp_mtx);
2942 if ((port_statep->sp_status & PORT_ONLINE_LOOP) &&
2943 (port_statep->sp_unsol_cb->statec_cb != NULL)) {
2944 mutex_exit(&port_statep->sp_mtx);
2945 (*port_statep->sp_unsol_cb->statec_cb)
2946 (port_statep->sp_unsol_cb->arg,
2947 FCAL_STATUS_LOOP_ONLINE);
2948 return (FCAL_SUCCESS);
2949
2950 } else
2951 mutex_exit(&port_statep->sp_mtx);
2952 }
2953 socalp->socal_stats.pstats[port].lips++;
2954 if ((fcalpkt =
2955 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
2956 == (fcal_packet_t *)NULL)
2957 return (FCAL_ALLOC_FAILED);
2958
2959 scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
2960 if (port)
2961 scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
2962 scr->scr_cqhdr.cq_hdr_count = 1;
2963 scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_LIP;
2964
2965 fcalpkt->fcal_pkt_cookie = (void *)socalp;
2966 return (socal_doit(fcalpkt, port_statep, polled, socal_force_lip_done,
2967 SOCAL_LIP_TIMEOUT, PORT_LIP_PENDING, NULL));
2968 }
2969
2970 static uint_t
socal_abort_cmd(void * ssp,uint_t port,fcal_packet_t * fcalpkt,uint_t polled)2971 socal_abort_cmd(void *ssp, uint_t port, fcal_packet_t *fcalpkt, uint_t polled)
2972 {
2973 fcal_packet_t *fcalpkt2, *fpkt;
2974 soc_cmdonly_request_t *scr, *tscr;
2975 socal_state_t *socalp = (socal_state_t *)ssp;
2976 socal_port_t *port_statep = &socalp->port_state[port];
2977 socal_kcq_t *kcq;
2978
2979 socalp->socal_stats.pstats[port].abts++;
2980 kcq = &socalp->request[CQ_REQUEST_1];
2981 mutex_enter(&kcq->skc_mtx);
2982 fcalpkt2 = kcq->skc_overflowh;
2983 fpkt = NULL;
2984 while (fcalpkt2 != NULL) {
2985 if (fcalpkt2 == fcalpkt) {
2986 if (fpkt == NULL)
2987 kcq->skc_overflowh = fcalpkt->fcal_pkt_next;
2988 else {
2989 fpkt->fcal_pkt_next = fcalpkt->fcal_pkt_next;
2990 if (kcq->skc_overflowt == fcalpkt)
2991 kcq->skc_overflowt = fpkt;
2992 }
2993 mutex_exit(&kcq->skc_mtx);
2994 socalp->socal_stats.pstats[port].abts_ok++;
2995 SOCAL_ID_FREE(fcalpkt->fcal_socal_request.
2996 sr_soc_hdr.sh_request_token);
2997 return (FCAL_ABORTED);
2998 } else {
2999 fpkt = fcalpkt2;
3000 fcalpkt2 = fcalpkt2->fcal_pkt_next;
3001 }
3002 }
3003 mutex_exit(&kcq->skc_mtx);
3004 if ((fcalpkt2 =
3005 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
3006 == (fcal_packet_t *)NULL)
3007 return (FCAL_ALLOC_FAILED);
3008
3009 mutex_enter(&socalp->abort_mtx);
3010 /* Too late? */
3011 if (fcalpkt->fcal_pkt_flags & FCFLAG_COMPLETE) {
3012 socal_packet_free(fcalpkt2);
3013 mutex_exit(&socalp->abort_mtx);
3014 return (FCAL_ABORTED);
3015 /* I lied. So shoot me. */
3016 }
3017 /* Mark packet as being aborted and put it in the abort pending list. */
3018 fcalpkt->fcal_pkt_flags |= FCFLAG_ABORTING;
3019
3020 scr = (soc_cmdonly_request_t *)&fcalpkt2->fcal_socal_request;
3021 tscr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
3022 scr->scr_soc_hdr.sh_byte_cnt = tscr->scr_soc_hdr.sh_request_token;
3023 scr->scr_cqhdr.cq_hdr_count = 1;
3024 scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_REQUEST_ABORT;
3025 if (port)
3026 scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
3027 fcalpkt2->fcal_pkt_cookie = (void *)socalp;
3028 mutex_exit(&socalp->abort_mtx);
3029
3030 return (socal_doit(fcalpkt2, port_statep, polled, socal_abort_done,
3031 SOCAL_ABORT_TIMEOUT, PORT_ABORT_PENDING, NULL));
3032 }
3033
3034 /*ARGSUSED*/
3035 static uint_t
socal_els(void * ssp,uint_t port,uint_t elscode,uint_t dest,void (* callback)(),void * arg,caddr_t reqpl,caddr_t * rsppl,uint_t sleep)3036 socal_els(void *ssp, uint_t port, uint_t elscode, uint_t dest,
3037 void (*callback)(), void *arg, caddr_t reqpl, caddr_t *rsppl,
3038 uint_t sleep)
3039 {
3040 return (FCAL_TRANSPORT_FAILURE);
3041 }
3042
3043 static uint_t
socal_bypass_dev(void * ssp,uint_t port,uint_t dest)3044 socal_bypass_dev(void *ssp, uint_t port, uint_t dest)
3045 {
3046 fcal_packet_t *fcalpkt;
3047 soc_cmdonly_request_t *scr;
3048 socal_state_t *socalp = (socal_state_t *)ssp;
3049 socal_port_t *port_statep = &socalp->port_state[port];
3050
3051 if ((fcalpkt =
3052 socal_packet_alloc(socalp, FCAL_SLEEP))
3053 == (fcal_packet_t *)NULL)
3054 return (FCAL_ALLOC_FAILED);
3055
3056 scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
3057 if (port)
3058 scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
3059 scr->scr_soc_hdr.sh_byte_cnt = dest;
3060 scr->scr_cqhdr.cq_hdr_count = 1;
3061 scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_BYPASS_DEV;
3062 return (socal_doit(fcalpkt, port_statep, 0, socal_bypass_dev_done,
3063 SOCAL_BYPASS_TIMEOUT, PORT_BYPASS_PENDING, NULL));
3064 }
3065
3066
3067 /*ARGSUSED*/
3068 static void
socal_force_reset(void * ssp,uint_t port,uint_t restart)3069 socal_force_reset(void *ssp, uint_t port, uint_t restart)
3070 {
3071 socal_state_t *socalp = (socal_state_t *)ssp;
3072
3073 mutex_enter(&socalp->k_imr_mtx);
3074 if (socalp->socal_shutdown) {
3075 mutex_exit(&socalp->k_imr_mtx);
3076 return;
3077 } else {
3078 socalp->socal_shutdown = 1;
3079 mutex_exit(&socalp->k_imr_mtx);
3080 }
3081 socalp->socal_stats.resets++;
3082 socal_doreset(socalp);
3083 if (restart) {
3084 if (socal_start(socalp) != FCAL_SUCCESS) {
3085 cmn_err(CE_WARN, "socal: start failed.\n");
3086 }
3087 }
3088 }
3089
3090
3091 static void
socal_add_ulp(void * ssp,uint_t port,uchar_t type,void (* ulp_statec_callback)(),void (* ulp_els_callback)(),void (* ulp_data_callback)(),void * arg)3092 socal_add_ulp(void *ssp, uint_t port, uchar_t type,
3093 void (*ulp_statec_callback)(), void (*ulp_els_callback)(),
3094 void (*ulp_data_callback)(), void *arg)
3095 {
3096 socal_state_t *socalp = (socal_state_t *)ssp;
3097 socal_port_t *port_statep = &socalp->port_state[port];
3098 socal_unsol_cb_t *cbentry;
3099
3100 mutex_enter(&port_statep->sp_mtx);
3101 for (cbentry = port_statep->sp_unsol_cb; cbentry;
3102 cbentry = cbentry->next) {
3103 if (cbentry->type == type) {
3104 cbentry->statec_cb = ulp_statec_callback;
3105 cbentry->els_cb = ulp_els_callback;
3106 cbentry->data_cb = ulp_data_callback;
3107 cbentry->arg = arg;
3108 mutex_exit(&port_statep->sp_mtx);
3109 return;
3110 }
3111 }
3112 mutex_exit(&port_statep->sp_mtx);
3113 if ((cbentry =
3114 (socal_unsol_cb_t *)kmem_zalloc(sizeof (socal_unsol_cb_t),
3115 KM_SLEEP)) == (socal_unsol_cb_t *)NULL) {
3116 return;
3117 }
3118 mutex_enter(&port_statep->sp_mtx);
3119 cbentry->statec_cb = ulp_statec_callback;
3120 cbentry->els_cb = ulp_els_callback;
3121 cbentry->data_cb = ulp_data_callback;
3122 cbentry->arg = arg;
3123 cbentry->type = type;
3124
3125 cbentry->next = port_statep->sp_unsol_cb;
3126 port_statep->sp_unsol_cb = cbentry;
3127 mutex_exit(&port_statep->sp_mtx);
3128 }
3129
3130
3131 /*
3132 * remove a ULP with matching type and arg
3133 */
3134 static void
socal_remove_ulp(void * ssp,uint_t port,uchar_t type,void * arg)3135 socal_remove_ulp(void *ssp, uint_t port, uchar_t type, void *arg)
3136 {
3137 socal_state_t *socalp = (socal_state_t *)ssp;
3138 socal_port_t *port_statep;
3139 socal_unsol_cb_t *cbentry;
3140 socal_unsol_cb_t *p_cbentry;
3141
3142
3143 ASSERT(ssp != NULL);
3144 port_statep = &socalp->port_state[port];
3145 ASSERT(port_statep != NULL);
3146
3147 /* scan the list of unsolicited callback entries */
3148 mutex_enter(&port_statep->sp_mtx);
3149 p_cbentry = NULL;
3150 for (cbentry = port_statep->sp_unsol_cb;
3151 cbentry != NULL;
3152 p_cbentry = cbentry, cbentry = cbentry->next) {
3153 if ((cbentry->type != type) || (cbentry->arg != arg)) {
3154 continue; /* this entry doesn't match */
3155 }
3156 /* found entry to remove */
3157 if (port_statep->sp_unsol_cb == cbentry) {
3158 /* remove first entry in list */
3159 port_statep->sp_unsol_cb = cbentry->next;
3160 } else {
3161 /* remove other entry in list */
3162 if (p_cbentry)
3163 p_cbentry->next = cbentry->next;
3164 }
3165 kmem_free((void *)cbentry, sizeof (socal_unsol_cb_t));
3166 DEBUGF(2, (CE_CONT, "socal port %d ULP removed\n", port));
3167 break;
3168 }
3169 mutex_exit(&port_statep->sp_mtx);
3170 }
3171
3172
3173 /*
3174 * static unsigned int
3175 * socal_intr() - this is the interrupt routine for the SOC. Process all
3176 * possible incoming interrupts from the soc device.
3177 */
3178
3179 static unsigned int
socal_intr(caddr_t arg)3180 socal_intr(caddr_t arg)
3181 {
3182 socal_state_t *socalp = (socal_state_t *)arg;
3183 register volatile socal_reg_t *socalreg = socalp->socal_rp;
3184 unsigned csr;
3185 int cause = 0;
3186 #if !defined(lint)
3187 int instance = ddi_get_instance(socalp->dip);
3188 #endif
3189 int i, j, request;
3190 char full;
3191 struct fcal_packet *fpkt, *nfpkt;
3192
3193 csr = socalreg->socal_csr.w;
3194 cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
3195
3196 DEBUGF(2, (CE_CONT,
3197 "socal%d: intr: csr: 0x%x cause: 0x%x\n",
3198 instance, csr, cause));
3199
3200 if (!cause) {
3201 socalp->socal_on_intr = 0;
3202 return (DDI_INTR_UNCLAIMED);
3203 }
3204
3205 socalp->socal_on_intr = 1;
3206
3207 while (cause) {
3208
3209 /*
3210 * Process the unsolicited messages first in case there are some
3211 * high priority async events that we should act on.
3212 *
3213 */
3214
3215 if (cause & SOCAL_CSR_RSP_QUE_1) {
3216 socal_intr_unsolicited(socalp, 1);
3217 DEBUGF(4, (CE_CONT, "socal%d intr: did unsolicited\n", instance));
3218 }
3219
3220 if (cause & SOCAL_CSR_RSP_QUE_0) {
3221 socal_intr_solicited(socalp, 0);
3222 DEBUGF(4, (CE_CONT, "socal%d intr: did solicited\n", instance));
3223 }
3224
3225 /*
3226 * for use with token-only response queues in the future
3227 * if (cause & SOCAL_CSR_RSP_QUE_0) {
3228 * socal_intr_solicited(socalp, 0);
3229 * }
3230 */
3231
3232
3233 /*
3234 * Process any request interrupts
3235 * We only allow request interrupts when the request
3236 * queue is full and we are waiting so we can enque
3237 * another command.
3238 */
3239 if ((request = (cause & SOCAL_CSR_HOST_TO_SOCAL)) != 0) {
3240 socalp->socal_stats.reqq_intrs++;
3241 for (i = SOCAL_CSR_1ST_H_TO_S, j = 0; j < SOCAL_N_CQS;
3242 j++, i <<= 1) {
3243 if (request & i) {
3244 socal_kcq_t *kcq = &socalp->request[j];
3245
3246 if (kcq->skc_full) {
3247 mutex_enter(&kcq->skc_mtx);
3248 full = kcq->skc_full;
3249 kcq->skc_full = 0;
3250 while ((fpkt = kcq->skc_overflowh) != NULL) {
3251 nfpkt = fpkt->fcal_pkt_next;
3252 fpkt->fcal_pkt_next = NULL;
3253 kcq->skc_overflowh = nfpkt;
3254 if (socal_cq_enque(socalp, (socal_port_t *)
3255 fpkt->fcal_pkt_cookie,
3256 (cqe_t *)&fpkt->fcal_socal_request,
3257 j, FCAL_NOSLEEP, NULL, 1) !=
3258 FCAL_TRANSPORT_SUCCESS) {
3259 break;
3260 }
3261 }
3262 if (!kcq->skc_overflowh) {
3263 if (full & SOCAL_SKC_SLEEP)
3264 cv_broadcast(&kcq->skc_cv);
3265
3266 /* Disable this queue's intrs */
3267 DEBUGF(2, (CE_CONT,
3268 "socal%d: req que %d overflow cleared\n",
3269 instance, j));
3270 mutex_enter(&socalp->k_imr_mtx);
3271 socalp->socal_rp->socal_imr =
3272 (socalp->socal_k_imr &= ~i);
3273 mutex_exit(&socalp->k_imr_mtx);
3274 }
3275 mutex_exit(&kcq->skc_mtx);
3276 }
3277 }
3278 }
3279 }
3280 csr = socalreg->socal_csr.w;
3281 cause = (int)SOCAL_INTR_CAUSE(socalp, csr);
3282 DEBUGF(4, (CE_CONT, "socal%d intr: did request queues\n", instance));
3283
3284 }
3285
3286 socalp->socal_on_intr = 0;
3287 return (DDI_INTR_CLAIMED);
3288 }
3289
3290 static void
socal_intr_solicited(socal_state_t * socalp,uint32_t srq)3291 socal_intr_solicited(socal_state_t *socalp, uint32_t srq)
3292 {
3293 socal_kcq_t *kcq;
3294 volatile socal_kcq_t *kcqv;
3295 soc_response_t *srp;
3296 cqe_t *cqe;
3297 uint_t status, i;
3298 fcal_packet_t *fcalpkt = NULL;
3299 soc_header_t *shp;
3300 register volatile socal_reg_t *socalreg = socalp->socal_rp;
3301 caddr_t src, dst;
3302 uchar_t index_in;
3303 cq_hdr_t *cq_hdr;
3304 char val;
3305 int port;
3306
3307 #if defined(DEBUG) && !defined(lint)
3308 int instance = ddi_get_instance(socalp->dip);
3309 #endif
3310 auto char buf[80];
3311
3312 kcq = &socalp->response[srq];
3313 kcqv = (volatile socal_kcq_t *)kcq;
3314 DEBUGF(4, (CE_CONT, "socal%d intr_sol: entered \n", instance));
3315
3316 /*
3317 * Grab lock for request queue.
3318 */
3319 mutex_enter(&kcq->skc_mtx);
3320
3321 /*
3322 * Process as many response queue entries as we can.
3323 */
3324 cqe = &(kcq->skc_cq[kcqv->skc_out]);
3325
3326 index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
3327
3328 if (index_in == kcqv->skc_out) {
3329 socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
3330 (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
3331
3332 /* make sure the write completed */
3333 i = socalreg->socal_csr.w;
3334
3335 index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
3336 }
3337
3338 kcqv->skc_in = index_in;
3339
3340 while (kcqv->skc_out != index_in) {
3341 /* Find out where the newest entry lives in the queue */
3342 (void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
3343 DDI_DMA_SYNC_FORKERNEL);
3344
3345 srp = (soc_response_t *)cqe;
3346 port = srp->sr_soc_hdr.sh_flags & SOC_PORT_B;
3347 shp = &srp->sr_soc_hdr;
3348 cq_hdr = &srp->sr_cqhdr;
3349 /*
3350 * It turns out that on faster CPU's we have a problem where
3351 * the soc interrupts us before the response has been DMA'ed
3352 * in. This should not happen but does !!. So to workaround
3353 * the problem for now, check the sequence # of the response.
3354 * If it does not match with what we have, we must be
3355 * reading stale data
3356 */
3357 if (cq_hdr->cq_hdr_seqno != kcqv->skc_seqno) {
3358 #if defined(DEBUG) && !defined(lint)
3359 socal_read_stale_data++;
3360 #endif
3361 if (kcq->deferred_intr_timeoutid) {
3362 mutex_exit(&kcq->skc_mtx);
3363 return;
3364 } else {
3365 kcq->skc_saved_out = kcqv->skc_out;
3366 kcq->skc_saved_seqno = kcqv->skc_seqno;
3367 kcq->deferred_intr_timeoutid = timeout(
3368 socal_deferred_intr, (caddr_t)kcq,
3369 drv_usectohz(10000));
3370 mutex_exit(&kcq->skc_mtx);
3371 return;
3372 }
3373 }
3374
3375 fcalpkt = (fcal_packet_t *)
3376 SOCAL_ID_LOOKUP(shp->sh_request_token);
3377
3378 if ((socal_core & SOCAL_TAKE_CORE) && ddi_peek8(socalp->dip,
3379 (char *)fcalpkt, &val) != DDI_SUCCESS) {
3380 cmn_err(CE_WARN, "bad token = %p\n", (void *)fcalpkt);
3381 mutex_exit(&kcq->skc_mtx);
3382 socal_take_core(socalp);
3383 }
3384
3385 if ((fcalpkt == (fcal_packet_t *)NULL) ||
3386 (fcalpkt->fcal_magic != FCALP_MAGIC)) {
3387 (void) sprintf(buf, "!invalid FC packet; \n\
3388 in, out, seqno = 0x%x, 0x%x, 0x%x\n",
3389 kcqv->skc_in, kcqv->skc_out, kcqv->skc_seqno);
3390 socal_disp_err(socalp, CE_WARN, "link.4060", buf);
3391 DEBUGF(4, (CE_CONT,
3392 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3393 socalreg->socal_cr.w,
3394 socalreg->socal_sae.w,
3395 socalreg->socal_csr.w,
3396 socalreg->socal_imr));
3397 /*
3398 * Update response queue ptrs and soc registers.
3399 */
3400 kcqv->skc_out++;
3401 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3402 kcqv->skc_out = 0;
3403 kcqv->skc_seqno++;
3404 }
3405
3406 } else {
3407
3408 DEBUGF(2, (CE_CONT, "packet 0x%p complete\n",
3409 fcalpkt));
3410 status = srp->sr_soc_status;
3411 fcalpkt->fcal_pkt_status = status;
3412 DEBUGF(2, (CE_CONT, "SOC status: 0x%x\n", status));
3413 /*
3414 * map soc status codes to
3415 * transport status codes
3416 */
3417
3418 ASSERT((fcalpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)
3419 == 0);
3420 mutex_enter(&socalp->abort_mtx);
3421 fcalpkt->fcal_pkt_flags |= FCFLAG_COMPLETE;
3422 mutex_exit(&socalp->abort_mtx);
3423
3424 /*
3425 * Copy the response frame header (if there is one)
3426 * so that the upper levels can use it. Note that,
3427 * for now, we'll copy the header only if there was
3428 * some sort of non-OK status, to save the PIO reads
3429 * required to get the header from the host adapter's
3430 * xRAM.
3431 */
3432 if (((status != FCAL_STATUS_OK) ||
3433 (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags
3434 & SOC_RESP_HEADER)) &&
3435 (srp->sr_soc_hdr.sh_flags & SOC_FC_HEADER)) {
3436 src = (caddr_t)&srp->sr_fc_frame_hdr;
3437 dst = (caddr_t)&fcalpkt->fcal_resp_hdr;
3438 bcopy(src, dst, sizeof (fc_frame_header_t));
3439 fcalpkt->fcal_pkt_flags |= FCFLAG_RESP_HEADER;
3440 i = srp->sr_soc_hdr.sh_flags & SOC_PORT_B ?
3441 1 : 0;
3442 if ((status != FCAL_STATUS_OK) &&
3443 (status <= FCAL_STATUS_MAX_STATUS)) {
3444 socalp->socal_stats.pstats[i].
3445 resp_status[status]++;
3446 } else {
3447 socalp->socal_stats.pstats[i].
3448 resp_status[FCAL_STATUS_ERROR]++;
3449 }
3450 } else if (status == FCAL_STATUS_OK) {
3451 fcalpkt->fcal_socal_request.
3452 sr_soc_hdr.sh_byte_cnt =
3453 shp->sh_byte_cnt;
3454 }
3455 fcalpkt->fcal_diag_status =
3456 (uint32_t)srp->sr_dataseg.fc_base;
3457 fcalpkt->fcal_ncmds = srp->sr_ncmds;
3458
3459 /*
3460 * Update response queue ptrs and soc registers.
3461 */
3462 kcqv->skc_out++;
3463 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3464 kcqv->skc_out = 0;
3465 kcqv->skc_seqno++;
3466 }
3467
3468 /* For incmplt DMA offline loop by loopback */
3469 if (fcalpkt->fcal_pkt_status ==
3470 FCAL_STATUS_INCOMPLETE_DMA_ERR) {
3471 socal_port_t *port_statep;
3472 uint_t r;
3473
3474 /*
3475 * Give up the mutex to avoid a deadlock
3476 * with the loopback routine.
3477 */
3478 mutex_exit(&kcq->skc_mtx);
3479
3480 port_statep = &socalp->port_state[port];
3481 mutex_enter(&port_statep->sp_mtx);
3482 if (port_statep->sp_status &
3483 PORT_DISABLED) {
3484 /* Already disabled */
3485 mutex_exit(&port_statep->sp_mtx);
3486 } else {
3487 port_statep->sp_status |=
3488 PORT_DISABLED;
3489 mutex_exit(&port_statep->sp_mtx);
3490 (void) socal_diag_request(
3491 (void *)socalp, port,
3492 &r, SOC_DIAG_INT_LOOP);
3493 }
3494 /* reacquire mutex */
3495 mutex_enter(&kcq->skc_mtx);
3496 }
3497
3498 /*
3499 * Complete the packet *ONLY* if it not being aborted
3500 * or the abort has already completed. Otherwise it is
3501 * not safe to free the ID.
3502 */
3503 mutex_enter(&socalp->abort_mtx);
3504 if (!(fcalpkt->fcal_pkt_flags & FCFLAG_ABORTING)) {
3505 /*
3506 * Call the completion routine
3507 */
3508 SOCAL_ID_FREE(shp->sh_request_token);
3509 if (fcalpkt->fcal_pkt_comp != NULL) {
3510 fcalpkt->fcal_cmd_state |=
3511 FCAL_CMD_COMPLETE;
3512
3513 /*
3514 * Give up the mutex to avoid a
3515 * deadlock with the callback routine.
3516 */
3517 mutex_exit(&socalp->abort_mtx);
3518 mutex_exit(&kcq->skc_mtx);
3519
3520 /* callback */
3521 (*fcalpkt->fcal_pkt_comp)(fcalpkt);
3522
3523 /* reacquire mutex */
3524 mutex_enter(&kcq->skc_mtx);
3525 } else {
3526 fcalpkt->fcal_cmd_state |=
3527 FCAL_CMD_COMPLETE;
3528 mutex_exit(&socalp->abort_mtx);
3529 }
3530 } else {
3531 mutex_exit(&socalp->abort_mtx);
3532 }
3533 }
3534
3535
3536 if (kcq->skc_cq == NULL)
3537 /*
3538 * This action averts a potential PANIC scenario
3539 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3540 * when we let it go, to call our completion routine,
3541 * and "initialized" the response queue. We exit our
3542 * processing loop here, thereby averting a PANIC due
3543 * to a NULL de-reference from the response queue.
3544 *
3545 * Note that this is an interim measure that needs
3546 * to be revisited when this driver is next revised
3547 * for enhanced performance.
3548 */
3549 break;
3550
3551 /*
3552 * We need to re-read the input and output pointers in
3553 * case a polling routine should process some entries
3554 * from the response queue while we're doing a callback
3555 * routine with the response queue mutex dropped.
3556 */
3557 cqe = &(kcq->skc_cq[kcqv->skc_out]);
3558 index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
3559
3560 /*
3561 * Mess around with the hardware if we think we've run out
3562 * of entries in the queue, just to make sure we've read
3563 * all entries that are available.
3564 */
3565
3566 socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
3567 (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_0));
3568
3569 /* Make sure the csr write has completed */
3570 i = socalreg->socal_csr.w;
3571 DEBUGF(9, (CE_CONT, "csr.w = %x\n", i));
3572
3573 /*
3574 * Update our idea of where the host adapter has placed
3575 * the most recent entry in the response queue and resync
3576 * the response queue
3577 */
3578 index_in = SOCAL_RESPONSEQ_INDEX(srq, socalreg->socal_rspp.w);
3579
3580 kcqv->skc_in = index_in;
3581 }
3582
3583 /* Drop lock for request queue. */
3584 mutex_exit(&kcq->skc_mtx);
3585 }
3586
3587 /*
3588 * Function name : socal_intr_unsolicited()
3589 *
3590 * Return Values : none
3591 *
3592 * Description : Processes entries in the unsolicited response
3593 * queue
3594 *
3595 * The SOC+ will give us an unsolicited response
3596 * whenever its status changes: OFFLINE, ONLINE,
3597 * or in response to a packet arriving from an originator.
3598 *
3599 * When message requests come in they will be placed in our
3600 * buffer queue or in the next "inline" packet by the SOC hardware.
3601 *
3602 * Context : Unsolicited interrupts must be masked
3603 */
3604
3605 static void
socal_intr_unsolicited(socal_state_t * socalp,uint32_t urq)3606 socal_intr_unsolicited(socal_state_t *socalp, uint32_t urq)
3607 {
3608 socal_kcq_t *kcq;
3609 volatile socal_kcq_t *kcqv;
3610 soc_response_t *srp;
3611 volatile cqe_t *cqe;
3612 int port;
3613 register uchar_t t_index, t_seqno;
3614 register volatile socal_reg_t *socalreg = socalp->socal_rp;
3615 volatile cqe_t *cqe_cont = NULL;
3616 uint_t i;
3617 int hdr_count;
3618 int status;
3619 ushort_t flags;
3620 auto char buf[256];
3621 socal_port_t *port_statep;
3622 #if defined(DEBUG) && !defined(lint)
3623 int instance = ddi_get_instance(socalp->dip);
3624 #endif
3625 uchar_t index_in;
3626 socal_unsol_cb_t *cblist;
3627
3628 kcq = &socalp->response[urq];
3629 kcqv = (volatile socal_kcq_t *)kcq;
3630
3631 /*
3632 * Grab lock for response queue.
3633 */
3634 mutex_enter(&kcq->skc_mtx);
3635
3636 cqe = (volatile cqe_t *)&(kcq->skc_cq[kcqv->skc_out]);
3637
3638 index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
3639
3640 kcqv->skc_in = index_in;
3641
3642 while (kcqv->skc_out != index_in) {
3643 (void) ddi_dma_sync(kcq->skc_dhandle, 0, 0,
3644 DDI_DMA_SYNC_FORKERNEL);
3645
3646 /* Check for continuation entries */
3647 if ((hdr_count = cqe->cqe_hdr.cq_hdr_count) != 1) {
3648
3649 t_seqno = kcqv->skc_seqno;
3650 t_index = kcqv->skc_out + hdr_count;
3651
3652 i = index_in;
3653 if (kcqv->skc_out > index_in)
3654 i += kcq->skc_last_index + 1;
3655
3656 /*
3657 * If we think the continuation entries haven't yet
3658 * arrived, try once more before giving up
3659 */
3660 if (i < t_index) {
3661
3662 socalreg->socal_csr.w =
3663 ((kcqv->skc_out << 24) |
3664 (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
3665
3666 /* Make sure the csr write has completed */
3667 i = socalreg->socal_csr.w;
3668
3669 /*
3670 * Update our idea of where the host adapter has placed
3671 * the most recent entry in the response queue
3672 */
3673 i = index_in = SOCAL_RESPONSEQ_INDEX(urq,
3674 socalreg->socal_rspp.w);
3675 if (kcqv->skc_out > index_in)
3676 i += kcq->skc_last_index + 1;
3677
3678 /*
3679 * Exit if the continuation entries haven't yet
3680 * arrived
3681 */
3682 if (i < t_index)
3683 break;
3684 }
3685
3686 if (t_index > kcq->skc_last_index) {
3687 t_seqno++;
3688 t_index &= kcq->skc_last_index;
3689 }
3690
3691 cqe_cont = (volatile cqe_t *)
3692 &(kcq->skc_cq[t_index ? t_index - 1 :
3693 kcq->skc_last_index]);
3694
3695
3696 /* A cq_hdr_count > 2 is illegal; throw away the response */
3697
3698 /*
3699 * XXX - should probably throw out as many entries as the
3700 * hdr_cout tells us there are
3701 */
3702 if (hdr_count != 2) {
3703 socal_disp_err(socalp, CE_WARN, "driver.4030",
3704 "!too many continuation entries");
3705 DEBUGF(4, (CE_CONT,
3706 "socal%d: soc+ unsolicited entry count = %d\n",
3707 instance, cqe->cqe_hdr.cq_hdr_count));
3708
3709 if ((++t_index & kcq->skc_last_index) == 0) {
3710 t_index = 0;
3711 t_seqno++;
3712 }
3713 kcqv->skc_out = t_index;
3714 kcqv->skc_seqno = t_seqno;
3715
3716 cqe = &(kcq->skc_cq[kcqv->skc_out]);
3717 cqe_cont = NULL;
3718 continue;
3719 }
3720 }
3721
3722 /*
3723 * Update unsolicited response queue ptrs
3724 */
3725 kcqv->skc_out++;
3726 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3727 kcqv->skc_out = 0;
3728 kcqv->skc_seqno++;
3729 }
3730
3731 if (cqe_cont != NULL) {
3732 kcqv->skc_out++;
3733 if ((kcqv->skc_out & kcq->skc_last_index) == 0) {
3734 kcqv->skc_out = 0;
3735 kcqv->skc_seqno++;
3736 }
3737 }
3738
3739 if (index_in == kcqv->skc_out) {
3740 socalreg->socal_csr.w = ((kcqv->skc_out << 24) |
3741 (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
3742
3743 /* Make sure the csr write has completed */
3744 i = socalreg->socal_csr.w;
3745 }
3746
3747 srp = (soc_response_t *)cqe;
3748 flags = srp->sr_soc_hdr.sh_flags;
3749 port = flags & SOC_PORT_B;
3750 port_statep = &socalp->port_state[port];
3751
3752 /*
3753 * XXX need to deal buffer pool entries here
3754 */
3755 switch (flags & ~SOC_PORT_B) {
3756 case SOC_UNSOLICITED | SOC_FC_HEADER:
3757
3758 srp = (soc_response_t *)cqe;
3759
3760 switch (srp->sr_fc_frame_hdr.r_ctl & R_CTL_ROUTING) {
3761 case R_CTL_EXTENDED_SVC:
3762 /*
3763 * Extended Link Services frame received
3764 */
3765 socalp->socal_stats.pstats[port].els_rcvd++;
3766 socal_us_els(socalp, (cqe_t *)cqe, (caddr_t)cqe_cont);
3767
3768 /* do callbacks to any interested ULPs */
3769 mutex_enter(&port_statep->sp_mtx);
3770 for (cblist = port_statep->sp_unsol_cb; cblist;
3771 cblist = cblist->next) {
3772 if (cblist->els_cb) {
3773 mutex_exit(&port_statep->sp_mtx);
3774 mutex_exit(&kcq->skc_mtx);
3775 cblist->els_cb(cblist->arg,
3776 (cqe_t *)cqe,
3777 (caddr_t)cqe_cont);
3778 mutex_enter(&kcq->skc_mtx);
3779 mutex_enter(&port_statep->sp_mtx);
3780 }
3781 }
3782 mutex_exit(&port_statep->sp_mtx);
3783 break;
3784 case R_CTL_BASIC_SVC:
3785 (void) sprintf(buf,
3786 "!unsupported Link Service command: 0x%x",
3787 srp->sr_fc_frame_hdr.type);
3788 socal_disp_err(socalp, CE_WARN, "link.4020", buf);
3789 break;
3790 case R_CTL_DEVICE_DATA:
3791 switch (srp->sr_fc_frame_hdr.type) {
3792 default:
3793 mutex_enter(&port_statep->sp_mtx);
3794 status = 1;
3795 for (cblist = port_statep->sp_unsol_cb; cblist;
3796 cblist = cblist->next) {
3797 if (cblist->data_cb &&
3798 (cblist->type ==
3799 srp->sr_fc_frame_hdr.type)) {
3800 mutex_exit(&port_statep->sp_mtx);
3801 mutex_exit(&kcq->skc_mtx);
3802 cblist->data_cb(cblist->arg,
3803 (cqe_t *)cqe, (caddr_t)cqe_cont);
3804 mutex_enter(&kcq->skc_mtx);
3805 mutex_enter(&port_statep->sp_mtx);
3806 status = 0;
3807 }
3808 }
3809 mutex_exit(&port_statep->sp_mtx);
3810
3811 if (status == 0)
3812 break;
3813
3814 (void) sprintf(buf,
3815 "!unknown FC-4 command: 0x%x",
3816 srp->sr_fc_frame_hdr.type);
3817 socal_disp_err(socalp, CE_WARN,
3818 "link.4030", buf);
3819 break;
3820 }
3821 break;
3822 default:
3823 (void) sprintf(buf, "!unsupported FC frame R_CTL: 0x%x",
3824 srp->sr_fc_frame_hdr.r_ctl);
3825 socal_disp_err(socalp, CE_WARN, "link.4040", buf);
3826 break;
3827 }
3828 break;
3829
3830 case SOC_STATUS: {
3831
3832 /*
3833 * Note that only the lsbyte of the status has
3834 * interesting information...
3835 */
3836 status = srp->sr_soc_status;
3837
3838 switch (status) {
3839
3840 case FCAL_STATUS_ONLINE:
3841 (void) sprintf(buf,
3842 "!port %d: Fibre Channel is ONLINE\n", port);
3843 socal_disp_err(socalp, CE_CONT, "link.6010",
3844 buf);
3845 mutex_enter(&port_statep->sp_mtx);
3846 port_statep->sp_status &= ~PORT_STATUS_MASK;
3847 port_statep->sp_status |= PORT_ONLINE;
3848 mutex_exit(&port_statep->sp_mtx);
3849 socalp->socal_stats.pstats[port].onlines++;
3850 DEBUGF(4, (CE_CONT,
3851 "socal%d intr_unsol: ONLINE intr\n",
3852 instance));
3853 break;
3854
3855 case FCAL_STATUS_LOOP_ONLINE:
3856 (void) sprintf(buf,
3857 "!port %d: Fibre Channel Loop is ONLINE\n",
3858 port);
3859 socal_disp_err(socalp, CE_CONT, "link.6010",
3860 buf);
3861 mutex_enter(&port_statep->sp_mtx);
3862 port_statep->sp_status &= ~PORT_STATUS_MASK;
3863 port_statep->sp_status |= PORT_ONLINE_LOOP;
3864 mutex_exit(&port_statep->sp_mtx);
3865 socalp->socal_stats.pstats[port].online_loops++;
3866 DEBUGF(4, (CE_CONT,
3867 "socal%d intr_unsol: ONLINE-LOOP intr\n",
3868 instance));
3869 break;
3870
3871 case FCAL_STATUS_ERR_OFFLINE:
3872 /*
3873 * SOC and Responder will both flush
3874 * all active commands.
3875 * So I don't have to do anything
3876 * until it comes back online.
3877 */
3878 (void) sprintf(buf,
3879 "!port %d: Fibre Channel is OFFLINE\n", port);
3880 socal_disp_err(socalp, CE_CONT, "link.5010",
3881 buf);
3882
3883 mutex_enter(&port_statep->sp_mtx);
3884 port_statep->sp_status &= ~PORT_STATUS_MASK;
3885 port_statep->sp_status |= PORT_OFFLINE;
3886 port_statep->sp_lilpmap_valid = 0;
3887 mutex_exit(&port_statep->sp_mtx);
3888 socalp->socal_stats.pstats[port].offlines++;
3889 DEBUGF(4, (CE_CONT,
3890 "socal%d intr_unsol: OFFLINE intr\n",
3891 instance));
3892
3893 break;
3894 default:
3895 (void) sprintf(buf, "!unknown status: 0x%x\n",
3896 status);
3897 socal_disp_err(socalp, CE_WARN, "link.3020",
3898 buf);
3899 }
3900 mutex_exit(&kcq->skc_mtx);
3901 mutex_enter(&port_statep->sp_mtx);
3902 for (cblist = port_statep->sp_unsol_cb; cblist;
3903 cblist = cblist->next) {
3904 if (cblist->statec_cb) {
3905 mutex_exit(&port_statep->sp_mtx);
3906 (*cblist->statec_cb)(cblist->arg,
3907 status);
3908 mutex_enter(&port_statep->sp_mtx);
3909 }
3910 }
3911 mutex_exit(&port_statep->sp_mtx);
3912 if (status == FCAL_STATUS_ERR_OFFLINE) {
3913 socal_flush_overflowq(socalp, port,
3914 CQ_REQUEST_0);
3915 socal_flush_overflowq(socalp, port,
3916 CQ_REQUEST_1);
3917 }
3918 mutex_enter(&kcq->skc_mtx);
3919 break;
3920 }
3921 default:
3922 (void) sprintf(buf, "!unexpected state: flags: 0x%x\n",
3923 flags);
3924 socal_disp_err(socalp, CE_WARN, "link.4050", buf);
3925 DEBUGF(4, (CE_CONT,
3926 "\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
3927 socalp->socal_rp->socal_cr.w,
3928 socalp->socal_rp->socal_sae.w,
3929 socalp->socal_rp->socal_csr.w,
3930 socalp->socal_rp->socal_imr));
3931 }
3932
3933
3934 if (kcq->skc_cq == NULL)
3935 /*
3936 * This action averts a potential PANIC scenario
3937 * where the SUSPEND code flow grabbed the kcq->skc_mtx
3938 * when we let it go, to call our completion routine,
3939 * and "initialized" the response queue. We exit our
3940 * processing loop here, thereby averting a PANIC due
3941 * to a NULL de-reference from the response queue.
3942 *
3943 * Note that this is an interim measure that needs
3944 * to be revisited when this driver is next revised
3945 * for enhanced performance.
3946 */
3947 break;
3948
3949 /*
3950 * We need to re-read the input and output pointers in
3951 * case a polling routine should process some entries
3952 * from the response queue while we're doing a callback
3953 * routine with the response queue mutex dropped.
3954 */
3955 cqe = &(kcq->skc_cq[kcqv->skc_out]);
3956 index_in = SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
3957 cqe_cont = NULL;
3958
3959 /*
3960 * Mess around with the hardware if we think we've run out
3961 * of entries in the queue, just to make sure we've read
3962 * all entries that are available.
3963 */
3964 if (index_in == kcqv->skc_out) {
3965
3966 socalreg->socal_csr.w =
3967 ((kcqv->skc_out << 24) |
3968 (SOCAL_CSR_SOCAL_TO_HOST & ~SOCAL_CSR_RSP_QUE_1));
3969
3970 /* Make sure the csr write has completed */
3971 i = socalreg->socal_csr.w;
3972
3973 /*
3974 * Update our idea of where the host adapter has placed
3975 * the most recent entry in the response queue
3976 */
3977 index_in =
3978 SOCAL_RESPONSEQ_INDEX(urq, socalreg->socal_rspp.w);
3979 }
3980
3981 socalp->socal_stats.pstats[port].unsol_resps++;
3982
3983 kcqv->skc_in = index_in;
3984
3985 }
3986
3987 /* Release lock for response queue. */
3988 mutex_exit(&kcq->skc_mtx);
3989 }
3990
3991 /*
3992 * socal_us_els() - This function handles unsolicited extended link
3993 * service responses received from the soc.
3994 */
3995 static void
socal_us_els(socal_state_t * socalp,cqe_t * cqe,caddr_t payload)3996 socal_us_els(socal_state_t *socalp, cqe_t *cqe, caddr_t payload)
3997 {
3998 soc_response_t *srp = (soc_response_t *)cqe;
3999 els_payload_t *els = (els_payload_t *)payload;
4000 int i;
4001 char *bp;
4002 auto char buf[256];
4003
4004 /*
4005 * There should be a CQE continuation entry for all
4006 * extended link services
4007 */
4008 if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
4009 socal_disp_err(socalp, CE_WARN, "link.4010",
4010 "!incomplete continuation entry");
4011 return;
4012 }
4013
4014 /* Quietly impose a maximum byte count */
4015 if (i > SOC_CQE_PAYLOAD)
4016 i = SOC_CQE_PAYLOAD;
4017 i -= sizeof (union els_cmd_u);
4018
4019 /*
4020 * Decode the LS_Command code
4021 */
4022 switch (els->els_cmd.c.ls_command) {
4023 case LA_ELS_DISPLAY:
4024 els->els_data[i] = '\0'; /* terminate the string */
4025 for (bp = (char *)&(els->els_data[0]); *bp; bp++) {
4026 /* squash newlines */
4027 if (*bp == '\n') *bp = ' ';
4028 }
4029 (void) sprintf(buf, "!message: %s\n", els->els_data);
4030 socal_disp_err(socalp, CE_CONT, "link.1010", buf);
4031 break;
4032
4033 default:
4034 DEBUGF(3, (CE_CONT, "!unknown LS_Command, %x\n",
4035 els->els_cmd.i));
4036 break;
4037 }
4038
4039 }
4040
4041 /*ARGSUSED*/
4042 static fcal_packet_t *
socal_packet_alloc(socal_state_t * socalp,fcal_sleep_t sleep)4043 socal_packet_alloc(socal_state_t *socalp, fcal_sleep_t sleep)
4044 {
4045 int flag;
4046 fcal_packet_t *pkt;
4047
4048 if (sleep == FCAL_SLEEP)
4049 flag = KM_SLEEP;
4050 else
4051 flag = KM_NOSLEEP;
4052
4053 pkt = (fcal_packet_t *)kmem_zalloc(sizeof (fcal_packet_t), flag);
4054
4055 if (pkt != (fcal_packet_t *)NULL)
4056 pkt->fcal_magic = FCALP_MAGIC;
4057
4058 return (pkt);
4059 }
4060
4061 static void
socal_packet_free(fcal_packet_t * fcalpkt)4062 socal_packet_free(fcal_packet_t *fcalpkt)
4063 {
4064 kmem_free((void *)fcalpkt, sizeof (fcal_packet_t));
4065 }
4066
4067 static void
socal_lilp_map_done(fcal_packet_t * fcalpkt)4068 socal_lilp_map_done(fcal_packet_t *fcalpkt)
4069 {
4070 uint32_t port;
4071 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4072
4073 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4074 port = 1;
4075 else
4076 port = 0;
4077 mutex_enter(&socalp->port_state[port].sp_mtx);
4078 socalp->port_state[port].sp_status &= ~PORT_LILP_PENDING;
4079 cv_broadcast(&socalp->port_state[port].sp_cv);
4080 mutex_exit(&socalp->port_state[port].sp_mtx);
4081 }
4082
4083 static void
socal_force_lip_done(fcal_packet_t * fcalpkt)4084 socal_force_lip_done(fcal_packet_t *fcalpkt)
4085 {
4086 uint32_t port;
4087 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4088
4089 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4090 port = 1;
4091 else
4092 port = 0;
4093 mutex_enter(&socalp->port_state[port].sp_mtx);
4094 socalp->port_state[port].sp_status &= ~PORT_LIP_PENDING;
4095 cv_broadcast(&socalp->port_state[port].sp_cv);
4096 mutex_exit(&socalp->port_state[port].sp_mtx);
4097 }
4098
4099 static void
socal_adisc_done(fcal_packet_t * fcalpkt)4100 socal_adisc_done(fcal_packet_t *fcalpkt)
4101 {
4102 uint32_t port;
4103 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4104
4105 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4106 port = 1;
4107 else
4108 port = 0;
4109 mutex_enter(&socalp->port_state[port].sp_mtx);
4110 socalp->port_state[port].sp_status &= ~PORT_ADISC_PENDING;
4111 cv_broadcast(&socalp->port_state[port].sp_cv);
4112 mutex_exit(&socalp->port_state[port].sp_mtx);
4113 }
4114
4115 static void
socal_lbf_done(fcal_packet_t * fcalpkt)4116 socal_lbf_done(fcal_packet_t *fcalpkt)
4117 {
4118 uint32_t port;
4119 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4120
4121 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4122 port = 1;
4123 else
4124 port = 0;
4125 mutex_enter(&socalp->port_state[port].sp_mtx);
4126 socalp->port_state[port].sp_status &= ~PORT_LBF_PENDING;
4127 cv_broadcast(&socalp->port_state[port].sp_cv);
4128 mutex_exit(&socalp->port_state[port].sp_mtx);
4129 }
4130
4131 static void
socal_rls_done(fcal_packet_t * fcalpkt)4132 socal_rls_done(fcal_packet_t *fcalpkt)
4133 {
4134 uint32_t port;
4135 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4136
4137 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4138 port = 1;
4139 else
4140 port = 0;
4141 mutex_enter(&socalp->port_state[port].sp_mtx);
4142 socalp->port_state[port].sp_status &= ~PORT_RLS_PENDING;
4143 cv_broadcast(&socalp->port_state[port].sp_cv);
4144 mutex_exit(&socalp->port_state[port].sp_mtx);
4145 }
4146
4147 static void
socal_force_offline_done(fcal_packet_t * fcalpkt)4148 socal_force_offline_done(fcal_packet_t *fcalpkt)
4149 {
4150 uint32_t port;
4151 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4152
4153 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4154 port = 1;
4155 else
4156 port = 0;
4157 mutex_enter(&socalp->port_state[port].sp_mtx);
4158 socalp->port_state[port].sp_status &= ~PORT_OFFLINE_PENDING;
4159 cv_broadcast(&socalp->port_state[port].sp_cv);
4160 mutex_exit(&socalp->port_state[port].sp_mtx);
4161 }
4162
4163 static void
socal_abort_done(fcal_packet_t * fcalpkt)4164 socal_abort_done(fcal_packet_t *fcalpkt)
4165 {
4166 uint32_t port;
4167 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4168 soc_header_t *shp =
4169 (soc_header_t *)&fcalpkt->fcal_socal_request.sr_soc_hdr;
4170 fcal_packet_t *target = (fcal_packet_t *)
4171 SOCAL_ID_LOOKUP(shp->sh_request_token);
4172
4173 mutex_enter(&socalp->abort_mtx);
4174 ASSERT(target->fcal_pkt_flags & FCFLAG_ABORTING);
4175 if (!(target->fcal_pkt_flags & FCFLAG_COMPLETE)) {
4176 SOCAL_ID_FREE(shp->sh_request_token);
4177 }
4178 mutex_exit(&socalp->abort_mtx);
4179 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4180 port = 1;
4181 else
4182 port = 0;
4183 mutex_enter(&socalp->port_state[port].sp_mtx);
4184 socalp->port_state[port].sp_status &= ~PORT_ABORT_PENDING;
4185 cv_broadcast(&socalp->port_state[port].sp_cv);
4186 mutex_exit(&socalp->port_state[port].sp_mtx);
4187 }
4188
4189 static void
socal_bypass_dev_done(fcal_packet_t * fcalpkt)4190 socal_bypass_dev_done(fcal_packet_t *fcalpkt)
4191 {
4192 uint32_t port;
4193 socal_state_t *socalp = (socal_state_t *)fcalpkt->fcal_pkt_cookie;
4194 if (fcalpkt->fcal_socal_request.sr_soc_hdr.sh_flags & SOC_PORT_B)
4195 port = 1;
4196 else
4197 port = 0;
4198 mutex_enter(&socalp->port_state[port].sp_mtx);
4199 socalp->port_state[port].sp_status &= ~PORT_BYPASS_PENDING;
4200 cv_broadcast(&socalp->port_state[port].sp_cv);
4201 mutex_exit(&socalp->port_state[port].sp_mtx);
4202 }
4203
4204 /*ARGSUSED*/
4205 static unsigned int
socal_dummy_intr(caddr_t arg)4206 socal_dummy_intr(caddr_t arg)
4207 {
4208 return (DDI_INTR_UNCLAIMED);
4209 }
4210
4211 static int
socal_diag_request(socal_state_t * socalp,uint32_t port,uint_t * diagcode,uint32_t cmd)4212 socal_diag_request(socal_state_t *socalp, uint32_t port, uint_t *diagcode,
4213 uint32_t cmd)
4214 {
4215 fcal_packet_t *fcalpkt;
4216 soc_diag_request_t *sdr;
4217 socal_port_t *port_statep = &socalp->port_state[port];
4218 struct fcal_lilp_map map;
4219
4220 /* Grabbing the state mutex is totally unnecessary.... */
4221 if (!(port_statep->sp_status & PORT_DISABLED)) {
4222 if (socal_getmap(socalp, port, (caddr_t)&map, 0, FKIOCTL)
4223 != -1) {
4224 if (map.lilp_length != 1 && ((port_statep->sp_status &
4225 PORT_ONLINE_LOOP) && cmd != SOC_DIAG_REM_LOOP))
4226 return (FCAL_TRANSPORT_UNAVAIL);
4227 }
4228 }
4229 if ((fcalpkt = socal_packet_alloc(socalp, FCAL_SLEEP))
4230 == (fcal_packet_t *)NULL)
4231 return (FCAL_ALLOC_FAILED);
4232 sdr = (soc_diag_request_t *)&fcalpkt->fcal_socal_request;
4233 if (port)
4234 sdr->sdr_soc_hdr.sh_flags = SOC_PORT_B;
4235 sdr->sdr_diag_cmd = cmd;
4236 sdr->sdr_cqhdr.cq_hdr_count = 1;
4237 sdr->sdr_cqhdr.cq_hdr_type = CQ_TYPE_DIAGNOSTIC;
4238 fcalpkt->fcal_pkt_cookie = (void *)socalp;
4239 return (socal_doit(fcalpkt, port_statep, 1, NULL,
4240 SOCAL_DIAG_TIMEOUT, 0, diagcode));
4241 }
4242
4243 static uint_t
socal_force_offline(void * ssp,uint_t port,uint_t polled)4244 socal_force_offline(void *ssp, uint_t port, uint_t polled)
4245 {
4246 fcal_packet_t *fcalpkt;
4247 soc_cmdonly_request_t *scr;
4248 socal_state_t *socalp = (socal_state_t *)ssp;
4249 socal_port_t *port_statep = &socalp->port_state[port];
4250
4251 if ((fcalpkt =
4252 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
4253 == (fcal_packet_t *)NULL)
4254 return (FCAL_ALLOC_FAILED);
4255
4256 scr = (soc_cmdonly_request_t *)&fcalpkt->fcal_socal_request;
4257 if (port)
4258 scr->scr_soc_hdr.sh_flags = SOC_PORT_B;
4259 scr->scr_cqhdr.cq_hdr_count = 1;
4260 scr->scr_cqhdr.cq_hdr_type = CQ_TYPE_OFFLINE;
4261 fcalpkt->fcal_pkt_cookie = (void *)socalp;
4262 return (socal_doit(fcalpkt, port_statep, 0, socal_force_offline_done,
4263 SOCAL_OFFLINE_TIMEOUT, PORT_OFFLINE_PENDING, NULL));
4264 }
4265
4266 static int
socal_issue_adisc(socal_state_t * socalp,uint32_t port,uint32_t dest,la_els_adisc_t * payload,uint32_t polled)4267 socal_issue_adisc(socal_state_t *socalp, uint32_t port, uint32_t dest,
4268 la_els_adisc_t *payload, uint32_t polled)
4269 {
4270 int retval;
4271 la_els_adisc_t *buf;
4272 fcal_packet_t *fcalpkt;
4273 socal_port_t *port_statep;
4274 socal_priv_cmd_t *privp;
4275
4276 port_statep = &socalp->port_state[port];
4277
4278 if ((fcalpkt =
4279 socal_els_alloc(socalp, port, dest, sizeof (la_els_adisc_t),
4280 sizeof (la_els_adisc_t), (caddr_t *)&privp, polled))
4281 == (fcal_packet_t *)NULL)
4282 return (FCAL_ALLOC_FAILED);
4283
4284 privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
4285 buf = (la_els_adisc_t *)privp->cmd;
4286 buf->ls_code = LA_ELS_ADISC;
4287 buf->mbz[0] = 0;
4288 buf->mbz[1] = 0;
4289 buf->mbz[2] = 0;
4290 buf->hard_address = 0;
4291 bcopy((caddr_t)&port_statep->sp_p_wwn,
4292 (caddr_t)&buf->port_wwn, sizeof (buf->port_wwn));
4293 bcopy((caddr_t)&socalp->socal_n_wwn,
4294 (caddr_t)&buf->node_wwn, sizeof (buf->node_wwn));
4295 buf->nport_id = fcalpkt->fcal_socal_request.sr_fc_frame_hdr.s_id;
4296 (void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
4297
4298 retval = socal_doit(fcalpkt, port_statep, 0, socal_adisc_done,
4299 SOCAL_ADISC_TIMEOUT, PORT_ADISC_PENDING, NULL);
4300 if (retval == FCAL_SUCCESS) {
4301 (void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4302 DDI_DMA_SYNC_FORKERNEL);
4303 bcopy(privp->rsp, (caddr_t)payload, sizeof (la_els_adisc_t));
4304 }
4305 privp->fapktp = NULL;
4306 socal_els_free(privp);
4307 return (retval);
4308 }
4309
4310 static int
socal_issue_lbf(socal_state_t * socalp,uint32_t port,uchar_t * payload,size_t length,uint32_t polled)4311 socal_issue_lbf(socal_state_t *socalp, uint32_t port,
4312 uchar_t *payload, size_t length, uint32_t polled)
4313 {
4314 int retval;
4315 fcal_packet_t *fcalpkt;
4316 socal_port_t *port_statep;
4317 socal_priv_cmd_t *privp;
4318
4319 port_statep = &socalp->port_state[port];
4320
4321 if ((fcalpkt = socal_lbf_alloc(socalp, port, length, length,
4322 (caddr_t *)&privp, polled)) == (fcal_packet_t *)NULL)
4323 return (FCAL_ALLOC_FAILED);
4324
4325 privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
4326 bcopy((caddr_t)payload, privp->cmd, length);
4327 (void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
4328
4329 retval = socal_doit(fcalpkt, port_statep, polled, socal_lbf_done,
4330 SOCAL_LBF_TIMEOUT, PORT_LBF_PENDING, NULL);
4331
4332 if (retval == FCAL_SUCCESS) {
4333 (void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4334 DDI_DMA_SYNC_FORKERNEL);
4335 bcopy(privp->rsp, (caddr_t)payload, length);
4336 }
4337 privp->fapktp = NULL;
4338 socal_lbf_free(privp);
4339 return (retval);
4340 }
4341
4342 static int
socal_issue_rls(socal_state_t * socalp,uint32_t port,uint32_t dest,la_els_rls_reply_t * payload,uint32_t polled)4343 socal_issue_rls(socal_state_t *socalp, uint32_t port, uint32_t dest,
4344 la_els_rls_reply_t *payload, uint32_t polled)
4345 {
4346 int retval;
4347 la_els_rls_t *buf;
4348 fcal_packet_t *fcalpkt;
4349 socal_port_t *port_statep;
4350 socal_priv_cmd_t *privp;
4351 uint32_t arg;
4352
4353 port_statep = &socalp->port_state[port];
4354
4355 if (dest == socal_getmap(socalp, port, NULL, 0, 0)) {
4356 /* load up the the struct with the local lesb */
4357 struct la_els_rjt *rsp = (struct la_els_rjt *)payload;
4358
4359 rsp->ls_code = LA_ELS_RJT;
4360 rsp->mbz[0] = 0;
4361 rsp->mbz[1] = 0;
4362 rsp->mbz[2] = 0;
4363 rsp->reason_code = RJT_UNSUPPORTED;
4364 rsp->reserved = 0;
4365 rsp->explanation = 0;
4366 rsp->vendor = 0;
4367 return (FCAL_SUCCESS);
4368 }
4369
4370 if ((fcalpkt =
4371 socal_els_alloc(socalp, port, dest, sizeof (la_els_rls_t),
4372 sizeof (la_els_rls_reply_t), (caddr_t *)&privp, polled))
4373 == (fcal_packet_t *)NULL)
4374 return (FCAL_ALLOC_FAILED);
4375
4376 privp = (socal_priv_cmd_t *)fcalpkt->fcal_pkt_private;
4377
4378 if (payload->link_failure & 0xff000000)
4379 arg = payload->link_failure;
4380 else
4381 arg = dest;
4382
4383 buf = (la_els_rls_t *)privp->cmd;
4384 buf->ls_code = LA_ELS_RLS;
4385 buf->mbz[0] = 0;
4386 buf->mbz[1] = 0;
4387 buf->mbz[2] = 0;
4388 buf->reserved = 0;
4389 buf->nport_id[0] = (arg >> 16) & 0xff;
4390 buf->nport_id[1] = (arg >> 8) & 0xff;
4391 buf->nport_id[2] = arg & 0xff;
4392 (void) ddi_dma_sync(privp->cmd_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
4393
4394 retval = socal_doit(fcalpkt, port_statep, 0, socal_rls_done,
4395 SOCAL_RLS_TIMEOUT, PORT_RLS_PENDING, NULL);
4396 if (retval == FCAL_SUCCESS) {
4397 (void) ddi_dma_sync(privp->rsp_handle, 0, 0,
4398 DDI_DMA_SYNC_FORKERNEL);
4399 bcopy(privp->rsp, (caddr_t)payload,
4400 sizeof (la_els_rls_reply_t));
4401 }
4402 privp->fapktp = NULL;
4403 socal_els_free(privp);
4404 return (retval);
4405 }
4406
4407 fcal_packet_t *
socal_els_alloc(socal_state_t * socalp,uint32_t port,uint32_t dest,uint32_t cmd_size,uint32_t rsp_size,caddr_t * rprivp,uint32_t polled)4408 socal_els_alloc(socal_state_t *socalp, uint32_t port, uint32_t dest,
4409 uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp, uint32_t polled)
4410 {
4411 struct fcal_packet *fcalpkt;
4412 ddi_dma_cookie_t ccookie;
4413 ddi_dma_cookie_t rcookie;
4414 socal_priv_cmd_t *privp;
4415 ddi_dma_handle_t chandle = NULL;
4416 ddi_dma_handle_t rhandle = NULL;
4417 ddi_acc_handle_t cacchandle;
4418 ddi_acc_handle_t racchandle;
4419 soc_request_t *srp;
4420 fc_frame_header_t *fhp;
4421 uint_t ccount, cmd_bound = 0, rsp_bound = 0;
4422 size_t real_len;
4423 caddr_t cmd;
4424 caddr_t rsp;
4425 uint32_t ouralpa;
4426
4427 if ((fcalpkt =
4428 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
4429 == (fcal_packet_t *)NULL)
4430 return (NULL);
4431
4432 if ((privp =
4433 (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
4434 polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
4435 goto fail;
4436 }
4437
4438 rprivp = (caddr_t *)&privp;
4439
4440 fcalpkt->fcal_pkt_private = (caddr_t)privp;
4441 privp->fapktp = (void *)fcalpkt;
4442
4443 if ((ouralpa = socal_getmap(socalp, port, NULL, 0, 0)) == -1)
4444 goto fail;
4445
4446 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4447 DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
4448 goto fail;
4449 privp->cmd_handle = chandle;
4450
4451 if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
4452 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4453 (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
4454 goto fail;
4455 privp->cmd = cmd;
4456 privp->cmd_acchandle = cacchandle;
4457
4458 if (real_len < cmd_size)
4459 goto fail;
4460
4461 if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
4462 (caddr_t)cmd, cmd_size,
4463 DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
4464 DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
4465 != DDI_DMA_MAPPED)
4466 goto fail;
4467 cmd_bound = 1;
4468 if (ccount != 1)
4469 goto fail;
4470
4471 if (rsp_size) {
4472 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4473 DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
4474 goto fail;
4475
4476 privp->rsp_handle = rhandle;
4477 if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
4478 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4479 &rsp, &real_len, &racchandle) != DDI_SUCCESS)
4480 goto fail;
4481 privp->rsp = rsp;
4482 privp->rsp_acchandle = racchandle;
4483 if (real_len < rsp_size)
4484 goto fail;
4485
4486 if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
4487 rsp, rsp_size,
4488 DDI_DMA_READ | DDI_DMA_CONSISTENT,
4489 DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4490 != DDI_DMA_MAPPED)
4491 goto fail;
4492
4493 rsp_bound = 1;
4494 if (ccount != 1)
4495 goto fail;
4496 }
4497
4498 srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
4499 srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
4500 if (port)
4501 srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
4502 srp->sr_soc_hdr.sh_class = 3;
4503 srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
4504 srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
4505 srp->sr_dataseg[0].fc_count = cmd_size;
4506 if (rsp_size == 0) {
4507 srp->sr_soc_hdr.sh_seg_cnt = 1;
4508 } else {
4509 srp->sr_soc_hdr.sh_seg_cnt = 2;
4510 srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
4511 srp->sr_dataseg[1].fc_count = rsp_size;
4512 }
4513 srp->sr_cqhdr.cq_hdr_count = 1;
4514 /* this will potentially be overwritten by the calling function */
4515 srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
4516
4517 fcalpkt->fcal_pkt_cookie = (void *)socalp;
4518
4519 /* Fill in the Fabric Channel Header */
4520 fhp = &srp->sr_fc_frame_hdr;
4521 fhp->r_ctl = R_CTL_ELS_REQ;
4522 fhp->d_id = dest;
4523 fhp->s_id = ouralpa;
4524 fhp->type = TYPE_EXTENDED_LS;
4525 fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4526 fhp->seq_id = 0;
4527 fhp->df_ctl = 0;
4528 fhp->seq_cnt = 0;
4529 fhp->ox_id = 0xffff;
4530 fhp->rx_id = 0xffff;
4531 fhp->ro = 0;
4532 return (fcalpkt);
4533 fail:
4534 socal_packet_free(fcalpkt);
4535 if (privp) {
4536 if (privp->cmd_handle) {
4537 if (cmd_bound)
4538 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4539 ddi_dma_free_handle(&privp->cmd_handle);
4540 }
4541 if (privp->cmd)
4542 ddi_dma_mem_free(&privp->cmd_acchandle);
4543 if (privp->rsp_handle) {
4544 if (rsp_bound)
4545 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4546 ddi_dma_free_handle(&privp->rsp_handle);
4547 }
4548 if (privp->rsp)
4549 ddi_dma_mem_free(&privp->rsp_acchandle);
4550
4551 kmem_free(privp, sizeof (*privp));
4552 }
4553 return (NULL);
4554 }
4555
4556 fcal_packet_t *
socal_lbf_alloc(socal_state_t * socalp,uint32_t port,uint32_t cmd_size,uint32_t rsp_size,caddr_t * rprivp,uint32_t polled)4557 socal_lbf_alloc(socal_state_t *socalp, uint32_t port,
4558 uint32_t cmd_size, uint32_t rsp_size, caddr_t *rprivp,
4559 uint32_t polled)
4560 {
4561 struct fcal_packet *fcalpkt;
4562 ddi_dma_cookie_t ccookie;
4563 ddi_dma_cookie_t rcookie;
4564 socal_priv_cmd_t *privp;
4565 ddi_dma_handle_t chandle = NULL;
4566 ddi_dma_handle_t rhandle = NULL;
4567 ddi_acc_handle_t cacchandle;
4568 ddi_acc_handle_t racchandle;
4569 soc_request_t *srp;
4570 fc_frame_header_t *fhp;
4571 uint_t ccount, cmd_bound = 0, rsp_bound = 0;
4572 size_t real_len;
4573 caddr_t cmd;
4574 caddr_t rsp;
4575
4576 if ((fcalpkt =
4577 socal_packet_alloc(socalp, polled ? FCAL_NOSLEEP : FCAL_SLEEP))
4578 == (fcal_packet_t *)NULL)
4579 return (NULL);
4580
4581 if ((privp =
4582 (socal_priv_cmd_t *)kmem_zalloc(sizeof (socal_priv_cmd_t),
4583 polled ? KM_NOSLEEP : KM_SLEEP)) == (socal_priv_cmd_t *)NULL) {
4584 goto fail;
4585 }
4586
4587 rprivp = (caddr_t *)&privp;
4588
4589 fcalpkt->fcal_pkt_private = (caddr_t)privp;
4590 privp->fapktp = (void *)fcalpkt;
4591
4592 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4593 DDI_DMA_DONTWAIT, NULL, &chandle) != DDI_SUCCESS)
4594 goto fail;
4595 privp->cmd_handle = chandle;
4596
4597 if (ddi_dma_mem_alloc(chandle, cmd_size, &socal_acc_attr,
4598 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4599 (caddr_t *)&cmd, &real_len, &cacchandle) != DDI_SUCCESS)
4600 goto fail;
4601 privp->cmd = cmd;
4602 privp->cmd_acchandle = cacchandle;
4603
4604 if (real_len < cmd_size)
4605 goto fail;
4606
4607 if (ddi_dma_addr_bind_handle(chandle, (struct as *)NULL,
4608 (caddr_t)cmd, cmd_size,
4609 DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
4610 DDI_DMA_DONTWAIT, NULL, &ccookie, &ccount)
4611 != DDI_DMA_MAPPED)
4612 goto fail;
4613 cmd_bound = 1;
4614 if (ccount != 1)
4615 goto fail;
4616
4617 if (rsp_size) {
4618 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4619 DDI_DMA_DONTWAIT, NULL, &rhandle) != DDI_SUCCESS)
4620 goto fail;
4621
4622 privp->rsp_handle = rhandle;
4623 if (ddi_dma_mem_alloc(rhandle, rsp_size, &socal_acc_attr,
4624 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4625 &rsp, &real_len, &racchandle) != DDI_SUCCESS)
4626 goto fail;
4627
4628 privp->rsp = rsp;
4629 privp->rsp_acchandle = racchandle;
4630 if (real_len < rsp_size)
4631 goto fail;
4632
4633 if (ddi_dma_addr_bind_handle(rhandle, (struct as *)NULL,
4634 rsp, rsp_size,
4635 DDI_DMA_READ | DDI_DMA_CONSISTENT,
4636 DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount)
4637 != DDI_DMA_MAPPED)
4638 goto fail;
4639
4640 rsp_bound = 1;
4641 if (ccount != 1)
4642 goto fail;
4643 }
4644
4645 srp = (soc_request_t *)&fcalpkt->fcal_socal_request;
4646 srp->sr_soc_hdr.sh_flags = SOC_FC_HEADER;
4647 if (port)
4648 srp->sr_soc_hdr.sh_flags |= SOC_PORT_B;
4649 srp->sr_soc_hdr.sh_class = 3;
4650 srp->sr_soc_hdr.sh_byte_cnt = cmd_size;
4651 srp->sr_dataseg[0].fc_base = (uint32_t)ccookie.dmac_address;
4652 srp->sr_dataseg[0].fc_count = cmd_size;
4653 if (rsp_size == 0) {
4654 srp->sr_soc_hdr.sh_seg_cnt = 1;
4655 } else {
4656 srp->sr_soc_hdr.sh_seg_cnt = 2;
4657 srp->sr_dataseg[1].fc_base = (uint32_t)rcookie.dmac_address;
4658 srp->sr_dataseg[1].fc_count = rsp_size;
4659 }
4660 srp->sr_cqhdr.cq_hdr_count = 1;
4661 /* this will potentially be overwritten by the calling function */
4662 srp->sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
4663
4664 fcalpkt->fcal_pkt_cookie = (void *)socalp;
4665
4666 /* Fill in the Fabric Channel Header */
4667 fhp = &srp->sr_fc_frame_hdr;
4668 fhp->r_ctl = R_CTL_SOLICITED_DATA;
4669 fhp->d_id = socalp->port_state[port].sp_src_id;
4670 fhp->s_id = socalp->port_state[port].sp_src_id;
4671 fhp->type = TYPE_SCSI_FCP;
4672 fhp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ | F_CTL_LAST_SEQ;
4673 fhp->seq_id = 0;
4674 fhp->df_ctl = 0;
4675 fhp->seq_cnt = 0;
4676 fhp->ox_id = 0xffff;
4677 fhp->rx_id = 0xffff;
4678 fhp->ro = 0;
4679 return (fcalpkt);
4680 fail:
4681 socal_packet_free(fcalpkt);
4682 if (privp) {
4683 if (privp->cmd_handle) {
4684 if (cmd_bound)
4685 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4686 ddi_dma_free_handle(&privp->cmd_handle);
4687 }
4688 if (privp->cmd)
4689 ddi_dma_mem_free(&privp->cmd_acchandle);
4690 if (privp->rsp_handle) {
4691 if (rsp_bound)
4692 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4693 ddi_dma_free_handle(&privp->rsp_handle);
4694 }
4695 if (privp->rsp)
4696 ddi_dma_mem_free(&privp->rsp_acchandle);
4697
4698 kmem_free(privp, sizeof (*privp));
4699 }
4700 return (NULL);
4701 }
4702
4703 void
socal_els_free(socal_priv_cmd_t * privp)4704 socal_els_free(socal_priv_cmd_t *privp)
4705 {
4706 fcal_packet_t *fcalpkt;
4707
4708 if (privp)
4709 fcalpkt = (fcal_packet_t *)privp->fapktp;
4710 else
4711 return;
4712
4713 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4714 ddi_dma_free_handle(&privp->cmd_handle);
4715 ddi_dma_mem_free(&privp->cmd_acchandle);
4716
4717 if (privp->rsp_handle) {
4718 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4719 ddi_dma_free_handle(&privp->rsp_handle);
4720 }
4721 if (privp->rsp)
4722 ddi_dma_mem_free(&privp->rsp_acchandle);
4723
4724 kmem_free(privp, sizeof (*privp));
4725 if (fcalpkt != NULL)
4726 socal_packet_free(fcalpkt);
4727 }
4728
4729 void
socal_lbf_free(socal_priv_cmd_t * privp)4730 socal_lbf_free(socal_priv_cmd_t *privp)
4731 {
4732 fcal_packet_t *fcalpkt;
4733
4734 if (privp)
4735 fcalpkt = (fcal_packet_t *)privp->fapktp;
4736 else
4737 return;
4738
4739 (void) ddi_dma_unbind_handle(privp->cmd_handle);
4740 ddi_dma_free_handle(&privp->cmd_handle);
4741 ddi_dma_mem_free(&privp->cmd_acchandle);
4742
4743 if (privp->rsp_handle) {
4744 (void) ddi_dma_unbind_handle(privp->rsp_handle);
4745 ddi_dma_free_handle(&privp->rsp_handle);
4746 }
4747
4748 if (privp->rsp)
4749 ddi_dma_mem_free(&privp->rsp_acchandle);
4750
4751 kmem_free(privp, sizeof (*privp));
4752 if (fcalpkt != NULL)
4753 socal_packet_free(fcalpkt);
4754 }
4755
4756 static int
socal_getmap(socal_state_t * socalp,uint32_t port,caddr_t arg,uint32_t polled,int flags)4757 socal_getmap(socal_state_t *socalp, uint32_t port, caddr_t arg,
4758 uint32_t polled, int flags)
4759 {
4760 ddi_dma_cookie_t dcookie;
4761 ddi_dma_handle_t dhandle = NULL;
4762 ddi_acc_handle_t acchandle;
4763 size_t real_len, i;
4764 uint_t ccount;
4765 fcal_lilp_map_t *buf = NULL;
4766 int retval, bound = 0;
4767 socal_port_t *port_statep;
4768
4769 port_statep = &socalp->port_state[port];
4770
4771 if (port_statep->sp_lilpmap_valid) {
4772
4773 buf = &port_statep->sp_lilpmap; /* give from cache */
4774
4775 if (arg) {
4776 if (ddi_copyout(buf, (caddr_t)arg,
4777 sizeof (struct lilpmap), flags) == -1)
4778 return (-1);
4779 }
4780
4781 return (buf->lilp_myalpa);
4782 }
4783
4784 if (ddi_dma_alloc_handle(socalp->dip, &socal_dma_attr,
4785 DDI_DMA_DONTWAIT, NULL, &dhandle) != DDI_SUCCESS)
4786 goto getmap_fail;
4787
4788 i = sizeof (struct fcal_lilp_map);
4789
4790 if (ddi_dma_mem_alloc(dhandle, i, &socal_acc_attr,
4791 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4792 (caddr_t *)&buf, &real_len, &acchandle) != DDI_SUCCESS)
4793 goto getmap_fail;
4794
4795 if (real_len < i)
4796 goto getmap_fail;
4797
4798 if (ddi_dma_addr_bind_handle(dhandle, (struct as *)NULL,
4799 (caddr_t)buf, i, DDI_DMA_READ | DDI_DMA_CONSISTENT,
4800 DDI_DMA_DONTWAIT, NULL, &dcookie, &ccount) != DDI_DMA_MAPPED)
4801 goto getmap_fail;
4802
4803 bound = 1;
4804 if (ccount != 1)
4805 goto getmap_fail;
4806
4807 retval = socal_lilp_map((void *)socalp, port,
4808 (uint32_t)dcookie.dmac_address, polled);
4809
4810 (void) ddi_dma_sync(dhandle, 0, 0, DDI_DMA_SYNC_FORKERNEL);
4811
4812 if (retval == FCAL_SUCCESS) {
4813 bcopy(buf, &port_statep->sp_lilpmap, sizeof (fcal_lilp_map_t));
4814
4815 mutex_enter(&port_statep->sp_mtx);
4816 port_statep->sp_src_id = buf->lilp_myalpa;
4817 port_statep->sp_lilpmap_valid = 1; /* cached */
4818 mutex_exit(&port_statep->sp_mtx);
4819
4820 if (arg) {
4821 if (ddi_copyout(buf, (caddr_t)arg,
4822 sizeof (struct lilpmap), flags) == -1)
4823 goto getmap_fail;
4824 }
4825
4826 retval = buf->lilp_myalpa;
4827 }
4828 else
4829 retval = -1;
4830
4831 (void) ddi_dma_unbind_handle(dhandle);
4832 ddi_dma_mem_free(&acchandle);
4833 ddi_dma_free_handle(&dhandle);
4834 return (retval);
4835
4836 getmap_fail:
4837 if (dhandle) {
4838 if (bound)
4839 (void) ddi_dma_unbind_handle(dhandle);
4840 ddi_dma_free_handle(&dhandle);
4841 }
4842 if (buf)
4843 ddi_dma_mem_free(&acchandle);
4844 return (-1);
4845 }
4846
4847 static void
socal_wcopy(uint_t * h_src,uint_t * h_dest,int len)4848 socal_wcopy(uint_t *h_src, uint_t *h_dest, int len)
4849 {
4850 int i;
4851 for (i = 0; i < len/4; i++) {
4852 *h_dest++ = *h_src++;
4853 }
4854 }
4855
4856 static void
socal_flush_overflowq(socal_state_t * socalp,int port,int q_no)4857 socal_flush_overflowq(socal_state_t *socalp, int port, int q_no)
4858 {
4859 socal_kcq_t *kcq;
4860 fcal_packet_t *fpkt1, *fpkt2, *head = NULL, *tmp;
4861
4862 kcq = &socalp->request[q_no];
4863 mutex_enter(&kcq->skc_mtx);
4864 fpkt2 = kcq->skc_overflowh;
4865 fpkt1 = NULL;
4866 while (fpkt2 != NULL) {
4867 if ((((soc_request_t *)&fpkt2->fcal_socal_request)
4868 ->sr_soc_hdr.sh_flags & SOC_PORT_B) == port) {
4869 if (fpkt1 == NULL)
4870 kcq->skc_overflowh = fpkt2->fcal_pkt_next;
4871 else {
4872 fpkt1->fcal_pkt_next = fpkt2->fcal_pkt_next;
4873 if (kcq->skc_overflowt == fpkt2)
4874 kcq->skc_overflowt = fpkt1;
4875 }
4876 tmp = fpkt2->fcal_pkt_next;
4877 fpkt2->fcal_pkt_next = head;
4878 head = fpkt2;
4879 fpkt2 = tmp;
4880 SOCAL_ID_FREE(head->fcal_socal_request.
4881 sr_soc_hdr.sh_request_token);
4882 } else {
4883 fpkt1 = fpkt2;
4884 fpkt2 = fpkt2->fcal_pkt_next;
4885 }
4886 }
4887 mutex_exit(&kcq->skc_mtx);
4888 fpkt2 = head;
4889 while (fpkt2 != NULL) {
4890 fpkt2->fcal_pkt_status = FCAL_STATUS_ERR_OFFLINE;
4891 fpkt2->fcal_cmd_state |= FCAL_CMD_COMPLETE;
4892 fpkt2->fcal_pkt_flags |= FCFLAG_COMPLETE;
4893 tmp = fpkt2->fcal_pkt_next;
4894 if (fpkt2->fcal_pkt_comp != NULL)
4895 (*fpkt2->fcal_pkt_comp)(fpkt2);
4896 fpkt2 = tmp;
4897 }
4898 }
4899
4900 static void
socal_deferred_intr(void * arg)4901 socal_deferred_intr(void *arg)
4902 {
4903 socal_kcq_t *kcq = (socal_kcq_t *)arg;
4904 socal_state_t *socalp = kcq->skc_socalp;
4905
4906 ASSERT((socalp != NULL));
4907
4908 mutex_enter(&kcq->skc_mtx);
4909
4910 if ((kcq->skc_out != kcq->skc_saved_out) ||
4911 (kcq->skc_seqno != kcq->skc_saved_seqno)) {
4912 kcq->deferred_intr_timeoutid = 0;
4913 mutex_exit(&kcq->skc_mtx);
4914 return;
4915 }
4916
4917 if (socalp->socal_on_intr) {
4918 mutex_exit(&kcq->skc_mtx);
4919 kcq->deferred_intr_timeoutid = timeout(socal_deferred_intr,
4920 (caddr_t)kcq, drv_usectohz(10000));
4921 return;
4922 }
4923
4924 kcq->deferred_intr_timeoutid = 0;
4925 mutex_exit(&kcq->skc_mtx);
4926 socal_intr_solicited(socalp, 0);
4927 }
4928
4929 static void
socal_take_core(void * arg)4930 socal_take_core(void *arg)
4931 {
4932 socal_state_t *socalp = (socal_state_t *)arg;
4933 int i, instance;
4934
4935 socal_disable(socalp);
4936 for (i = 0; i < SOCAL_N_CQS; i++) {
4937 mutex_enter(&socalp->request[i].skc_mtx);
4938 mutex_enter(&socalp->response[i].skc_mtx);
4939 }
4940 for (i = 0; i < 4; i++) {
4941 socalp->socal_rp->socal_cr.w &=
4942 ~SOCAL_CR_EXTERNAL_RAM_BANK_MASK;
4943 socalp->socal_rp->socal_cr.w |= i<<24;
4944 (void) bcopy((caddr_t)socalp->socal_xrp,
4945 (caddr_t)&socal_xrambuf[i*0x10000], 0x10000);
4946 }
4947 for (i = 3; i >= 0; i--) {
4948 mutex_exit(&socalp->request[i].skc_mtx);
4949 mutex_exit(&socalp->response[i].skc_mtx);
4950 }
4951 instance = ddi_get_instance(socalp->dip);
4952 cmn_err(CE_PANIC,
4953 "socal take core (socal instance %d)", instance);
4954 }
4955
4956 /*
4957 * Preset AL_PA in hardware, if is told.
4958 */
4959 static void
socal_fix_harda(socal_state_t * socalp,int port)4960 socal_fix_harda(socal_state_t *socalp, int port)
4961 {
4962 socal_port_t *portp = &socalp->port_state[port];
4963 uint_t *xrp = (uint_t *)socalp->socal_xrp;
4964 uint_t accum, harda;
4965
4966 harda = portp->sp_hard_alpa;
4967 accum = xrp[SOCAL_XRAM_PORTA_HRDA/4];
4968 if (port == 0) {
4969 accum &= 0x00FFFFFF;
4970 accum |= ((harda & 0xFF) << 24);
4971 } else {
4972 accum &= 0xFF00FFFF;
4973 accum |= ((harda & 0xFF) << 16);
4974 }
4975 xrp[SOCAL_XRAM_PORTA_HRDA/4] = accum;
4976 }
4977
4978 /*
4979 * Target-Mode attach function
4980 */
4981 fcal_transport_t *
socal_sftm_attach(dev_t dev,int loop_id)4982 socal_sftm_attach(dev_t dev, int loop_id)
4983 {
4984 int instance = getminor(dev) / 2;
4985 int port = getminor(dev) % 2;
4986 int hard_alpa;
4987 char *name;
4988 socal_state_t *socalp;
4989
4990 /*
4991 * If the device is not a "socal" device, return
4992 */
4993 if ((name = ddi_major_to_name(getmajor(dev))) == NULL ||
4994 strcmp(name, "socal") != 0)
4995 return (NULL);
4996
4997 /*
4998 * If no soft state structure, return
4999 */
5000 socalp = ddi_get_soft_state(socal_soft_state_p, instance);
5001 if (socalp == NULL)
5002 return (NULL);
5003
5004 /*
5005 * If the port is already attached, return
5006 */
5007 if (socalp->port_state[port].sp_status & PORT_CHILD_INIT)
5008 return (NULL);
5009
5010 if (loop_id < 0 || loop_id > 126)
5011 return (NULL);
5012
5013 /* if this instance is detaching, don't attach */
5014 mutex_enter(&socalp->board_mtx);
5015 mutex_enter(&socalp->port_state[port].sp_mtx);
5016 if (socalp->socal_busy < 0) {
5017 mutex_exit(&socalp->port_state[port].sp_mtx);
5018 mutex_exit(&socalp->board_mtx);
5019 return (NULL);
5020 }
5021 socalp->socal_busy++;
5022 socalp->port_state[port].sp_status |= PORT_CHILD_INIT;
5023 mutex_exit(&socalp->port_state[port].sp_mtx);
5024 mutex_exit(&socalp->board_mtx);
5025
5026 /*
5027 * Since we keep the Hard Loop-id in two config files, warn the
5028 * user if they don't match.
5029 */
5030 hard_alpa = socal_switch_to_alpa[loop_id];
5031 if (hard_alpa != socalp->port_state[port].sp_hard_alpa) {
5032 socalp->port_state[port].sp_hard_alpa = hard_alpa;
5033 cmn_err(CE_WARN, "socal%d: Hard Loop-id mismatch - "
5034 "using Loop-id %d",
5035 instance, loop_id);
5036 }
5037
5038 return (socalp->port_state[port].sp_transport);
5039 }
5040
5041
5042 /*
5043 * Target-Mode detach function
5044 */
5045 int
socal_sftm_detach(socal_state_t * socalp,int port)5046 socal_sftm_detach(socal_state_t *socalp, int port)
5047 {
5048 mutex_enter(&socalp->board_mtx);
5049 socalp->socal_busy--;
5050 socalp->port_state[port].sp_status &= ~PORT_CHILD_INIT;
5051 mutex_exit(&socalp->board_mtx);
5052
5053 return (0);
5054 }
5055