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