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