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