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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/conf.h> 27 #include <sys/file.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/modctl.h> 31 #include <sys/scsi/scsi.h> 32 #include <sys/scsi/impl/scsi_reset_notify.h> 33 #include <sys/disp.h> 34 #include <sys/byteorder.h> 35 #include <sys/varargs.h> 36 #include <sys/atomic.h> 37 #include <sys/sdt.h> 38 39 #include <stmf.h> 40 #include <stmf_ioctl.h> 41 #include <portif.h> 42 #include <fct.h> 43 #include <fctio.h> 44 #include <fct_impl.h> 45 #include <discovery.h> 46 47 static int fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 48 static int fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 49 static int fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 50 void **result); 51 static int fct_open(dev_t *devp, int flag, int otype, cred_t *credp); 52 static int fct_close(dev_t dev, int flag, int otype, cred_t *credp); 53 static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 54 cred_t *credp, int *rval); 55 static int fct_fctiocmd(intptr_t data, int mode); 56 57 static dev_info_t *fct_dip; 58 static struct cb_ops fct_cb_ops = { 59 fct_open, /* open */ 60 fct_close, /* close */ 61 nodev, /* strategy */ 62 nodev, /* print */ 63 nodev, /* dump */ 64 nodev, /* read */ 65 nodev, /* write */ 66 fct_ioctl, /* ioctl */ 67 nodev, /* devmap */ 68 nodev, /* mmap */ 69 nodev, /* segmap */ 70 nochpoll, /* chpoll */ 71 ddi_prop_op, /* cb_prop_op */ 72 0, /* streamtab */ 73 D_NEW | D_MP, /* cb_flag */ 74 CB_REV, /* rev */ 75 nodev, /* aread */ 76 nodev /* awrite */ 77 }; 78 79 static struct dev_ops fct_ops = { 80 DEVO_REV, 81 0, 82 fct_getinfo, 83 nulldev, /* identify */ 84 nulldev, /* probe */ 85 fct_attach, 86 fct_detach, 87 nodev, /* reset */ 88 &fct_cb_ops, 89 NULL, /* bus_ops */ 90 NULL /* power */ 91 }; 92 93 #define FCT_NAME "COMSTAR FCT" 94 95 extern struct mod_ops mod_driverops; 96 static struct modldrv modldrv = { 97 &mod_driverops, 98 FCT_NAME, 99 &fct_ops 100 }; 101 102 static struct modlinkage modlinkage = { 103 MODREV_1, 104 &modldrv, 105 NULL 106 }; 107 108 static uint32_t rportid_table_size = FCT_HASH_TABLE_SIZE; 109 static int max_cached_ncmds = FCT_MAX_CACHED_CMDS; 110 static fct_i_local_port_t *fct_iport_list = NULL; 111 static kmutex_t fct_global_mutex; 112 uint32_t fct_rscn_options = RSCN_OPTION_VERIFY; 113 114 int 115 _init(void) 116 { 117 int ret; 118 119 ret = mod_install(&modlinkage); 120 if (ret) 121 return (ret); 122 /* XXX */ 123 mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL); 124 return (ret); 125 } 126 127 int 128 _fini(void) 129 { 130 int ret; 131 132 ret = mod_remove(&modlinkage); 133 if (ret) 134 return (ret); 135 /* XXX */ 136 mutex_destroy(&fct_global_mutex); 137 return (ret); 138 } 139 140 int 141 _info(struct modinfo *modinfop) 142 { 143 return (mod_info(&modlinkage, modinfop)); 144 } 145 146 /* ARGSUSED */ 147 static int 148 fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 149 { 150 switch (cmd) { 151 case DDI_INFO_DEVT2DEVINFO: 152 *result = fct_dip; 153 break; 154 case DDI_INFO_DEVT2INSTANCE: 155 *result = (void *)(uintptr_t)ddi_get_instance(fct_dip); 156 break; 157 default: 158 return (DDI_FAILURE); 159 } 160 161 return (DDI_SUCCESS); 162 } 163 164 static int 165 fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 166 { 167 switch (cmd) { 168 case DDI_ATTACH: 169 fct_dip = dip; 170 171 if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0, 172 DDI_NT_STMF_PP, 0) != DDI_SUCCESS) { 173 break; 174 } 175 ddi_report_dev(dip); 176 return (DDI_SUCCESS); 177 } 178 179 return (DDI_FAILURE); 180 } 181 182 static int 183 fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 184 { 185 switch (cmd) { 186 case DDI_DETACH: 187 ddi_remove_minor_node(dip, 0); 188 return (DDI_SUCCESS); 189 } 190 191 return (DDI_FAILURE); 192 } 193 194 /* ARGSUSED */ 195 static int 196 fct_open(dev_t *devp, int flag, int otype, cred_t *credp) 197 { 198 if (otype != OTYP_CHR) 199 return (EINVAL); 200 return (0); 201 } 202 203 /* ARGSUSED */ 204 static int 205 fct_close(dev_t dev, int flag, int otype, cred_t *credp) 206 { 207 return (0); 208 } 209 210 /* ARGSUSED */ 211 static int 212 fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 213 cred_t *credp, int *rval) 214 { 215 int ret = 0; 216 217 if ((cmd & 0xff000000) != FCT_IOCTL) { 218 return (ENOTTY); 219 } 220 221 if (drv_priv(credp) != 0) { 222 return (EPERM); 223 } 224 225 switch (cmd) { 226 case FCTIO_CMD: 227 ret = fct_fctiocmd(data, mode); 228 break; 229 default: 230 ret = ENOTTY; 231 break; 232 } 233 234 return (ret); 235 } 236 237 int 238 fct_copyin_iocdata(intptr_t data, int mode, fctio_t **fctio, 239 void **ibuf, void **abuf, void **obuf) 240 { 241 int ret = 0; 242 243 *ibuf = NULL; 244 *abuf = NULL; 245 *obuf = NULL; 246 *fctio = kmem_zalloc(sizeof (fctio_t), KM_SLEEP); 247 if (ddi_copyin((void *)data, *fctio, sizeof (fctio_t), mode)) { 248 ret = EFAULT; 249 goto copyin_iocdata_done; 250 } 251 252 if ((*fctio)->fctio_ilen) { 253 *ibuf = kmem_zalloc((*fctio)->fctio_ilen, KM_SLEEP); 254 if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_ibuf, 255 *ibuf, (*fctio)->fctio_ilen, mode)) { 256 ret = EFAULT; 257 goto copyin_iocdata_done; 258 } 259 } 260 if ((*fctio)->fctio_alen) { 261 *abuf = kmem_zalloc((*fctio)->fctio_alen, KM_SLEEP); 262 if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_abuf, 263 *abuf, (*fctio)->fctio_alen, mode)) { 264 ret = EFAULT; 265 goto copyin_iocdata_done; 266 } 267 } 268 if ((*fctio)->fctio_olen) 269 *obuf = kmem_zalloc((*fctio)->fctio_olen, KM_SLEEP); 270 if (ret == 0) 271 return (0); 272 ret = EFAULT; 273 copyin_iocdata_done: 274 if (*obuf) { 275 kmem_free(*obuf, (*fctio)->fctio_olen); 276 *obuf = NULL; 277 } 278 if (*abuf) { 279 kmem_free(*abuf, (*fctio)->fctio_alen); 280 *abuf = NULL; 281 } 282 if (*ibuf) { 283 kmem_free(*ibuf, (*fctio)->fctio_ilen); 284 *ibuf = NULL; 285 } 286 kmem_free(*fctio, sizeof (fctio_t)); 287 return (ret); 288 } 289 290 int 291 fct_copyout_iocdata(intptr_t data, int mode, fctio_t *fctio, void *obuf) 292 { 293 int ret = 0; 294 295 if (fctio->fctio_olen) { 296 ret = ddi_copyout(obuf, 297 (void *)(unsigned long)fctio->fctio_obuf, fctio->fctio_olen, 298 mode); 299 if (ret) { 300 return (EFAULT); 301 } 302 } 303 ret = ddi_copyout(fctio, (void *)data, sizeof (fctio_t), mode); 304 if (ret) { 305 return (EFAULT); 306 } 307 return (0); 308 } 309 310 int 311 fct_get_port_list(char *pathList, int count) 312 { 313 fct_i_local_port_t *iport; 314 int i = 0, maxPorts = 0; 315 316 ASSERT(pathList != NULL); 317 318 mutex_enter(&fct_global_mutex); 319 for (iport = fct_iport_list; iport; iport = iport->iport_next) { 320 if (i < count) 321 bcopy(iport->iport_port->port_pwwn, 322 pathList + 8 * i, 8); 323 maxPorts ++; 324 i++; 325 } 326 mutex_exit(&fct_global_mutex); 327 return (maxPorts); 328 } 329 330 /* invoked with fct_global_mutex locked */ 331 fct_i_local_port_t * 332 fct_get_iport_per_wwn(uint8_t *pwwn) 333 { 334 fct_i_local_port_t *iport; 335 336 ASSERT(mutex_owned(&fct_global_mutex)); 337 for (iport = fct_iport_list; iport; iport = iport->iport_next) { 338 if (bcmp(iport->iport_port->port_pwwn, pwwn, 8) == 0) 339 return (iport); 340 } 341 return (NULL); 342 } 343 344 int 345 fct_get_adapter_attr(uint8_t *pwwn, fc_tgt_hba_adapter_attributes_t *hba_attr, 346 uint32_t *err_detail) 347 { 348 fct_i_local_port_t *iport; 349 fct_port_attrs_t *attr; 350 351 hba_attr->version = FCT_HBA_ADAPTER_ATTRIBUTES_VERSION; 352 iport = fct_get_iport_per_wwn(pwwn); 353 if (!iport) { 354 *err_detail = FCTIO_BADWWN; 355 return (ENXIO); 356 } 357 358 attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t), 359 KM_SLEEP); 360 mutex_exit(&fct_global_mutex); 361 iport->iport_port->port_populate_hba_details(iport->iport_port, attr); 362 mutex_enter(&fct_global_mutex); 363 364 bcopy(attr->manufacturer, hba_attr->Manufacturer, 365 sizeof (hba_attr->Manufacturer)); 366 bcopy(attr->serial_number, hba_attr->SerialNumber, 367 sizeof (hba_attr->SerialNumber)); 368 bcopy(attr->model, hba_attr->Model, sizeof (hba_attr->Model)); 369 bcopy(attr->model_description, hba_attr->ModelDescription, 370 sizeof (hba_attr->ModelDescription)); 371 if (iport->iport_port->port_sym_node_name) 372 bcopy(iport->iport_port->port_sym_node_name, 373 hba_attr->NodeSymbolicName, 374 strlen(iport->iport_port->port_sym_node_name)); 375 else 376 bcopy(utsname.nodename, hba_attr->NodeSymbolicName, 377 strlen(utsname.nodename)); 378 bcopy(attr->hardware_version, hba_attr->HardwareVersion, 379 sizeof (hba_attr->HardwareVersion)); 380 bcopy(attr->option_rom_version, hba_attr->OptionROMVersion, 381 sizeof (hba_attr->OptionROMVersion)); 382 bcopy(attr->firmware_version, hba_attr->FirmwareVersion, 383 sizeof (hba_attr->FirmwareVersion)); 384 hba_attr->VendorSpecificID = attr->vendor_specific_id; 385 bcopy(iport->iport_port->port_nwwn, hba_attr->NodeWWN, 386 sizeof (hba_attr->NodeWWN)); 387 388 bcopy(attr->driver_name, hba_attr->DriverName, 389 sizeof (hba_attr->DriverName)); 390 bcopy(attr->driver_version, hba_attr->DriverVersion, 391 sizeof (hba_attr->DriverVersion)); 392 393 394 /* hba_attr->NumberOfPorts = fct_count_fru_ports(iport); */ 395 hba_attr->NumberOfPorts = 1; 396 397 kmem_free(attr, sizeof (fct_port_attrs_t)); 398 return (0); 399 } 400 401 int 402 fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn, 403 fc_tgt_hba_port_attributes_t *port_attr, uint32_t *err_detail) 404 { 405 fct_i_local_port_t *iport = ilport; 406 fct_i_remote_port_t *irp = NULL; 407 fct_port_attrs_t *attr; 408 int i = 0; 409 410 port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION; 411 412 if (!ilport) { 413 iport = fct_get_iport_per_wwn(pwwn); 414 if (!iport) { 415 *err_detail = FCTIO_BADWWN; 416 return (ENXIO); 417 } 418 } 419 420 attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t), 421 KM_SLEEP); 422 mutex_exit(&fct_global_mutex); 423 iport->iport_port->port_populate_hba_details(iport->iport_port, attr); 424 mutex_enter(&fct_global_mutex); 425 426 port_attr->lastChange = iport->iport_last_change; 427 bcopy(iport->iport_port->port_nwwn, port_attr->NodeWWN, 428 sizeof (port_attr->NodeWWN)); 429 bcopy(iport->iport_port->port_pwwn, port_attr->PortWWN, 430 sizeof (port_attr->PortWWN)); 431 bzero(port_attr->FabricName, sizeof (port_attr->FabricName)); 432 port_attr->PortFcId = iport->iport_link_info.portid; 433 if ((iport->iport_link_state & S_LINK_ONLINE) || 434 (iport->iport_link_state & S_RCVD_LINK_UP)) { 435 port_attr->PortState = FC_HBA_PORTSTATE_ONLINE; 436 } else { 437 port_attr->PortState = FC_HBA_PORTSTATE_OFFLINE; 438 } 439 switch (iport->iport_link_info.port_topology) { 440 case PORT_TOPOLOGY_PT_TO_PT: 441 port_attr->PortType = FC_HBA_PORTTYPE_PTP; 442 break; 443 case PORT_TOPOLOGY_PRIVATE_LOOP: 444 port_attr->PortType = FC_HBA_PORTTYPE_LPORT; 445 break; 446 case PORT_TOPOLOGY_PUBLIC_LOOP: 447 port_attr->PortType = FC_HBA_PORTTYPE_NLPORT; 448 break; 449 case PORT_TOPOLOGY_FABRIC_PT_TO_PT: 450 port_attr->PortType = FC_HBA_PORTTYPE_FPORT; 451 break; 452 default: 453 port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN; 454 break; 455 } 456 port_attr->PortSupportedClassofService = attr->supported_cos; 457 port_attr->PortSupportedFc4Types[0] = 0; 458 port_attr->PortActiveFc4Types[2] = 1; 459 if (iport->iport_port->port_sym_port_name) 460 bcopy(iport->iport_port->port_sym_port_name, 461 port_attr->PortSymbolicName, 462 strlen(iport->iport_port->port_sym_port_name)); 463 else if (iport->iport_port->port_default_alias) 464 bcopy(iport->iport_port->port_default_alias, 465 port_attr->PortSymbolicName, 466 strlen(iport->iport_port->port_default_alias)); 467 else 468 port_attr->PortSymbolicName[0] = 0; 469 /* the definition is different so need to translate */ 470 if (attr->supported_speed & PORT_SPEED_1G) 471 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT; 472 if (attr->supported_speed & PORT_SPEED_2G) 473 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT; 474 if (attr->supported_speed & PORT_SPEED_4G) 475 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT; 476 if (attr->supported_speed & PORT_SPEED_8G) 477 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT; 478 if (attr->supported_speed & PORT_SPEED_10G) 479 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT; 480 switch (iport->iport_link_info.port_speed) { 481 case PORT_SPEED_1G: 482 port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT; 483 break; 484 case PORT_SPEED_2G: 485 port_attr->PortSpeed = FC_HBA_PORTSPEED_2GBIT; 486 break; 487 case PORT_SPEED_4G: 488 port_attr->PortSpeed = FC_HBA_PORTSPEED_4GBIT; 489 break; 490 case PORT_SPEED_8G: 491 port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT; 492 break; 493 case PORT_SPEED_10G: 494 port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT; 495 break; 496 default: 497 port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 498 break; 499 } 500 port_attr->PortMaxFrameSize = attr->max_frame_size; 501 rw_enter(&iport->iport_lock, RW_READER); 502 port_attr->NumberofDiscoveredPorts = iport->iport_nrps_login; 503 for (; i < iport->iport_port->port_max_logins; i++) { 504 irp = iport->iport_rp_slots[i]; 505 if (irp && irp->irp_flags & IRP_PLOGI_DONE) { 506 if (FC_WELL_KNOWN_ADDR(irp->irp_portid)) 507 port_attr->NumberofDiscoveredPorts --; 508 } 509 } 510 rw_exit(&iport->iport_lock); 511 512 kmem_free(attr, sizeof (fct_port_attrs_t)); 513 514 return (0); 515 } 516 517 int 518 fct_get_discovered_port_attr(fct_i_remote_port_t *remote_port, 519 uint8_t *port_wwn, uint32_t index, fc_tgt_hba_port_attributes_t *port_attr, 520 uint32_t *error_detail) 521 { 522 fct_i_local_port_t *iport; 523 fct_i_remote_port_t *irp = remote_port; 524 int count = 0, i = 0; 525 526 port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION; 527 if (!remote_port) { 528 iport = fct_get_iport_per_wwn(port_wwn); 529 if (!iport) { 530 *error_detail = FCTIO_BADWWN; 531 return (ENXIO); 532 } 533 534 rw_enter(&iport->iport_lock, RW_READER); 535 536 if (index >= iport->iport_nrps_login) { 537 rw_exit(&iport->iport_lock); 538 *error_detail = FCTIO_OUTOFBOUNDS; 539 return (EINVAL); 540 } 541 for (; i < iport->iport_port->port_max_logins; i++) { 542 irp = iport->iport_rp_slots[i]; 543 if (irp && irp->irp_flags & IRP_PLOGI_DONE && 544 !FC_WELL_KNOWN_ADDR(irp->irp_portid)) { 545 count ++; 546 if ((index + 1) <= count) 547 break; 548 } 549 } 550 if (i >= iport->iport_port->port_max_logins) { 551 rw_exit(&iport->iport_lock); 552 *error_detail = FCTIO_OUTOFBOUNDS; 553 return (EINVAL); 554 } 555 ASSERT(irp); 556 } else { 557 iport = (fct_i_local_port_t *) 558 irp->irp_rp->rp_port->port_fct_private; 559 } 560 port_attr->lastChange = iport->iport_last_change; 561 rw_enter(&irp->irp_lock, RW_READER); 562 bcopy(irp->irp_rp->rp_pwwn, port_attr->PortWWN, 563 sizeof (port_attr->PortWWN)); 564 bcopy(irp->irp_rp->rp_nwwn, port_attr->NodeWWN, 565 sizeof (port_attr->NodeWWN)); 566 port_attr->PortFcId = irp->irp_portid; 567 if (irp->irp_spn) 568 (void) strncpy(port_attr->PortSymbolicName, irp->irp_spn, 569 strlen(irp->irp_spn)); 570 else 571 port_attr->PortSymbolicName[0] = '\0'; 572 port_attr->PortSupportedClassofService = irp->irp_cos; 573 bcopy((caddr_t)irp->irp_fc4types, port_attr->PortActiveFc4Types, 574 sizeof (irp->irp_fc4types)); 575 bcopy((caddr_t)irp->irp_fc4types, port_attr->PortSupportedFc4Types, 576 sizeof (irp->irp_fc4types)); 577 if (irp->irp_flags & IRP_PLOGI_DONE) 578 port_attr->PortState = FC_HBA_PORTSTATE_ONLINE; 579 else 580 port_attr->PortState = FC_HBA_PORTSTATE_UNKNOWN; 581 582 port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN; 583 port_attr->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 584 port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 585 port_attr->PortMaxFrameSize = 0; 586 port_attr->NumberofDiscoveredPorts = 0; 587 rw_exit(&irp->irp_lock); 588 if (!remote_port) { 589 rw_exit(&iport->iport_lock); 590 } 591 return (0); 592 } 593 594 int 595 fct_get_port_attr(uint8_t *port_wwn, 596 fc_tgt_hba_port_attributes_t *port_attr, uint32_t *error_detail) 597 { 598 fct_i_local_port_t *iport; 599 fct_i_remote_port_t *irp; 600 int i, ret; 601 602 iport = fct_get_iport_per_wwn(port_wwn); 603 if (iport) { 604 return (fct_get_adapter_port_attr(iport, port_wwn, 605 port_attr, error_detail)); 606 } 607 /* else */ 608 for (iport = fct_iport_list; iport; iport = iport->iport_next) { 609 rw_enter(&iport->iport_lock, RW_READER); 610 for (i = 0; i < rportid_table_size; i++) { 611 irp = iport->iport_rp_tb[i]; 612 while (irp) { 613 if (bcmp(irp->irp_rp->rp_pwwn, 614 port_wwn, 8) == 0 && 615 irp->irp_flags & IRP_PLOGI_DONE) { 616 ret = fct_get_discovered_port_attr( 617 irp, NULL, 0, port_attr, 618 error_detail); 619 rw_exit(&iport->iport_lock); 620 return (ret); 621 } 622 irp = irp->irp_next; 623 } 624 } 625 rw_exit(&iport->iport_lock); 626 } 627 *error_detail = FCTIO_BADWWN; 628 return (ENXIO); 629 } 630 631 /* ARGSUSED */ 632 int 633 fct_get_port_stats(uint8_t *port_wwn, 634 fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail) 635 { 636 fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn); 637 638 if (!iport) 639 return (ENXIO); 640 port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION; 641 /* 642 * port_stats->SecondsSinceLastReset = ; 643 * port_stats->TxFrames = ; 644 * port_stats->TxWords = ; 645 * port_stats->RxFrames = ; 646 * port_stats->RxWords = ; 647 * port_stats->LIPCount = ; 648 * port_stats->NOSCount = ; 649 * port_stats->ErrorFrames = ; 650 * port_stats->DumpedFrames = ; 651 * port_stats->LinkFailureCount = ; 652 * port_stats->LossOfSyncCount = ; 653 * port_stats->LossOfSignalCount = ; 654 * port_stats->PrimitiveSeqProtocol = ; 655 * port_stats->InvalidTxWordCount = ; 656 * port_stats->InvalidCRCCount = ; 657 */ 658 return (0); 659 } 660 661 static int 662 fct_fctiocmd(intptr_t data, int mode) 663 { 664 int ret = 0; 665 void *ibuf = NULL; 666 void *obuf = NULL; 667 void *abuf = NULL; 668 fctio_t *fctio; 669 uint32_t attr_length; 670 671 ret = fct_copyin_iocdata(data, mode, &fctio, &ibuf, &abuf, &obuf); 672 if (ret) { 673 return (ret); 674 } 675 676 switch (fctio->fctio_cmd) { 677 case FCTIO_ADAPTER_LIST: { 678 fc_tgt_hba_list_t *list = (fc_tgt_hba_list_t *)obuf; 679 int count; 680 681 if (fctio->fctio_olen < sizeof (fc_tgt_hba_list_t)) { 682 ret = EINVAL; 683 break; 684 } 685 list->numPorts = (fctio->fctio_olen - 686 sizeof (fc_tgt_hba_list_t))/8 + 1; 687 688 list->version = FCT_HBA_LIST_VERSION; 689 count = fct_get_port_list((char *)list->port_wwn, 690 list->numPorts); 691 if (count < 0) { 692 ret = ENXIO; 693 break; 694 } 695 if (count > list->numPorts) { 696 fctio->fctio_errno = FCTIO_MOREDATA; 697 ret = ENOSPC; 698 } 699 list->numPorts = count; 700 break; 701 } 702 case FCTIO_GET_ADAPTER_ATTRIBUTES: { 703 fc_tgt_hba_adapter_attributes_t *hba_attr; 704 uint8_t *port_wwn = (uint8_t *)ibuf; 705 706 attr_length = sizeof (fc_tgt_hba_adapter_attributes_t); 707 if (fctio->fctio_olen < attr_length || 708 fctio->fctio_xfer != FCTIO_XFER_READ) { 709 ret = EINVAL; 710 break; 711 } 712 hba_attr = (fc_tgt_hba_adapter_attributes_t *)obuf; 713 714 mutex_enter(&fct_global_mutex); 715 ret = fct_get_adapter_attr(port_wwn, hba_attr, 716 &fctio->fctio_errno); 717 mutex_exit(&fct_global_mutex); 718 719 break; 720 } 721 case FCTIO_GET_ADAPTER_PORT_ATTRIBUTES: { 722 fc_tgt_hba_port_attributes_t *port_attr; 723 724 uint8_t *port_wwn = (uint8_t *)ibuf; 725 726 attr_length = sizeof (fc_tgt_hba_port_attributes_t); 727 if (fctio->fctio_olen < attr_length || 728 fctio->fctio_xfer != FCTIO_XFER_READ) { 729 ret = EINVAL; 730 break; 731 } 732 port_attr = (fc_tgt_hba_port_attributes_t *)obuf; 733 734 mutex_enter(&fct_global_mutex); 735 ret = fct_get_adapter_port_attr(NULL, port_wwn, port_attr, 736 &fctio->fctio_errno); 737 mutex_exit(&fct_global_mutex); 738 739 break; 740 } 741 case FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES: { 742 uint8_t *port_wwn = (uint8_t *)ibuf; 743 uint32_t *port_index = (uint32_t *)abuf; 744 fc_tgt_hba_port_attributes_t *port_attr; 745 746 attr_length = sizeof (fc_tgt_hba_port_attributes_t); 747 if (fctio->fctio_olen < attr_length || 748 fctio->fctio_xfer != FCTIO_XFER_READ) { 749 ret = EINVAL; 750 break; 751 } 752 port_attr = (fc_tgt_hba_port_attributes_t *)obuf; 753 754 mutex_enter(&fct_global_mutex); 755 ret = fct_get_discovered_port_attr(NULL, port_wwn, 756 *port_index, port_attr, &fctio->fctio_errno); 757 mutex_exit(&fct_global_mutex); 758 759 break; 760 } 761 case FCTIO_GET_PORT_ATTRIBUTES: { 762 uint8_t *port_wwn = (uint8_t *)ibuf; 763 fc_tgt_hba_port_attributes_t *port_attr; 764 765 attr_length = sizeof (fc_tgt_hba_port_attributes_t); 766 if (fctio->fctio_olen < attr_length || 767 fctio->fctio_xfer != FCTIO_XFER_READ) { 768 ret = EINVAL; 769 break; 770 } 771 772 port_attr = (fc_tgt_hba_port_attributes_t *)obuf; 773 774 mutex_enter(&fct_global_mutex); 775 ret = fct_get_port_attr(port_wwn, port_attr, 776 &fctio->fctio_errno); 777 mutex_exit(&fct_global_mutex); 778 779 break; 780 } 781 case FCTIO_GET_ADAPTER_PORT_STATS: { 782 uint8_t *port_wwn = (uint8_t *)ibuf; 783 fc_tgt_hba_adapter_port_stats_t *port_stats = 784 (fc_tgt_hba_adapter_port_stats_t *)obuf; 785 mutex_enter(&fct_global_mutex); 786 ret = fct_get_port_stats(port_wwn, port_stats, 787 &fctio->fctio_errno); 788 mutex_exit(&fct_global_mutex); 789 break; 790 } 791 default: 792 break; 793 } 794 if (ret == 0) { 795 ret = fct_copyout_iocdata(data, mode, fctio, obuf); 796 } else if (fctio->fctio_errno) { 797 (void) fct_copyout_iocdata(data, mode, fctio, obuf); 798 } 799 800 if (obuf) { 801 kmem_free(obuf, fctio->fctio_olen); 802 obuf = NULL; 803 } 804 if (abuf) { 805 kmem_free(abuf, fctio->fctio_alen); 806 abuf = NULL; 807 } 808 809 if (ibuf) { 810 kmem_free(ibuf, fctio->fctio_ilen); 811 ibuf = NULL; 812 } 813 kmem_free(fctio, sizeof (fctio_t)); 814 return (ret); 815 } 816 817 typedef struct { 818 void *bp; /* back pointer from internal struct to main struct */ 819 int alloc_size; 820 fct_struct_id_t struct_id; 821 } __ifct_t; 822 823 typedef struct { 824 __ifct_t *fp; /* Framework private */ 825 void *cp; /* Caller private */ 826 void *ss; /* struct specific */ 827 } __fct_t; 828 829 static struct { 830 int shared; 831 int fw_private; 832 int struct_specific; 833 } fct_sizes[] = { { 0, 0, 0 }, 834 { GET_STRUCT_SIZE(fct_local_port_t), 835 GET_STRUCT_SIZE(fct_i_local_port_t), 0 }, 836 { GET_STRUCT_SIZE(fct_remote_port_t), 837 GET_STRUCT_SIZE(fct_i_remote_port_t), 0 }, 838 { GET_STRUCT_SIZE(fct_cmd_t), 839 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) }, 840 { GET_STRUCT_SIZE(fct_cmd_t), 841 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) }, 842 { GET_STRUCT_SIZE(fct_cmd_t), 843 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_sol_ct_t) }, 844 { GET_STRUCT_SIZE(fct_cmd_t), GET_STRUCT_SIZE(fct_i_cmd_t), 845 GET_STRUCT_SIZE(fct_rcvd_abts_t) }, 846 { GET_STRUCT_SIZE(fct_cmd_t), /* FCT_STRUCT_CMD_FCP_XCHG */ 847 GET_STRUCT_SIZE(fct_i_cmd_t), 0 }, 848 { GET_STRUCT_SIZE(fct_dbuf_store_t), 849 GET_STRUCT_SIZE(__ifct_t), 0 } 850 }; 851 852 void * 853 fct_alloc(fct_struct_id_t struct_id, int additional_size, int flags) 854 { 855 int fct_size; 856 int kmem_flag; 857 __fct_t *sh; 858 859 if ((struct_id == 0) || (struct_id >= FCT_MAX_STRUCT_IDS)) 860 return (NULL); 861 862 if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) { 863 kmem_flag = KM_NOSLEEP; 864 } else { 865 kmem_flag = KM_SLEEP; 866 } 867 868 additional_size = (additional_size + 7) & (~7); 869 fct_size = fct_sizes[struct_id].shared + 870 fct_sizes[struct_id].fw_private + 871 fct_sizes[struct_id].struct_specific + additional_size; 872 873 if (struct_id == FCT_STRUCT_LOCAL_PORT) { 874 stmf_local_port_t *lport; 875 876 lport = (stmf_local_port_t *)stmf_alloc( 877 STMF_STRUCT_STMF_LOCAL_PORT, fct_size, flags); 878 if (lport) { 879 sh = (__fct_t *)lport->lport_port_private; 880 sh->ss = lport; 881 } else { 882 return (NULL); 883 } 884 } else if (struct_id == FCT_STRUCT_DBUF_STORE) { 885 stmf_dbuf_store_t *ds; 886 887 ds = (stmf_dbuf_store_t *)stmf_alloc(STMF_STRUCT_DBUF_STORE, 888 fct_size, flags); 889 if (ds) { 890 sh = (__fct_t *)ds->ds_port_private; 891 sh->ss = ds; 892 } else { 893 return (NULL); 894 } 895 } else { 896 sh = (__fct_t *)kmem_zalloc(fct_size, kmem_flag); 897 } 898 899 if (sh == NULL) 900 return (NULL); 901 902 sh->fp = (__ifct_t *)GET_BYTE_OFFSET(sh, fct_sizes[struct_id].shared); 903 sh->cp = GET_BYTE_OFFSET(sh->fp, fct_sizes[struct_id].fw_private); 904 if (fct_sizes[struct_id].struct_specific) 905 sh->ss = GET_BYTE_OFFSET(sh->cp, additional_size); 906 907 sh->fp->bp = sh; 908 sh->fp->alloc_size = fct_size; 909 sh->fp->struct_id = struct_id; 910 911 if (struct_id == FCT_STRUCT_CMD_FCP_XCHG) { 912 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_FCP_XCHG; 913 } else if (struct_id == FCT_STRUCT_CMD_RCVD_ELS) { 914 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ELS; 915 } else if (struct_id == FCT_STRUCT_CMD_SOL_ELS) { 916 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_ELS; 917 } else if (struct_id == FCT_STRUCT_CMD_RCVD_ABTS) { 918 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ABTS; 919 } else if (struct_id == FCT_STRUCT_CMD_SOL_CT) { 920 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_CT; 921 } 922 923 return (sh); 924 } 925 926 void 927 fct_free(void *ptr) 928 { 929 __fct_t *sh = (__fct_t *)ptr; 930 fct_struct_id_t struct_id = sh->fp->struct_id; 931 932 if (struct_id == FCT_STRUCT_CMD_SOL_CT) { 933 fct_sol_ct_t *ct = (fct_sol_ct_t *) 934 ((fct_cmd_t *)ptr)->cmd_specific; 935 936 if (ct->ct_req_alloc_size) { 937 kmem_free(ct->ct_req_payload, ct->ct_req_alloc_size); 938 } 939 if (ct->ct_resp_alloc_size) { 940 kmem_free(ct->ct_resp_payload, ct->ct_resp_alloc_size); 941 } 942 } else if ((struct_id == FCT_STRUCT_CMD_RCVD_ELS) || 943 (struct_id == FCT_STRUCT_CMD_SOL_ELS)) { 944 fct_els_t *els = (fct_els_t *) 945 ((fct_cmd_t *)ptr)->cmd_specific; 946 if (els->els_req_alloc_size) 947 kmem_free(els->els_req_payload, 948 els->els_req_alloc_size); 949 if (els->els_resp_alloc_size) 950 kmem_free(els->els_resp_payload, 951 els->els_resp_alloc_size); 952 } 953 954 if (struct_id == FCT_STRUCT_LOCAL_PORT) { 955 stmf_free(((fct_local_port_t *)ptr)->port_lport); 956 } else if (struct_id == FCT_STRUCT_DBUF_STORE) { 957 stmf_free(((fct_dbuf_store_t *)ptr)->fds_ds); 958 } else { 959 kmem_free(ptr, sh->fp->alloc_size); 960 } 961 } 962 963 stmf_data_buf_t * 964 fct_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 965 uint32_t flags) 966 { 967 fct_local_port_t *port = (fct_local_port_t *) 968 task->task_lport->lport_port_private; 969 970 return (port->port_fds->fds_alloc_data_buf(port, size, 971 pminsize, flags)); 972 } 973 974 void 975 fct_free_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf) 976 { 977 fct_dbuf_store_t *fds; 978 979 fds = (fct_dbuf_store_t *)ds->ds_port_private; 980 981 fds->fds_free_data_buf(fds, dbuf); 982 } 983 984 static uint32_t taskq_cntr = 0; 985 986 fct_status_t 987 fct_register_local_port(fct_local_port_t *port) 988 { 989 fct_i_local_port_t *iport; 990 stmf_local_port_t *lport; 991 fct_cmd_slot_t *slot; 992 int i; 993 char taskq_name[24]; 994 995 iport = (fct_i_local_port_t *)port->port_fct_private; 996 if (port->port_default_alias) { 997 int l = strlen(port->port_default_alias); 998 999 if (l < 16) { 1000 iport->iport_alias = iport->iport_alias_mem; 1001 } else { 1002 iport->iport_alias = 1003 (char *)kmem_zalloc(l+1, KM_SLEEP); 1004 } 1005 (void) strcpy(iport->iport_alias, port->port_default_alias); 1006 } else { 1007 iport->iport_alias = NULL; 1008 } 1009 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id, 1010 port->port_pwwn, PROTOCOL_FIBRE_CHANNEL); 1011 (void) snprintf(taskq_name, 24, "stmf_fct_taskq_%d", 1012 atomic_add_32_nv(&taskq_cntr, 1)); 1013 taskq_name[23] = 0; 1014 if ((iport->iport_worker_taskq = ddi_taskq_create(NULL, 1015 taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 1016 return (FCT_FAILURE); 1017 } 1018 mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL); 1019 cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL); 1020 rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL); 1021 1022 /* Remote port mgmt */ 1023 iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc( 1024 port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP); 1025 iport->iport_rp_tb = kmem_zalloc(rportid_table_size * 1026 sizeof (fct_i_remote_port_t *), KM_SLEEP); 1027 1028 /* fct_cmds for SCSI traffic */ 1029 iport->iport_total_alloced_ncmds = 0; 1030 iport->iport_cached_ncmds = 0; 1031 port->port_fca_fcp_cmd_size = 1032 (port->port_fca_fcp_cmd_size + 7) & ~7; 1033 iport->iport_cached_cmdlist = NULL; 1034 mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL); 1035 1036 /* Initialize cmd slots */ 1037 iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc( 1038 port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP); 1039 iport->iport_next_free_slot = 0; 1040 for (i = 0; i < port->port_max_xchges; ) { 1041 slot = &iport->iport_cmd_slots[i]; 1042 slot->slot_no = (uint16_t)i; 1043 slot->slot_next = (uint16_t)(++i); 1044 } 1045 slot->slot_next = FCT_SLOT_EOL; 1046 iport->iport_nslots_free = port->port_max_xchges; 1047 1048 iport->iport_task_green_limit = 1049 (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100; 1050 iport->iport_task_yellow_limit = 1051 (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100; 1052 iport->iport_task_red_limit = 1053 (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100; 1054 1055 /* Start worker thread */ 1056 atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER); 1057 (void) ddi_taskq_dispatch(iport->iport_worker_taskq, 1058 fct_port_worker, port, DDI_SLEEP); 1059 /* Wait for taskq to start */ 1060 while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) { 1061 delay(1); 1062 } 1063 1064 lport = port->port_lport; 1065 lport->lport_id = (scsi_devid_desc_t *)iport->iport_id; 1066 lport->lport_alias = iport->iport_alias; 1067 lport->lport_pp = port->port_pp; 1068 port->port_fds->fds_ds->ds_alloc_data_buf = fct_alloc_dbuf; 1069 port->port_fds->fds_ds->ds_free_data_buf = fct_free_dbuf; 1070 lport->lport_ds = port->port_fds->fds_ds; 1071 lport->lport_xfer_data = fct_xfer_scsi_data; 1072 lport->lport_send_status = fct_send_scsi_status; 1073 lport->lport_task_free = fct_scsi_task_free; 1074 lport->lport_abort = fct_scsi_abort; 1075 lport->lport_ctl = fct_ctl; 1076 lport->lport_info = fct_info; 1077 lport->lport_event_handler = fct_event_handler; 1078 if (stmf_register_local_port(port->port_lport) != FCT_SUCCESS) { 1079 goto fct_regport_fail1; 1080 } 1081 (void) stmf_lport_add_event(lport, LPORT_EVENT_INITIAL_LUN_MAPPED); 1082 1083 mutex_enter(&fct_global_mutex); 1084 iport->iport_next = fct_iport_list; 1085 iport->iport_prev = NULL; 1086 if (iport->iport_next) 1087 iport->iport_next->iport_prev = iport; 1088 fct_iport_list = iport; 1089 mutex_exit(&fct_global_mutex); 1090 1091 fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH); 1092 1093 return (FCT_SUCCESS); 1094 1095 fct_regport_fail1:; 1096 /* Stop the taskq 1st */ 1097 if (iport->iport_flags & IPORT_WORKER_RUNNING) { 1098 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER); 1099 cv_broadcast(&iport->iport_worker_cv); 1100 while (iport->iport_flags & IPORT_WORKER_RUNNING) { 1101 delay(1); 1102 } 1103 } 1104 ddi_taskq_destroy(iport->iport_worker_taskq); 1105 if (iport->iport_rp_tb) { 1106 kmem_free(iport->iport_rp_tb, rportid_table_size * 1107 sizeof (fct_i_remote_port_t *)); 1108 } 1109 return (FCT_FAILURE); 1110 } 1111 1112 fct_status_t 1113 fct_deregister_local_port(fct_local_port_t *port) 1114 { 1115 fct_i_local_port_t *iport; 1116 fct_i_cmd_t *icmd, *next_icmd; 1117 int ndx; 1118 1119 iport = (fct_i_local_port_t *)port->port_fct_private; 1120 1121 if ((iport->iport_state != FCT_STATE_OFFLINE) || 1122 iport->iport_state_not_acked) { 1123 return (FCT_FAILURE); 1124 } 1125 1126 /* Stop the taskq 1st */ 1127 if (iport->iport_flags & IPORT_WORKER_RUNNING) { 1128 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER); 1129 cv_broadcast(&iport->iport_worker_cv); 1130 for (ndx = 0; ndx < 100; ndx++) { 1131 if ((iport->iport_flags & IPORT_WORKER_RUNNING) 1132 == 0) { 1133 break; 1134 } 1135 delay(drv_usectohz(10000)); 1136 } 1137 if (ndx == 100) { 1138 atomic_and_32(&iport->iport_flags, 1139 ~IPORT_TERMINATE_WORKER); 1140 return (FCT_WORKER_STUCK); 1141 } 1142 } 1143 1144 if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) { 1145 goto fct_deregport_fail1; 1146 } 1147 1148 mutex_enter(&fct_global_mutex); 1149 if (iport->iport_next) 1150 iport->iport_next->iport_prev = iport->iport_prev; 1151 if (iport->iport_prev) 1152 iport->iport_prev->iport_next = iport->iport_next; 1153 else 1154 fct_iport_list = iport->iport_next; 1155 mutex_exit(&fct_global_mutex); 1156 /* 1157 * At this time, there should be no outstanding and pending 1158 * I/Os, so we can just release resources. 1159 */ 1160 ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds); 1161 for (icmd = iport->iport_cached_cmdlist; icmd; icmd = next_icmd) { 1162 next_icmd = icmd->icmd_next; 1163 fct_free(icmd->icmd_cmd); 1164 } 1165 mutex_destroy(&iport->iport_cached_cmd_lock); 1166 kmem_free(iport->iport_cmd_slots, port->port_max_xchges * 1167 sizeof (fct_cmd_slot_t)); 1168 kmem_free(iport->iport_rp_slots, port->port_max_logins * 1169 sizeof (fct_i_remote_port_t *)); 1170 rw_destroy(&iport->iport_lock); 1171 cv_destroy(&iport->iport_worker_cv); 1172 mutex_destroy(&iport->iport_worker_lock); 1173 ddi_taskq_destroy(iport->iport_worker_taskq); 1174 if (iport->iport_rp_tb) { 1175 kmem_free(iport->iport_rp_tb, rportid_table_size * 1176 sizeof (fct_i_remote_port_t *)); 1177 } 1178 1179 fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH); 1180 return (FCT_SUCCESS); 1181 1182 fct_deregport_fail1:; 1183 /* Restart the worker */ 1184 atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER); 1185 (void) ddi_taskq_dispatch(iport->iport_worker_taskq, 1186 fct_port_worker, port, DDI_SLEEP); 1187 /* Wait for taskq to start */ 1188 while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) { 1189 delay(1); 1190 } 1191 return (FCT_FAILURE); 1192 } 1193 1194 /* ARGSUSED */ 1195 void 1196 fct_handle_event(fct_local_port_t *port, int event_id, uint32_t event_flags, 1197 caddr_t arg) 1198 { 1199 char info[80]; 1200 fct_i_event_t *e; 1201 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1202 port->port_fct_private; 1203 1204 e = kmem_zalloc(sizeof (fct_i_event_t), KM_NOSLEEP); 1205 1206 if (e == NULL) { 1207 /* 1208 * XXX Throw HBA fatal error event 1209 */ 1210 (void) snprintf(info, 80, 1211 "fct_handle_event: iport-%p, allocation " 1212 "of fct_i_event failed", (void *)iport); 1213 info[79] = 0; 1214 (void) fct_port_shutdown(iport->iport_port, 1215 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1216 return; 1217 } 1218 /* Just queue the event */ 1219 e->event_type = event_id; 1220 mutex_enter(&iport->iport_worker_lock); 1221 if (iport->iport_event_head == NULL) { 1222 iport->iport_event_head = iport->iport_event_tail = e; 1223 } else { 1224 iport->iport_event_tail->event_next = e; 1225 iport->iport_event_tail = e; 1226 } 1227 if (IS_WORKER_SLEEPING(iport)) 1228 cv_signal(&iport->iport_worker_cv); 1229 mutex_exit(&iport->iport_worker_lock); 1230 } 1231 1232 /* 1233 * Called with iport_lock held as reader. 1234 */ 1235 fct_i_remote_port_t * 1236 fct_portid_to_portptr(fct_i_local_port_t *iport, uint32_t portid) 1237 { 1238 fct_i_remote_port_t *irp; 1239 1240 irp = iport->iport_rp_tb[FCT_PORTID_HASH_FUNC(portid)]; 1241 for (; irp != NULL; irp = irp->irp_next) { 1242 if (irp->irp_portid == portid) 1243 return (irp); 1244 } 1245 1246 return (NULL); 1247 1248 } 1249 1250 /* 1251 * Called with irp_lock held as writer. 1252 */ 1253 void 1254 fct_queue_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp) 1255 { 1256 int hash_key = 1257 FCT_PORTID_HASH_FUNC(irp->irp_portid); 1258 1259 irp->irp_next = iport->iport_rp_tb[hash_key]; 1260 iport->iport_rp_tb[hash_key] = irp; 1261 iport->iport_nrps++; 1262 } 1263 1264 /* 1265 * Called with irp_lock and iport_lock held as writer. 1266 */ 1267 void 1268 fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp) 1269 { 1270 fct_i_remote_port_t *irp_next = NULL; 1271 fct_i_remote_port_t *irp_last = NULL; 1272 int hash_key = 1273 FCT_PORTID_HASH_FUNC(irp->irp_portid); 1274 1275 irp_next = iport->iport_rp_tb[hash_key]; 1276 irp_last = NULL; 1277 while (irp_next != NULL) { 1278 if (irp == irp_next) { 1279 break; 1280 } 1281 irp_last = irp_next; 1282 irp_next = irp_next->irp_next; 1283 } 1284 1285 if (irp_next) { 1286 if (irp_last == NULL) { 1287 iport->iport_rp_tb[hash_key] = 1288 irp->irp_next; 1289 } else { 1290 irp_last->irp_next = irp->irp_next; 1291 } 1292 irp->irp_next = NULL; 1293 iport->iport_nrps--; 1294 } 1295 } 1296 1297 int 1298 fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit) 1299 { 1300 int logging_out = 0; 1301 1302 rw_enter(&irp->irp_lock, RW_WRITER); 1303 if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) { 1304 logging_out = 0; 1305 goto ilo_done; 1306 } 1307 if ((irp->irp_els_list == NULL) && (irp->irp_deregister_timer)) { 1308 if (force_implicit && irp->irp_nonfcp_xchg_count) { 1309 logging_out = 0; 1310 } else { 1311 logging_out = 1; 1312 } 1313 goto ilo_done; 1314 } 1315 if (irp->irp_els_list) { 1316 fct_i_cmd_t *icmd; 1317 /* Last session affecting ELS should be a LOGO */ 1318 for (icmd = irp->irp_els_list; icmd; icmd = icmd->icmd_next) { 1319 uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0]; 1320 if (op == ELS_OP_LOGO) { 1321 if (force_implicit) { 1322 if (icmd->icmd_flags & ICMD_IMPLICIT) 1323 logging_out = 1; 1324 else 1325 logging_out = 0; 1326 } else { 1327 logging_out = 1; 1328 } 1329 } else if ((op == ELS_OP_PLOGI) || 1330 (op == ELS_OP_PRLI) || 1331 (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) { 1332 logging_out = 0; 1333 } 1334 } 1335 } 1336 ilo_done:; 1337 rw_exit(&irp->irp_lock); 1338 1339 return (logging_out); 1340 } 1341 1342 /* 1343 * The force_implicit flag enforces the implicit semantics which may be 1344 * needed if a received logout got stuck e.g. a response to a received 1345 * LOGO never came back from the FCA. 1346 */ 1347 int 1348 fct_implicitly_logo_all(fct_i_local_port_t *iport, int force_implicit) 1349 { 1350 fct_i_remote_port_t *irp = NULL; 1351 fct_cmd_t *cmd = NULL; 1352 int i = 0; 1353 int nports = 0; 1354 1355 if (!iport->iport_nrps) { 1356 return (nports); 1357 } 1358 1359 rw_enter(&iport->iport_lock, RW_WRITER); 1360 for (i = 0; i < rportid_table_size; i++) { 1361 irp = iport->iport_rp_tb[i]; 1362 while (irp) { 1363 if ((!(irp->irp_flags & IRP_PLOGI_DONE)) && 1364 (fct_is_irp_logging_out(irp, force_implicit))) { 1365 irp = irp->irp_next; 1366 continue; 1367 } 1368 1369 cmd = fct_create_solels(iport->iport_port, irp->irp_rp, 1370 1, ELS_OP_LOGO, 0, fct_logo_cb); 1371 if (cmd == NULL) { 1372 stmf_trace(iport->iport_alias, 1373 "fct_implictly_logo_all: cmd null"); 1374 rw_exit(&iport->iport_lock); 1375 1376 return (nports); 1377 } 1378 1379 fct_post_implicit_logo(cmd); 1380 nports++; 1381 irp = irp->irp_next; 1382 } 1383 } 1384 rw_exit(&iport->iport_lock); 1385 1386 return (nports); 1387 } 1388 1389 void 1390 fct_rehash(fct_i_local_port_t *iport) 1391 { 1392 fct_i_remote_port_t **iport_rp_tb_tmp; 1393 fct_i_remote_port_t **iport_rp_tb_new; 1394 fct_i_remote_port_t *irp; 1395 fct_i_remote_port_t *irp_next; 1396 int i; 1397 1398 iport_rp_tb_new = kmem_zalloc(rportid_table_size * 1399 sizeof (fct_i_remote_port_t *), KM_SLEEP); 1400 rw_enter(&iport->iport_lock, RW_WRITER); 1401 /* reconstruct the hash table */ 1402 iport_rp_tb_tmp = iport->iport_rp_tb; 1403 iport->iport_rp_tb = iport_rp_tb_new; 1404 iport->iport_nrps = 0; 1405 for (i = 0; i < rportid_table_size; i++) { 1406 irp = iport_rp_tb_tmp[i]; 1407 while (irp) { 1408 irp_next = irp->irp_next; 1409 fct_queue_rp(iport, irp); 1410 irp = irp_next; 1411 } 1412 } 1413 rw_exit(&iport->iport_lock); 1414 kmem_free(iport_rp_tb_tmp, rportid_table_size * 1415 sizeof (fct_i_remote_port_t *)); 1416 1417 } 1418 1419 uint8_t 1420 fct_local_port_cleanup_done(fct_i_local_port_t *iport) 1421 { 1422 fct_i_remote_port_t *irp; 1423 int i; 1424 1425 if (iport->iport_nrps_login) 1426 return (0); 1427 /* loop all rps to check if the cmd have already been drained */ 1428 for (i = 0; i < rportid_table_size; i++) { 1429 irp = iport->iport_rp_tb[i]; 1430 while (irp) { 1431 if (irp->irp_fcp_xchg_count || 1432 irp->irp_nonfcp_xchg_count) 1433 return (0); 1434 irp = irp->irp_next; 1435 } 1436 } 1437 return (1); 1438 } 1439 1440 fct_cmd_t * 1441 fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle, 1442 uint32_t rportid, uint8_t *lun, uint16_t cdb_length, 1443 uint16_t task_ext) 1444 { 1445 fct_cmd_t *cmd; 1446 fct_i_cmd_t *icmd; 1447 fct_i_local_port_t *iport = 1448 (fct_i_local_port_t *)port->port_fct_private; 1449 fct_i_remote_port_t *irp; 1450 scsi_task_t *task; 1451 fct_remote_port_t *rp; 1452 uint16_t cmd_slot; 1453 1454 rw_enter(&iport->iport_lock, RW_READER); 1455 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) { 1456 rw_exit(&iport->iport_lock); 1457 stmf_trace(iport->iport_alias, "cmd alloc called while the port" 1458 " was offline"); 1459 return (NULL); 1460 } 1461 1462 if (rp_handle == FCT_HANDLE_NONE) { 1463 irp = fct_portid_to_portptr(iport, rportid); 1464 if (irp == NULL) { 1465 rw_exit(&iport->iport_lock); 1466 stmf_trace(iport->iport_alias, "cmd received from " 1467 "non existent port %x", rportid); 1468 return (NULL); 1469 } 1470 } else { 1471 if ((rp_handle >= port->port_max_logins) || 1472 ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) { 1473 rw_exit(&iport->iport_lock); 1474 stmf_trace(iport->iport_alias, "cmd received from " 1475 "invalid port handle %x", rp_handle); 1476 return (NULL); 1477 } 1478 } 1479 rp = irp->irp_rp; 1480 1481 rw_enter(&irp->irp_lock, RW_READER); 1482 if ((irp->irp_flags & IRP_PRLI_DONE) == 0) { 1483 rw_exit(&irp->irp_lock); 1484 rw_exit(&iport->iport_lock); 1485 stmf_trace(iport->iport_alias, "cmd alloc called while fcp " 1486 "login was not done. portid=%x, rp=%p", rp->rp_id, rp); 1487 return (NULL); 1488 } 1489 1490 mutex_enter(&iport->iport_cached_cmd_lock); 1491 if ((icmd = iport->iport_cached_cmdlist) != NULL) { 1492 iport->iport_cached_cmdlist = icmd->icmd_next; 1493 iport->iport_cached_ncmds--; 1494 cmd = icmd->icmd_cmd; 1495 } else { 1496 icmd = NULL; 1497 } 1498 mutex_exit(&iport->iport_cached_cmd_lock); 1499 if (icmd == NULL) { 1500 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG, 1501 port->port_fca_fcp_cmd_size, 0); 1502 if (cmd == NULL) { 1503 rw_exit(&irp->irp_lock); 1504 rw_exit(&iport->iport_lock); 1505 stmf_trace(iport->iport_alias, "Ran out of " 1506 "memory, port=%p", port); 1507 return (NULL); 1508 } 1509 1510 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1511 icmd->icmd_next = NULL; 1512 cmd->cmd_port = port; 1513 atomic_add_32(&iport->iport_total_alloced_ncmds, 1); 1514 } 1515 1516 /* 1517 * The accuracy of iport_max_active_ncmds is not important 1518 */ 1519 if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) > 1520 iport->iport_max_active_ncmds) { 1521 iport->iport_max_active_ncmds = 1522 iport->iport_total_alloced_ncmds - 1523 iport->iport_cached_ncmds; 1524 } 1525 1526 /* Lets get a slot */ 1527 cmd_slot = fct_alloc_cmd_slot(iport, cmd); 1528 if (cmd_slot == FCT_SLOT_EOL) { 1529 rw_exit(&irp->irp_lock); 1530 rw_exit(&iport->iport_lock); 1531 stmf_trace(iport->iport_alias, "Ran out of xchg resources"); 1532 cmd->cmd_handle = 0; 1533 fct_cmd_free(cmd); 1534 return (NULL); 1535 } 1536 atomic_add_16(&irp->irp_fcp_xchg_count, 1); 1537 cmd->cmd_rp = rp; 1538 icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA; 1539 rw_exit(&irp->irp_lock); 1540 rw_exit(&iport->iport_lock); 1541 1542 icmd->icmd_start_time = ddi_get_lbolt(); 1543 1544 cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session, 1545 lun, cdb_length, task_ext); 1546 if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) { 1547 task->task_port_private = cmd; 1548 return (cmd); 1549 } 1550 1551 fct_cmd_free(cmd); 1552 1553 return (NULL); 1554 } 1555 1556 void 1557 fct_scsi_task_free(scsi_task_t *task) 1558 { 1559 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private; 1560 1561 cmd->cmd_comp_status = task->task_completion_status; 1562 fct_cmd_free(cmd); 1563 } 1564 1565 void 1566 fct_post_rcvd_cmd(fct_cmd_t *cmd, stmf_data_buf_t *dbuf) 1567 { 1568 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 1569 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1570 fct_i_local_port_t *iport = 1571 (fct_i_local_port_t *)cmd->cmd_port->port_fct_private; 1572 fct_i_remote_port_t *irp = 1573 (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private; 1574 scsi_task_t *task = (scsi_task_t *)cmd->cmd_specific; 1575 1576 uint16_t irp_task = irp->irp_fcp_xchg_count; 1577 uint32_t load = iport->iport_total_alloced_ncmds - 1578 iport->iport_cached_ncmds; 1579 1580 DTRACE_FC_4(scsi__command, 1581 fct_cmd_t, cmd, 1582 fct_i_local_port_t, iport, 1583 scsi_task_t, task, 1584 fct_i_remote_port_t, irp); 1585 1586 if (load >= iport->iport_task_green_limit) { 1587 if ((load < iport->iport_task_yellow_limit && 1588 irp_task >= 4) || 1589 (load >= iport->iport_task_yellow_limit && 1590 load < iport->iport_task_red_limit && 1591 irp_task >= 1) || 1592 (load >= iport->iport_task_red_limit)) 1593 task->task_additional_flags |= 1594 TASK_AF_PORT_LOAD_HIGH; 1595 } 1596 stmf_post_task((scsi_task_t *)cmd->cmd_specific, dbuf); 1597 atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_TRANSITION); 1598 return; 1599 } 1600 /* We dont need dbuf for other cmds */ 1601 if (dbuf) { 1602 cmd->cmd_port->port_fds->fds_free_data_buf( 1603 cmd->cmd_port->port_fds, dbuf); 1604 dbuf = NULL; 1605 } 1606 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1607 fct_handle_els(cmd); 1608 return; 1609 } 1610 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) { 1611 fct_handle_rcvd_abts(cmd); 1612 return; 1613 } 1614 1615 ASSERT(0); 1616 } 1617 1618 /* 1619 * This function bypasses fct_handle_els() 1620 */ 1621 void 1622 fct_post_implicit_logo(fct_cmd_t *cmd) 1623 { 1624 fct_local_port_t *port = cmd->cmd_port; 1625 fct_i_local_port_t *iport = 1626 (fct_i_local_port_t *)port->port_fct_private; 1627 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1628 fct_remote_port_t *rp = cmd->cmd_rp; 1629 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private; 1630 1631 icmd->icmd_start_time = ddi_get_lbolt(); 1632 1633 rw_enter(&irp->irp_lock, RW_WRITER); 1634 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE); 1635 atomic_add_16(&irp->irp_nonfcp_xchg_count, 1); 1636 atomic_add_16(&irp->irp_sa_elses_count, 1); 1637 /* 1638 * An implicit LOGO can also be posted to a irp where a PLOGI might 1639 * be in process. That PLOGI will reset this flag and decrement the 1640 * iport_nrps_login counter. 1641 */ 1642 if (irp->irp_flags & IRP_PLOGI_DONE) { 1643 atomic_add_32(&iport->iport_nrps_login, -1); 1644 } 1645 atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE)); 1646 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING); 1647 fct_post_to_discovery_queue(iport, irp, icmd); 1648 rw_exit(&irp->irp_lock); 1649 } 1650 1651 /* 1652 * called with iport_lock held, return the slot number 1653 */ 1654 uint16_t 1655 fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd) 1656 { 1657 uint16_t cmd_slot; 1658 uint32_t old, new; 1659 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1660 1661 do { 1662 old = iport->iport_next_free_slot; 1663 cmd_slot = old & 0xFFFF; 1664 if (cmd_slot == FCT_SLOT_EOL) 1665 return (cmd_slot); 1666 /* 1667 * We use high order 16 bits as a counter which keeps on 1668 * incrementing to avoid ABA issues with atomic lists. 1669 */ 1670 new = ((old + (0x10000)) & 0xFFFF0000); 1671 new |= iport->iport_cmd_slots[cmd_slot].slot_next; 1672 } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old); 1673 1674 atomic_add_16(&iport->iport_nslots_free, -1); 1675 iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd; 1676 cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 | 1677 (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr)) 1678 << 24); 1679 return (cmd_slot); 1680 } 1681 1682 /* 1683 * If icmd is not NULL, irp_lock must be held 1684 */ 1685 void 1686 fct_post_to_discovery_queue(fct_i_local_port_t *iport, 1687 fct_i_remote_port_t *irp, fct_i_cmd_t *icmd) 1688 { 1689 fct_i_cmd_t **p; 1690 1691 ASSERT(!MUTEX_HELD(&iport->iport_worker_lock)); 1692 if (icmd) { 1693 icmd->icmd_next = NULL; 1694 for (p = &irp->irp_els_list; *p != NULL; 1695 p = &((*p)->icmd_next)) 1696 ; 1697 1698 *p = icmd; 1699 atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE); 1700 } 1701 1702 mutex_enter(&iport->iport_worker_lock); 1703 if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) { 1704 1705 /* 1706 * CAUTION: do not grab local_port/remote_port locks after 1707 * grabbing the worker lock. 1708 */ 1709 irp->irp_discovery_next = NULL; 1710 if (iport->iport_rpwe_tail) { 1711 iport->iport_rpwe_tail->irp_discovery_next = irp; 1712 iport->iport_rpwe_tail = irp; 1713 } else { 1714 iport->iport_rpwe_head = iport->iport_rpwe_tail = irp; 1715 } 1716 1717 atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE); 1718 } 1719 1720 /* 1721 * We need always signal the port worker irrespective of the fact that 1722 * irp is already in discovery queue or not. 1723 */ 1724 if (IS_WORKER_SLEEPING(iport)) { 1725 cv_signal(&iport->iport_worker_cv); 1726 } 1727 mutex_exit(&iport->iport_worker_lock); 1728 } 1729 1730 stmf_status_t 1731 fct_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) 1732 { 1733 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private; 1734 1735 DTRACE_FC_5(xfer__start, 1736 fct_cmd_t, cmd, 1737 fct_i_local_port_t, cmd->cmd_port->port_fct_private, 1738 scsi_task_t, task, 1739 fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private, 1740 stmf_data_buf_t, dbuf); 1741 1742 return (cmd->cmd_port->port_xfer_scsi_data(cmd, dbuf, ioflags)); 1743 } 1744 1745 void 1746 fct_scsi_data_xfer_done(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags) 1747 { 1748 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1749 uint32_t old, new; 1750 uint32_t iof = 0; 1751 1752 DTRACE_FC_5(xfer__done, 1753 fct_cmd_t, cmd, 1754 fct_i_local_port_t, cmd->cmd_port->port_fct_private, 1755 scsi_task_t, ((scsi_task_t *)cmd->cmd_specific), 1756 fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private, 1757 stmf_data_buf_t, dbuf); 1758 1759 if (ioflags & FCT_IOF_FCA_DONE) { 1760 do { 1761 old = new = icmd->icmd_flags; 1762 if (old & ICMD_BEING_ABORTED) { 1763 return; 1764 } 1765 new &= ~ICMD_KNOWN_TO_FCA; 1766 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 1767 iof = STMF_IOF_LPORT_DONE; 1768 cmd->cmd_comp_status = dbuf->db_xfer_status; 1769 } 1770 1771 if (icmd->icmd_flags & ICMD_BEING_ABORTED) 1772 return; 1773 stmf_data_xfer_done((scsi_task_t *)cmd->cmd_specific, dbuf, iof); 1774 } 1775 1776 stmf_status_t 1777 fct_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 1778 { 1779 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private; 1780 1781 DTRACE_FC_4(scsi__response, 1782 fct_cmd_t, cmd, 1783 fct_i_local_port_t, 1784 (fct_i_local_port_t *)cmd->cmd_port->port_fct_private, 1785 scsi_task_t, task, 1786 fct_i_remote_port_t, 1787 (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private); 1788 1789 return (cmd->cmd_port->port_send_cmd_response(cmd, ioflags)); 1790 } 1791 1792 void 1793 fct_send_response_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags) 1794 { 1795 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1796 fct_local_port_t *port = cmd->cmd_port; 1797 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1798 port->port_fct_private; 1799 uint32_t old, new; 1800 1801 if ((ioflags & FCT_IOF_FCA_DONE) == 0) { 1802 /* Until we support confirmed completions, this is an error */ 1803 fct_queue_cmd_for_termination(cmd, s); 1804 return; 1805 } 1806 do { 1807 old = new = icmd->icmd_flags; 1808 if (old & ICMD_BEING_ABORTED) { 1809 return; 1810 } 1811 new &= ~ICMD_KNOWN_TO_FCA; 1812 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 1813 1814 cmd->cmd_comp_status = s; 1815 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 1816 stmf_send_status_done((scsi_task_t *)cmd->cmd_specific, s, 1817 STMF_IOF_LPORT_DONE); 1818 return; 1819 } 1820 1821 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1822 fct_cmd_free(cmd); 1823 return; 1824 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) { 1825 fct_handle_sol_els_completion(iport, icmd); 1826 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { 1827 /* Tell the caller that we are done */ 1828 atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE); 1829 } else { 1830 ASSERT(0); 1831 } 1832 } 1833 1834 void 1835 fct_cmd_free(fct_cmd_t *cmd) 1836 { 1837 char info[80]; 1838 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1839 fct_local_port_t *port = cmd->cmd_port; 1840 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1841 port->port_fct_private; 1842 fct_i_remote_port_t *irp = NULL; 1843 int do_abts_acc = 0; 1844 uint32_t old, new; 1845 1846 ASSERT(!mutex_owned(&iport->iport_worker_lock)); 1847 /* Give the slot back */ 1848 if (CMD_HANDLE_VALID(cmd->cmd_handle)) { 1849 uint16_t n = CMD_HANDLE_SLOT_INDEX(cmd->cmd_handle); 1850 fct_cmd_slot_t *slot; 1851 1852 /* 1853 * If anything went wrong, grab the lock as writer. This is 1854 * probably unnecessary. 1855 */ 1856 if ((cmd->cmd_comp_status != FCT_SUCCESS) || 1857 (icmd->icmd_flags & ICMD_ABTS_RECEIVED)) { 1858 rw_enter(&iport->iport_lock, RW_WRITER); 1859 } else { 1860 rw_enter(&iport->iport_lock, RW_READER); 1861 } 1862 1863 if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) && 1864 (cmd->cmd_link != NULL)) { 1865 do_abts_acc = 1; 1866 } 1867 1868 /* XXX Validate slot before freeing */ 1869 1870 slot = &iport->iport_cmd_slots[n]; 1871 slot->slot_uniq_cntr++; 1872 slot->slot_cmd = NULL; 1873 do { 1874 old = iport->iport_next_free_slot; 1875 slot->slot_next = old & 0xFFFF; 1876 new = (old + 0x10000) & 0xFFFF0000; 1877 new |= slot->slot_no; 1878 } while (atomic_cas_32(&iport->iport_next_free_slot, 1879 old, new) != old); 1880 cmd->cmd_handle = 0; 1881 atomic_add_16(&iport->iport_nslots_free, 1); 1882 if (cmd->cmd_rp) { 1883 irp = (fct_i_remote_port_t *) 1884 cmd->cmd_rp->rp_fct_private; 1885 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) 1886 atomic_add_16(&irp->irp_fcp_xchg_count, -1); 1887 else 1888 atomic_add_16(&irp->irp_nonfcp_xchg_count, -1); 1889 } 1890 rw_exit(&iport->iport_lock); 1891 } else if ((icmd->icmd_flags & ICMD_IMPLICIT) && 1892 (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) { 1893 /* for implicit cmd, no cmd slot is used */ 1894 if (cmd->cmd_rp) { 1895 irp = (fct_i_remote_port_t *) 1896 cmd->cmd_rp->rp_fct_private; 1897 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) 1898 atomic_add_16(&irp->irp_fcp_xchg_count, -1); 1899 else 1900 atomic_add_16(&irp->irp_nonfcp_xchg_count, -1); 1901 } 1902 } 1903 1904 if (do_abts_acc) { 1905 fct_cmd_t *lcmd = cmd->cmd_link; 1906 fct_fill_abts_acc(lcmd); 1907 if (port->port_send_cmd_response(lcmd, 1908 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) { 1909 /* 1910 * XXX Throw HBA fatal error event 1911 * Later shutdown svc will terminate the ABTS in the end 1912 */ 1913 (void) snprintf(info, 80, 1914 "fct_cmd_free: iport-%p, ABTS_ACC" 1915 " port_send_cmd_response failed", (void *)iport); 1916 info[79] = 0; 1917 (void) fct_port_shutdown(iport->iport_port, 1918 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1919 return; 1920 } else { 1921 fct_cmd_free(lcmd); 1922 cmd->cmd_link = NULL; 1923 } 1924 } 1925 1926 /* Free the cmd */ 1927 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 1928 if (iport->iport_cached_ncmds < max_cached_ncmds) { 1929 icmd->icmd_flags = 0; 1930 mutex_enter(&iport->iport_cached_cmd_lock); 1931 icmd->icmd_next = iport->iport_cached_cmdlist; 1932 iport->iport_cached_cmdlist = icmd; 1933 iport->iport_cached_ncmds++; 1934 mutex_exit(&iport->iport_cached_cmd_lock); 1935 } else { 1936 atomic_add_32(&iport->iport_total_alloced_ncmds, -1); 1937 fct_free(cmd); 1938 } 1939 } else { 1940 fct_free(cmd); 1941 } 1942 } 1943 1944 /* ARGSUSED */ 1945 stmf_status_t 1946 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg, 1947 uint32_t flags) 1948 { 1949 stmf_status_t ret = STMF_SUCCESS; 1950 scsi_task_t *task; 1951 fct_cmd_t *cmd; 1952 fct_i_cmd_t *icmd; 1953 fct_local_port_t *port; 1954 uint32_t old, new; 1955 1956 ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK); 1957 1958 task = (scsi_task_t *)arg; 1959 cmd = (fct_cmd_t *)task->task_port_private; 1960 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 1961 port = (fct_local_port_t *)lport->lport_port_private; 1962 1963 do { 1964 old = new = icmd->icmd_flags; 1965 if ((old & ICMD_KNOWN_TO_FCA) == 0) 1966 return (STMF_NOT_FOUND); 1967 ASSERT((old & ICMD_FCA_ABORT_CALLED) == 0); 1968 new |= ICMD_BEING_ABORTED | ICMD_FCA_ABORT_CALLED; 1969 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 1970 ret = port->port_abort_cmd(port, cmd, 0); 1971 if ((ret == FCT_NOT_FOUND) || (ret == FCT_ABORT_SUCCESS)) { 1972 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 1973 } else if (ret == FCT_BUSY) { 1974 atomic_and_32(&icmd->icmd_flags, ~ICMD_FCA_ABORT_CALLED); 1975 } 1976 1977 return (ret); 1978 } 1979 1980 void 1981 fct_ctl(struct stmf_local_port *lport, int cmd, void *arg) 1982 { 1983 fct_local_port_t *port; 1984 fct_i_local_port_t *iport; 1985 stmf_change_status_t st; 1986 stmf_change_status_t *pst; 1987 1988 ASSERT((cmd == STMF_CMD_LPORT_ONLINE) || 1989 (cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) || 1990 (cmd == STMF_CMD_LPORT_OFFLINE) || 1991 (cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE) || 1992 (cmd == FCT_CMD_PORT_ONLINE_COMPLETE) || 1993 (cmd == FCT_CMD_PORT_OFFLINE_COMPLETE)); 1994 1995 port = (fct_local_port_t *)lport->lport_port_private; 1996 pst = (stmf_change_status_t *)arg; 1997 st.st_completion_status = STMF_SUCCESS; 1998 st.st_additional_info = NULL; 1999 2000 iport = (fct_i_local_port_t *)port->port_fct_private; 2001 /* 2002 * We are mostly a passthrough, except during offline. 2003 */ 2004 switch (cmd) { 2005 case STMF_CMD_LPORT_ONLINE: 2006 if (iport->iport_state == FCT_STATE_ONLINE) 2007 st.st_completion_status = STMF_ALREADY; 2008 else if (iport->iport_state != FCT_STATE_OFFLINE) 2009 st.st_completion_status = STMF_INVALID_ARG; 2010 if (st.st_completion_status != STMF_SUCCESS) { 2011 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, 2012 &st); 2013 break; 2014 } 2015 iport->iport_state_not_acked = 1; 2016 iport->iport_state = FCT_STATE_ONLINING; 2017 port->port_ctl(port, FCT_CMD_PORT_ONLINE, arg); 2018 break; 2019 case FCT_CMD_PORT_ONLINE_COMPLETE: 2020 ASSERT(iport->iport_state == FCT_STATE_ONLINING); 2021 if (pst->st_completion_status != FCT_SUCCESS) { 2022 iport->iport_state = FCT_STATE_OFFLINE; 2023 iport->iport_state_not_acked = 0; 2024 } else { 2025 iport->iport_state = FCT_STATE_ONLINE; 2026 } 2027 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, arg); 2028 break; 2029 case STMF_ACK_LPORT_ONLINE_COMPLETE: 2030 ASSERT(iport->iport_state == FCT_STATE_ONLINE); 2031 iport->iport_state_not_acked = 0; 2032 port->port_ctl(port, FCT_ACK_PORT_ONLINE_COMPLETE, arg); 2033 break; 2034 2035 case STMF_CMD_LPORT_OFFLINE: 2036 if (iport->iport_state == FCT_STATE_OFFLINE) 2037 st.st_completion_status = STMF_ALREADY; 2038 else if (iport->iport_state != FCT_STATE_ONLINE) 2039 st.st_completion_status = STMF_INVALID_ARG; 2040 if (st.st_completion_status != STMF_SUCCESS) { 2041 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport, 2042 &st); 2043 break; 2044 } 2045 iport->iport_state_not_acked = 1; 2046 iport->iport_state = FCT_STATE_OFFLINING; 2047 port->port_ctl(port, FCT_CMD_PORT_OFFLINE, arg); 2048 break; 2049 case FCT_CMD_PORT_OFFLINE_COMPLETE: 2050 ASSERT(iport->iport_state == FCT_STATE_OFFLINING); 2051 if (pst->st_completion_status != FCT_SUCCESS) { 2052 iport->iport_state = FCT_STATE_ONLINE; 2053 iport->iport_state_not_acked = 0; 2054 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport, 2055 pst); 2056 break; 2057 } 2058 2059 /* 2060 * If FCA's offline was successful, we dont tell stmf yet. 2061 * Becasue now we have to do the cleanup before we go upto 2062 * stmf. That cleanup is done by the worker thread. 2063 */ 2064 2065 /* FCA is offline, post a link down, its harmless anyway */ 2066 fct_handle_event(port, FCT_EVENT_LINK_DOWN, 0, 0); 2067 2068 /* Trigger port offline processing by the worker */ 2069 iport->iport_offline_prstate = FCT_OPR_START; 2070 break; 2071 case STMF_ACK_LPORT_OFFLINE_COMPLETE: 2072 ASSERT(iport->iport_state == FCT_STATE_OFFLINE); 2073 iport->iport_state_not_acked = 0; 2074 port->port_ctl(port, FCT_ACK_PORT_OFFLINE_COMPLETE, arg); 2075 break; 2076 } 2077 } 2078 2079 /* ARGSUSED */ 2080 stmf_status_t 2081 fct_info(uint32_t cmd, stmf_local_port_t *lport, void *arg, uint8_t *buf, 2082 uint32_t *bufsizep) 2083 { 2084 return (STMF_NOT_SUPPORTED); 2085 } 2086 2087 /* 2088 * implicit: if it's true, it means it will only be used in fct module, or else 2089 * it will be sent to the link. 2090 */ 2091 fct_cmd_t * 2092 fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp, int implicit, 2093 uchar_t elsop, uint32_t wkdid, fct_icmd_cb_t icmdcb) 2094 { 2095 fct_cmd_t *cmd = NULL; 2096 fct_i_cmd_t *icmd = NULL; 2097 fct_els_t *els = NULL; 2098 fct_i_remote_port_t *irp = NULL; 2099 uint8_t *p = NULL; 2100 uint32_t ptid = 0; 2101 2102 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS, 2103 port->port_fca_sol_els_private_size, 0); 2104 if (!cmd) { 2105 return (NULL); 2106 } 2107 2108 if (rp) { 2109 irp = RP_TO_IRP(rp); 2110 } else if (((irp = fct_portid_to_portptr(PORT_TO_IPORT(port), 2111 wkdid)) == NULL) && (elsop != ELS_OP_PLOGI)) { 2112 stmf_trace(PORT_TO_IPORT(port)->iport_alias, 2113 "fct_create_solels: Must PLOGI to %x first", wkdid); 2114 fct_free(cmd); 2115 return (NULL); 2116 } 2117 2118 cmd->cmd_port = port; 2119 cmd->cmd_oxid = PTR2INT(cmd, uint16_t); 2120 cmd->cmd_rxid = 0xFFFF; 2121 cmd->cmd_handle = 0; 2122 icmd = CMD_TO_ICMD(cmd); 2123 els = ICMD_TO_ELS(icmd); 2124 icmd->icmd_cb = icmdcb; 2125 if (irp) { 2126 cmd->cmd_rp = irp->irp_rp; 2127 cmd->cmd_rp_handle = irp->irp_rp->rp_handle; 2128 cmd->cmd_rportid = irp->irp_rp->rp_id; 2129 } else { 2130 cmd->cmd_rp_handle = FCT_HANDLE_NONE; 2131 cmd->cmd_rportid = wkdid; 2132 } 2133 cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid; 2134 2135 if (implicit) { 2136 /* 2137 * Since we will not send it to FCA, so we only allocate space 2138 */ 2139 ASSERT(elsop & (ELS_OP_LOGO | ELS_OP_PLOGI)); 2140 icmd->icmd_flags |= ICMD_IMPLICIT; 2141 if (elsop == ELS_OP_LOGO) { 2142 /* 2143 * Handling implicit LOGO should dependent on as less 2144 * as resources. So a trick here. 2145 */ 2146 els->els_req_size = 1; 2147 els->els_req_payload = cmd->cmd_fca_private; 2148 } else { 2149 els->els_req_alloc_size = els->els_req_size = 116; 2150 els->els_resp_alloc_size = els->els_resp_size = 116; 2151 els->els_req_payload = (uint8_t *) 2152 kmem_zalloc(els->els_req_size, KM_SLEEP); 2153 els->els_resp_payload = (uint8_t *) 2154 kmem_zalloc(els->els_resp_size, KM_SLEEP); 2155 } 2156 } else { 2157 /* 2158 * Allocate space for its request and response 2159 * Fill the request payload according to spec. 2160 */ 2161 switch (elsop) { 2162 case ELS_OP_LOGO: 2163 els->els_resp_alloc_size = els->els_resp_size = 4; 2164 els->els_resp_payload = (uint8_t *)kmem_zalloc( 2165 els->els_resp_size, KM_SLEEP); 2166 els->els_req_alloc_size = els->els_req_size = 16; 2167 els->els_req_payload = (uint8_t *)kmem_zalloc( 2168 els->els_req_size, KM_SLEEP); 2169 ptid = PORT_TO_IPORT(port)->iport_link_info.portid; 2170 fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3); 2171 bcopy(port->port_pwwn, els->els_req_payload + 8, 8); 2172 break; 2173 2174 case ELS_OP_RSCN: 2175 els->els_resp_alloc_size = els->els_resp_size = 4; 2176 els->els_resp_payload = (uint8_t *)kmem_zalloc( 2177 els->els_resp_size, KM_SLEEP); 2178 els->els_req_size = els->els_req_alloc_size = 8; 2179 els->els_req_payload = (uint8_t *)kmem_zalloc( 2180 els->els_req_size, KM_SLEEP); 2181 els->els_req_payload[1] = 0x04; 2182 els->els_req_payload[3] = 0x08; 2183 els->els_req_payload[4] |= 0x80; 2184 ptid = PORT_TO_IPORT(port)->iport_link_info.portid; 2185 fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3); 2186 break; 2187 2188 case ELS_OP_PLOGI: 2189 els->els_resp_alloc_size = els->els_resp_size = 116; 2190 els->els_resp_payload = (uint8_t *) 2191 kmem_zalloc(els->els_resp_size, KM_SLEEP); 2192 els->els_req_alloc_size = els->els_req_size = 116; 2193 p = els->els_req_payload = (uint8_t *) 2194 kmem_zalloc(els->els_req_size, KM_SLEEP); 2195 bcopy(port->port_pwwn, p + 20, 8); 2196 bcopy(port->port_nwwn, p + 28, 8); 2197 2198 /* 2199 * Common service parameters 2200 */ 2201 p[0x04] = 0x09; /* high version */ 2202 p[0x05] = 0x08; /* low version */ 2203 p[0x06] = 0x00; /* BB credit: 0x0065 */ 2204 p[0x07] = 0x65; 2205 2206 /* CI0: Continuously Increasing Offset - 1 */ 2207 /* RRO: Randomly Relative Offset - 0 */ 2208 /* VVV: Vendor Version Level - 0 */ 2209 /* N-F: N or F Port Payload Sender - 0 (N) */ 2210 /* BBM: BB Credit Management - 0 (Normal) */ 2211 p[0x08] = 0x80; 2212 p[0x09] = 0x00; 2213 2214 /* Max RX size */ 2215 p[0x0A] = 0x08; 2216 p[0x0B] = 0x00; 2217 2218 /* NPTCS: N Port Total Concurrent Sequences - 0x0000 */ 2219 p[0x0C] = 0x00; 2220 p[0x0D] = 0x00; 2221 2222 /* ROIC: Relative Offset By Info - 0xFFFF */ 2223 p[0x0E] = 0xFF; 2224 p[0x0F] = 0xFF; 2225 2226 /* EDTOV: Error Detect Timeout - 0x000007D0 */ 2227 p[0x10] = 0x00; 2228 p[0x11] = 0x00; 2229 p[0x12] = 0x07; 2230 p[0x13] = 0xD0; 2231 2232 /* 2233 * Class-3 Parameters 2234 */ 2235 /* C3-VAL: Class 3 Value - 1 */ 2236 /* C3-XID: X_ID Reassignment - 0 */ 2237 /* C3-IPA: Initial Process Assignment */ 2238 /* C3-AI-DCC: Data compression capable */ 2239 /* C3-AI-DC-HB: Data compression history buffer size */ 2240 /* C3-AI-DCE: Data encrytion capable */ 2241 /* C3-AI-CSC: Clock synchronization capable */ 2242 /* C3-ErrPol: Error pliciy */ 2243 /* C3-CatSeq: Information Cat. Per Sequence */ 2244 /* C3-AR-DCC: */ 2245 /* C3-AR-DC-HB: */ 2246 /* C3-AR-DCE: */ 2247 /* C3-AR-CSC */ 2248 p[0x44] = 0x80; 2249 p[0x45] = 0x00; 2250 p[0x46] = 0x00; 2251 p[0x47] = 0x00; 2252 p[0x48] = 0x00; 2253 p[0x49] = 0x00; 2254 2255 /* C3-RxSize: Class 3 receive data size */ 2256 p[0x4A] = 0x08; 2257 p[0x4B] = 0x00; 2258 2259 /* C3-ConSeq: Class 3 Concourrent sequences */ 2260 p[0x4C] = 0x00; 2261 p[0x4D] = 0xFF; 2262 2263 /* C3-OSPE: Class 3 open sequence per exchange */ 2264 p[0x50] = 0x00; 2265 p[0x51] = 0x01; 2266 2267 break; 2268 2269 case ELS_OP_SCR: 2270 els->els_resp_alloc_size = els->els_resp_size = 4; 2271 els->els_resp_payload = (uint8_t *) 2272 kmem_zalloc(els->els_resp_size, KM_SLEEP); 2273 els->els_req_alloc_size = els->els_req_size = 8; 2274 p = els->els_req_payload = (uint8_t *) 2275 kmem_zalloc(els->els_req_size, KM_SLEEP); 2276 p[7] = FC_SCR_FULL_REGISTRATION; 2277 break; 2278 2279 default: 2280 ASSERT(0); 2281 } 2282 } 2283 2284 els->els_req_payload[0] = elsop; 2285 return (cmd); 2286 } 2287 2288 fct_cmd_t * 2289 fct_create_solct(fct_local_port_t *port, fct_remote_port_t *query_rp, 2290 uint16_t ctop, fct_icmd_cb_t icmdcb) 2291 { 2292 fct_cmd_t *cmd = NULL; 2293 fct_i_cmd_t *icmd = NULL; 2294 fct_sol_ct_t *ct = NULL; 2295 uint8_t *p = NULL; 2296 fct_i_remote_port_t *irp = NULL; 2297 fct_i_local_port_t *iport = NULL; 2298 char *nname = NULL; 2299 int namelen = 0; 2300 2301 /* 2302 * Allocate space 2303 */ 2304 cmd = fct_alloc(FCT_STRUCT_CMD_SOL_CT, 2305 port->port_fca_sol_ct_private_size, 0); 2306 if (!cmd) { 2307 return (NULL); 2308 } 2309 2310 /* 2311 * We should have PLOGIed to the name server (0xFFFFFC) 2312 * Caution: this irp is not query_rp->rp_fct_private. 2313 */ 2314 irp = fct_portid_to_portptr((fct_i_local_port_t *) 2315 port->port_fct_private, FS_NAME_SERVER); 2316 if (irp == NULL) { 2317 stmf_trace(PORT_TO_IPORT(port)->iport_alias, 2318 "fct_create_solct: Must PLOGI name server first"); 2319 fct_free(cmd); 2320 return (NULL); 2321 } 2322 2323 cmd->cmd_port = port; 2324 cmd->cmd_rp = irp->irp_rp; 2325 cmd->cmd_rp_handle = irp->irp_rp->rp_handle; 2326 cmd->cmd_rportid = irp->irp_rp->rp_id; 2327 cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid; 2328 cmd->cmd_oxid = PTR2INT(cmd, uint16_t); 2329 cmd->cmd_rxid = 0xFFFF; 2330 cmd->cmd_handle = 0; 2331 icmd = CMD_TO_ICMD(cmd); 2332 ct = ICMD_TO_CT(icmd); 2333 icmd->icmd_cb = icmdcb; 2334 iport = ICMD_TO_IPORT(icmd); 2335 2336 switch (ctop) { 2337 case NS_GSNN_NN: 2338 /* 2339 * Allocate max space for its sybolic name 2340 */ 2341 ct->ct_resp_alloc_size = ct->ct_resp_size = 272; 2342 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2343 KM_SLEEP); 2344 2345 ct->ct_req_size = ct->ct_req_alloc_size = 24; 2346 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2347 KM_SLEEP); 2348 2349 bcopy(query_rp->rp_nwwn, p + 16, 8); 2350 break; 2351 2352 case NS_RNN_ID: 2353 ct->ct_resp_alloc_size = ct->ct_resp_size = 16; 2354 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2355 KM_SLEEP); 2356 ct->ct_req_size = ct->ct_req_alloc_size = 28; 2357 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2358 KM_SLEEP); 2359 2360 /* 2361 * Port Identifier 2362 */ 2363 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF; 2364 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF; 2365 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF; 2366 2367 /* 2368 * Node Name 2369 */ 2370 bcopy(port->port_nwwn, p + 20, 8); 2371 break; 2372 2373 case NS_RCS_ID: 2374 ct->ct_resp_alloc_size = ct->ct_resp_size = 16; 2375 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2376 KM_SLEEP); 2377 ct->ct_req_size = ct->ct_req_alloc_size = 24; 2378 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2379 KM_SLEEP); 2380 2381 /* 2382 * Port Identifier 2383 */ 2384 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF; 2385 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF; 2386 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF; 2387 2388 /* 2389 * Class of Service 2390 */ 2391 *(p + 23) = FC_NS_CLASS3; 2392 break; 2393 2394 case NS_RFT_ID: 2395 ct->ct_resp_alloc_size = ct->ct_resp_size = 16; 2396 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2397 KM_SLEEP); 2398 ct->ct_req_size = ct->ct_req_alloc_size = 52; 2399 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2400 KM_SLEEP); 2401 2402 /* 2403 * Port Identifier 2404 */ 2405 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF; 2406 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF; 2407 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF; 2408 2409 /* 2410 * FC-4 Protocol Types 2411 */ 2412 *(p + 22) = 0x1; /* 0x100 */ 2413 break; 2414 2415 case NS_RSPN_ID: 2416 /* 2417 * If we get here, port->port_sym_port_name is always not NULL. 2418 */ 2419 ASSERT(port->port_sym_port_name); 2420 namelen = strlen(port->port_sym_port_name); 2421 ct->ct_resp_alloc_size = ct->ct_resp_size = 16; 2422 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2423 KM_SLEEP); 2424 ct->ct_req_size = ct->ct_req_alloc_size = 2425 (21 + namelen + 3) & ~3; 2426 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2427 KM_SLEEP); 2428 2429 /* 2430 * Port Identifier 2431 */ 2432 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF; 2433 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF; 2434 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF; 2435 2436 /* 2437 * String length 2438 */ 2439 p[20] = namelen; 2440 2441 /* 2442 * Symbolic port name 2443 */ 2444 bcopy(port->port_sym_port_name, p + 21, ct->ct_req_size - 21); 2445 break; 2446 2447 case NS_RSNN_NN: 2448 namelen = port->port_sym_node_name == NULL ? 2449 strlen(utsname.nodename) : 2450 strlen(port->port_sym_node_name); 2451 nname = port->port_sym_node_name == NULL ? 2452 utsname.nodename : port->port_sym_node_name; 2453 2454 ct->ct_resp_alloc_size = ct->ct_resp_size = 16; 2455 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2456 KM_SLEEP); 2457 ct->ct_req_size = ct->ct_req_alloc_size = 2458 (25 + namelen + 3) & ~3; 2459 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2460 KM_SLEEP); 2461 2462 /* 2463 * Node name 2464 */ 2465 bcopy(port->port_nwwn, p + 16, 8); 2466 2467 /* 2468 * String length 2469 */ 2470 p[24] = namelen; 2471 2472 /* 2473 * Symbolic node name 2474 */ 2475 bcopy(nname, p + 25, ct->ct_req_size - 25); 2476 break; 2477 2478 case NS_GSPN_ID: 2479 ct->ct_resp_alloc_size = ct->ct_resp_size = 272; 2480 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2481 KM_SLEEP); 2482 ct->ct_req_size = ct->ct_req_alloc_size = 20; 2483 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2484 KM_SLEEP); 2485 /* 2486 * Port Identifier 2487 */ 2488 p[17] = (query_rp->rp_id >> 16) & 0xFF; 2489 p[18] = (query_rp->rp_id >> 8) & 0xFF; 2490 p[19] = (query_rp->rp_id >> 0) & 0xFF; 2491 break; 2492 2493 case NS_GCS_ID: 2494 ct->ct_resp_alloc_size = ct->ct_resp_size = 20; 2495 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2496 KM_SLEEP); 2497 ct->ct_req_size = ct->ct_req_alloc_size = 20; 2498 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2499 KM_SLEEP); 2500 /* 2501 * Port Identifier 2502 */ 2503 p[17] = (query_rp->rp_id >> 16) & 0xFF; 2504 p[18] = (query_rp->rp_id >> 8) & 0xFF; 2505 p[19] = (query_rp->rp_id >> 0) & 0xFF; 2506 break; 2507 2508 case NS_GFT_ID: 2509 ct->ct_resp_alloc_size = ct->ct_resp_size = 48; 2510 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2511 KM_SLEEP); 2512 ct->ct_req_size = ct->ct_req_alloc_size = 20; 2513 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2514 KM_SLEEP); 2515 /* 2516 * Port Identifier 2517 */ 2518 p[17] = (query_rp->rp_id >> 16) & 0xFF; 2519 p[18] = (query_rp->rp_id >> 8) & 0xFF; 2520 p[19] = (query_rp->rp_id >> 0) & 0xFF; 2521 break; 2522 2523 case NS_GID_PN: 2524 ct->ct_resp_alloc_size = ct->ct_resp_size = 20; 2525 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size, 2526 KM_SLEEP); 2527 2528 ct->ct_req_size = ct->ct_req_alloc_size = 24; 2529 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size, 2530 KM_SLEEP); 2531 2532 bcopy(query_rp->rp_pwwn, p + 16, 8); 2533 break; 2534 2535 default: 2536 /* CONSTCOND */ 2537 ASSERT(0); 2538 } 2539 2540 FCT_FILL_CTIU_PREAMPLE(p, ctop); 2541 return (cmd); 2542 } 2543 2544 /* 2545 * Cmd can only be solicited CT/ELS. They will be dispatched to the discovery 2546 * queue eventually too. 2547 * We queue solicited cmds here to track solicited cmds and to take full use 2548 * of single thread mechanism. 2549 * But in current implmentation, we don't use this mechanism on SOL_CT, PLOGI. 2550 * To avoid to interrupt current flow, ICMD_IN_SOLCMD_QUEUE is used here. 2551 */ 2552 void 2553 fct_post_to_solcmd_queue(fct_local_port_t *port, fct_cmd_t *cmd) 2554 { 2555 fct_i_local_port_t *iport = (fct_i_local_port_t *) 2556 port->port_fct_private; 2557 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 2558 2559 mutex_enter(&iport->iport_worker_lock); 2560 icmd->icmd_solcmd_next = iport->iport_solcmd_queue; 2561 iport->iport_solcmd_queue = icmd; 2562 atomic_or_32(&icmd->icmd_flags, ICMD_IN_SOLCMD_QUEUE | ICMD_SOLCMD_NEW); 2563 if (IS_WORKER_SLEEPING(iport)) { 2564 cv_signal(&iport->iport_worker_cv); 2565 } 2566 mutex_exit(&iport->iport_worker_lock); 2567 } 2568 2569 /* ARGSUSED */ 2570 void 2571 fct_event_handler(stmf_local_port_t *lport, int eventid, void *arg, 2572 uint32_t flags) 2573 { 2574 fct_local_port_t *port = (fct_local_port_t *) 2575 lport->lport_port_private; 2576 fct_i_local_port_t *iport = (fct_i_local_port_t *) 2577 port->port_fct_private; 2578 stmf_scsi_session_t *ss; 2579 fct_i_remote_port_t *irp; 2580 2581 switch (eventid) { 2582 case LPORT_EVENT_INITIAL_LUN_MAPPED: 2583 ss = (stmf_scsi_session_t *)arg; 2584 irp = (fct_i_remote_port_t *)ss->ss_port_private; 2585 stmf_trace(iport->iport_alias, 2586 "Initial LUN mapped to session ss-%p, irp-%p", ss, irp); 2587 break; 2588 2589 default: 2590 stmf_trace(iport->iport_alias, 2591 "Unknown event received, %d", eventid); 2592 } 2593 } 2594 2595 void 2596 fct_send_cmd_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags) 2597 { 2598 /* XXX For now just call send_resp_done() */ 2599 fct_send_response_done(cmd, s, ioflags); 2600 } 2601 2602 void 2603 fct_cmd_fca_aborted(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags) 2604 { 2605 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 2606 char info[160]; 2607 unsigned long long st; 2608 2609 st = s; /* To make gcc happy */ 2610 ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED); 2611 if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) || 2612 ((ioflags & FCT_IOF_FCA_DONE) == 0)) { 2613 (void) snprintf(info, 160, "fct_cmd_fca_aborted: cmd-%p, " 2614 "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags); 2615 info[159] = 0; 2616 (void) fct_port_shutdown(cmd->cmd_port, 2617 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 2618 return; 2619 } 2620 2621 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 2622 /* For non FCP Rest of the work is done by the terminator */ 2623 /* For FCP stuff just call stmf */ 2624 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 2625 stmf_task_lport_aborted((scsi_task_t *)cmd->cmd_specific, 2626 s, STMF_IOF_LPORT_DONE); 2627 } 2628 } 2629 2630 /* 2631 * FCA drivers will use it, when they want to abort some FC transactions 2632 * due to lack of resource. 2633 */ 2634 uint16_t 2635 fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid) 2636 { 2637 fct_i_remote_port_t *irp; 2638 2639 irp = fct_portid_to_portptr( 2640 (fct_i_local_port_t *)(port->port_fct_private), rportid); 2641 if (irp == NULL) { 2642 return (0xFFFF); 2643 } else { 2644 return (irp->irp_rp->rp_handle); 2645 } 2646 } 2647 2648 fct_cmd_t * 2649 fct_handle_to_cmd(fct_local_port_t *port, uint32_t fct_handle) 2650 { 2651 fct_cmd_slot_t *slot; 2652 uint16_t ndx; 2653 2654 if (!CMD_HANDLE_VALID(fct_handle)) 2655 return (NULL); 2656 if ((ndx = CMD_HANDLE_SLOT_INDEX(fct_handle)) >= port->port_max_xchges) 2657 return (NULL); 2658 2659 slot = &((fct_i_local_port_t *)port->port_fct_private)->iport_cmd_slots[ 2660 ndx]; 2661 2662 if ((slot->slot_uniq_cntr | 0x80) != (fct_handle >> 24)) 2663 return (NULL); 2664 return (slot->slot_cmd->icmd_cmd); 2665 } 2666 2667 void 2668 fct_queue_scsi_task_for_termination(fct_cmd_t *cmd, fct_status_t s) 2669 { 2670 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 2671 2672 uint32_t old, new; 2673 2674 do { 2675 old = icmd->icmd_flags; 2676 if ((old & (ICMD_BEING_ABORTED | ICMD_KNOWN_TO_FCA)) != 2677 ICMD_KNOWN_TO_FCA) 2678 return; 2679 new = old | ICMD_BEING_ABORTED; 2680 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 2681 stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific, 2682 s, NULL); 2683 } 2684 2685 void 2686 fct_fill_abts_acc(fct_cmd_t *cmd) 2687 { 2688 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; 2689 uint8_t *p; 2690 2691 abts->abts_resp_rctl = BLS_OP_BA_ACC; 2692 p = abts->abts_resp_payload; 2693 bzero(p, 12); 2694 *((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid); 2695 *((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid); 2696 p[10] = p[11] = 0xff; 2697 } 2698 2699 void 2700 fct_handle_rcvd_abts(fct_cmd_t *cmd) 2701 { 2702 char info[80]; 2703 fct_local_port_t *port = cmd->cmd_port; 2704 fct_i_local_port_t *iport = 2705 (fct_i_local_port_t *)port->port_fct_private; 2706 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 2707 fct_i_remote_port_t *irp; 2708 fct_cmd_t *c = NULL; 2709 fct_i_cmd_t *ic = NULL; 2710 int found = 0; 2711 int i; 2712 2713 icmd->icmd_start_time = ddi_get_lbolt(); 2714 icmd->icmd_flags |= ICMD_KNOWN_TO_FCA; 2715 2716 rw_enter(&iport->iport_lock, RW_WRITER); 2717 /* Make sure local port is sane */ 2718 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) { 2719 rw_exit(&iport->iport_lock); 2720 stmf_trace(iport->iport_alias, "ABTS not posted becasue" 2721 "port state was %x", iport->iport_link_state); 2722 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE); 2723 return; 2724 } 2725 2726 if (cmd->cmd_rp_handle == FCT_HANDLE_NONE) 2727 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid); 2728 else if (cmd->cmd_rp_handle < port->port_max_logins) 2729 irp = iport->iport_rp_slots[cmd->cmd_rp_handle]; 2730 else 2731 irp = NULL; 2732 if (irp == NULL) { 2733 /* XXX Throw a logout to the initiator */ 2734 rw_exit(&iport->iport_lock); 2735 stmf_trace(iport->iport_alias, "ABTS received from" 2736 " %x without a session", cmd->cmd_rportid); 2737 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN); 2738 return; 2739 } 2740 cmd->cmd_rp = irp->irp_rp; 2741 2742 /* 2743 * No need to allocate an xchg resource. ABTSes use the same 2744 * xchg resource as the cmd they are aborting. 2745 */ 2746 rw_enter(&irp->irp_lock, RW_WRITER); 2747 mutex_enter(&iport->iport_worker_lock); 2748 /* Lets find the command first */ 2749 for (i = 0; i < port->port_max_xchges; i++) { 2750 if ((ic = iport->iport_cmd_slots[i].slot_cmd) == NULL) 2751 continue; 2752 if ((ic->icmd_flags & ICMD_KNOWN_TO_FCA) == 0) 2753 continue; 2754 c = ic->icmd_cmd; 2755 if (!CMD_HANDLE_VALID(c->cmd_handle)) 2756 continue; 2757 if ((c->cmd_rportid != cmd->cmd_rportid) || 2758 (c->cmd_oxid != cmd->cmd_oxid)) 2759 continue; 2760 /* Found the command */ 2761 found = 1; 2762 break; 2763 } 2764 if (!found) { 2765 mutex_exit(&iport->iport_worker_lock); 2766 rw_exit(&irp->irp_lock); 2767 rw_exit(&iport->iport_lock); 2768 /* Dont even bother queueing it. Just respond */ 2769 fct_fill_abts_acc(cmd); 2770 if (port->port_send_cmd_response(cmd, 2771 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) { 2772 /* 2773 * XXX Throw HBA fatal error event 2774 * Later shutdown svc will terminate the ABTS in the end 2775 */ 2776 (void) snprintf(info, 80, 2777 "fct_handle_rcvd_abts: iport-%p, " 2778 "ABTS_ACC port_send_cmd_response failed", 2779 (void *)iport); 2780 info[79] = 0; 2781 (void) fct_port_shutdown(iport->iport_port, 2782 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 2783 } else { 2784 fct_cmd_free(cmd); 2785 } 2786 return; 2787 } 2788 2789 /* Check if this an abts retry */ 2790 if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) { 2791 /* Kill this abts. */ 2792 fct_q_for_termination_lock_held(iport, icmd, FCT_ABORTED); 2793 if (IS_WORKER_SLEEPING(iport)) 2794 cv_signal(&iport->iport_worker_cv); 2795 mutex_exit(&iport->iport_worker_lock); 2796 rw_exit(&irp->irp_lock); 2797 rw_exit(&iport->iport_lock); 2798 return; 2799 } 2800 c->cmd_link = cmd; 2801 atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED); 2802 cmd->cmd_link = c; 2803 mutex_exit(&iport->iport_worker_lock); 2804 rw_exit(&irp->irp_lock); 2805 fct_queue_cmd_for_termination(c, FCT_ABTS_RECEIVED); 2806 rw_exit(&iport->iport_lock); 2807 } 2808 2809 void 2810 fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s) 2811 { 2812 fct_local_port_t *port = cmd->cmd_port; 2813 fct_i_local_port_t *iport = (fct_i_local_port_t *) 2814 port->port_fct_private; 2815 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 2816 2817 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 2818 fct_queue_scsi_task_for_termination(cmd, s); 2819 return; 2820 } 2821 mutex_enter(&iport->iport_worker_lock); 2822 fct_q_for_termination_lock_held(iport, icmd, s); 2823 if (IS_WORKER_SLEEPING(iport)) 2824 cv_signal(&iport->iport_worker_cv); 2825 mutex_exit(&iport->iport_worker_lock); 2826 } 2827 2828 /* 2829 * This function will not be called for SCSI CMDS 2830 */ 2831 void 2832 fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd, 2833 fct_status_t s) 2834 { 2835 uint32_t old, new; 2836 fct_i_cmd_t **ppicmd; 2837 2838 do { 2839 old = icmd->icmd_flags; 2840 if (old & ICMD_BEING_ABORTED) 2841 return; 2842 new = old | ICMD_BEING_ABORTED; 2843 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 2844 2845 icmd->icmd_start_time = ddi_get_lbolt(); 2846 icmd->icmd_cmd->cmd_comp_status = s; 2847 2848 icmd->icmd_next = NULL; 2849 for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL; 2850 ppicmd = &((*ppicmd)->icmd_next)) 2851 ; 2852 2853 *ppicmd = icmd; 2854 } 2855 2856 /* 2857 * For those cmds, for which we called fca_abort but it has not yet completed, 2858 * reset the FCA_ABORT_CALLED flag, so that abort can be called again. 2859 * This is done after a FCA offline. The reason is that after offline, the 2860 * firmware is not running so abort will never complete. But if we call it 2861 * again, the FCA will detect that it is not offline and it will 2862 * not call the firmware at all. Most likely it will abort in a synchronous 2863 * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND. 2864 */ 2865 void 2866 fct_reset_flag_abort_called(fct_i_local_port_t *iport) 2867 { 2868 fct_i_cmd_t *icmd; 2869 uint32_t old, new; 2870 int i, do_clear; 2871 2872 ASSERT(mutex_owned(&iport->iport_worker_lock)); 2873 mutex_exit(&iport->iport_worker_lock); 2874 rw_enter(&iport->iport_lock, RW_WRITER); 2875 mutex_enter(&iport->iport_worker_lock); 2876 2877 for (i = 0; i < iport->iport_port->port_max_xchges; i++) { 2878 if (iport->iport_cmd_slots[i].slot_cmd == NULL) 2879 continue; 2880 2881 icmd = iport->iport_cmd_slots[i].slot_cmd; 2882 2883 do { 2884 old = new = icmd->icmd_flags; 2885 if ((old & (ICMD_KNOWN_TO_FCA | 2886 ICMD_FCA_ABORT_CALLED)) == (ICMD_KNOWN_TO_FCA | 2887 ICMD_FCA_ABORT_CALLED)) { 2888 new &= ~ICMD_FCA_ABORT_CALLED; 2889 do_clear = 1; 2890 } else { 2891 do_clear = 0; 2892 break; 2893 } 2894 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old); 2895 if (do_clear && 2896 (icmd->icmd_cmd->cmd_type == FCT_CMD_FCP_XCHG)) { 2897 stmf_abort(STMF_REQUEUE_TASK_ABORT_LPORT, 2898 icmd->icmd_cmd->cmd_specific, 0, NULL); 2899 } 2900 } 2901 2902 rw_exit(&iport->iport_lock); 2903 } 2904 2905 /* 2906 * Modify the irp_deregister_timer such that the ports start deregistering 2907 * quickly. 2908 */ 2909 void 2910 fct_irp_deregister_speedup(fct_i_local_port_t *iport) 2911 { 2912 fct_i_remote_port_t *irp; 2913 int i; 2914 2915 if (!iport->iport_nrps) 2916 return; 2917 2918 for (i = 0; i < rportid_table_size; i++) { 2919 irp = iport->iport_rp_tb[i]; 2920 while (irp) { 2921 irp->irp_deregister_timer = ddi_get_lbolt() - 1; 2922 irp = irp->irp_next; 2923 } 2924 } 2925 } 2926 2927 disc_action_t 2928 fct_handle_port_offline(fct_i_local_port_t *iport) 2929 { 2930 if (iport->iport_offline_prstate == FCT_OPR_START) { 2931 fct_reset_flag_abort_called(iport); 2932 iport->iport_offline_prstate = FCT_OPR_CMD_CLEANUP_WAIT; 2933 /* fct_ctl has already submitted a link offline event */ 2934 return (DISC_ACTION_DELAY_RESCAN); 2935 } 2936 if (iport->iport_offline_prstate == FCT_OPR_CMD_CLEANUP_WAIT) { 2937 if (iport->iport_link_state != PORT_STATE_LINK_DOWN) 2938 return (DISC_ACTION_DELAY_RESCAN); 2939 /* 2940 * All I/Os have been killed at this time. Lets speedup 2941 * the port deregister process. 2942 */ 2943 mutex_exit(&iport->iport_worker_lock); 2944 rw_enter(&iport->iport_lock, RW_WRITER); 2945 fct_irp_deregister_speedup(iport); 2946 rw_exit(&iport->iport_lock); 2947 mutex_enter(&iport->iport_worker_lock); 2948 iport->iport_offline_prstate = FCT_OPR_INT_CLEANUP_WAIT; 2949 return (DISC_ACTION_RESCAN); 2950 } 2951 if (iport->iport_offline_prstate == FCT_OPR_INT_CLEANUP_WAIT) { 2952 stmf_change_status_t st; 2953 2954 if (iport->iport_solcmd_queue) { 2955 return (DISC_ACTION_DELAY_RESCAN); 2956 } 2957 2958 if (iport->iport_nrps) { 2959 /* 2960 * A port logout may have gone when implicit logo all 2961 * was retried. So do the port speedup again here. 2962 */ 2963 mutex_exit(&iport->iport_worker_lock); 2964 rw_enter(&iport->iport_lock, RW_WRITER); 2965 fct_irp_deregister_speedup(iport); 2966 rw_exit(&iport->iport_lock); 2967 mutex_enter(&iport->iport_worker_lock); 2968 return (DISC_ACTION_DELAY_RESCAN); 2969 } 2970 2971 if (iport->iport_event_head != NULL) { 2972 return (DISC_ACTION_DELAY_RESCAN); 2973 } 2974 2975 st.st_completion_status = STMF_SUCCESS; 2976 st.st_additional_info = NULL; 2977 iport->iport_offline_prstate = FCT_OPR_DONE; 2978 iport->iport_state = FCT_STATE_OFFLINE; 2979 mutex_exit(&iport->iport_worker_lock); 2980 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, 2981 iport->iport_port->port_lport, &st); 2982 mutex_enter(&iport->iport_worker_lock); 2983 return (DISC_ACTION_DELAY_RESCAN); 2984 } 2985 2986 /* NOTREACHED */ 2987 return (0); 2988 } 2989 2990 /* 2991 * See stmf.h for information on rflags. Additional info is just a text 2992 * description of the reason for this call. Additional_info can be NULL. 2993 * Also the caller can declare additional info on the stack. stmf_ctl 2994 * makes a copy of it before returning. 2995 */ 2996 fct_status_t 2997 fct_port_initialize(fct_local_port_t *port, uint32_t rflags, 2998 char *additional_info) 2999 { 3000 stmf_state_change_info_t st; 3001 3002 st.st_rflags = rflags; 3003 st.st_additional_info = additional_info; 3004 stmf_trace(NULL, "fct_port_initialize: port-%p, %s", port, 3005 additional_info? additional_info : "no more information"); 3006 return (stmf_ctl(STMF_CMD_LPORT_ONLINE, port->port_lport, &st)); 3007 } 3008 3009 fct_status_t 3010 fct_port_shutdown(fct_local_port_t *port, uint32_t rflags, 3011 char *additional_info) 3012 { 3013 stmf_state_change_info_t st; 3014 3015 st.st_rflags = rflags; 3016 st.st_additional_info = additional_info; 3017 stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port, 3018 additional_info? additional_info : "no more information"); 3019 return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st)); 3020 } 3021 3022 /* 3023 * Called by worker thread. The aim is to terminate the command 3024 * using whatever means it takes. 3025 * Called with worker lock held. 3026 */ 3027 disc_action_t 3028 fct_cmd_terminator(fct_i_local_port_t *iport) 3029 { 3030 char info[80]; 3031 clock_t endtime; 3032 fct_i_cmd_t **ppicmd; 3033 fct_i_cmd_t *icmd; 3034 fct_cmd_t *cmd; 3035 fct_local_port_t *port = iport->iport_port; 3036 disc_action_t ret = DISC_ACTION_NO_WORK; 3037 fct_status_t abort_ret; 3038 int fca_done, fct_done, cmd_implicit = 0; 3039 int flags; 3040 unsigned long long st; 3041 3042 /* Lets Limit each run to 20ms max. */ 3043 endtime = ddi_get_lbolt() + drv_usectohz(20000); 3044 3045 /* Start from where we left off last time */ 3046 if (iport->iport_ppicmd_term) { 3047 ppicmd = iport->iport_ppicmd_term; 3048 iport->iport_ppicmd_term = NULL; 3049 } else { 3050 ppicmd = &iport->iport_abort_queue; 3051 } 3052 3053 /* 3054 * Once a command gets on discovery queue, this is the only thread 3055 * which can access it. So no need for the lock here. 3056 */ 3057 mutex_exit(&iport->iport_worker_lock); 3058 3059 while ((icmd = *ppicmd) != NULL) { 3060 cmd = icmd->icmd_cmd; 3061 3062 /* Always remember that cmd->cmd_rp can be NULL */ 3063 if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA | 3064 ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) { 3065 atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED); 3066 if (CMD_HANDLE_VALID(cmd->cmd_handle)) 3067 flags = 0; 3068 else 3069 flags = FCT_IOF_FORCE_FCA_DONE; 3070 abort_ret = port->port_abort_cmd(port, cmd, flags); 3071 if ((abort_ret != FCT_SUCCESS) && 3072 (abort_ret != FCT_ABORT_SUCCESS) && 3073 (abort_ret != FCT_NOT_FOUND)) { 3074 if (flags & FCT_IOF_FORCE_FCA_DONE) { 3075 /* 3076 * XXX trigger port fatal, 3077 * Abort the termination, and shutdown 3078 * svc will trigger fct_cmd_termination 3079 * again. 3080 */ 3081 (void) snprintf(info, 80, 3082 "fct_cmd_terminator:" 3083 " iport-%p, port_abort_cmd with " 3084 "FORCE_FCA_DONE failed", 3085 (void *)iport); 3086 info[79] = 0; 3087 (void) fct_port_shutdown( 3088 iport->iport_port, 3089 STMF_RFLAG_FATAL_ERROR | 3090 STMF_RFLAG_RESET, info); 3091 3092 mutex_enter(&iport->iport_worker_lock); 3093 iport->iport_ppicmd_term = ppicmd; 3094 return (DISC_ACTION_DELAY_RESCAN); 3095 } 3096 atomic_and_32(&icmd->icmd_flags, 3097 ~ICMD_FCA_ABORT_CALLED); 3098 } else if ((flags & FCT_IOF_FORCE_FCA_DONE) || 3099 (abort_ret == FCT_ABORT_SUCCESS) || 3100 (abort_ret == FCT_NOT_FOUND)) { 3101 atomic_and_32(&icmd->icmd_flags, 3102 ~ICMD_KNOWN_TO_FCA); 3103 } 3104 ret |= DISC_ACTION_DELAY_RESCAN; 3105 } else if (icmd->icmd_flags & ICMD_IMPLICIT) { 3106 if (cmd->cmd_type == FCT_CMD_SOL_ELS) 3107 cmd->cmd_comp_status = FCT_ABORTED; 3108 atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED); 3109 cmd_implicit = 1; 3110 } 3111 if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0) 3112 fca_done = 1; 3113 else 3114 fca_done = 0; 3115 if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0) 3116 fct_done = 1; 3117 else 3118 fct_done = 0; 3119 if ((fca_done || cmd_implicit) && fct_done) { 3120 mutex_enter(&iport->iport_worker_lock); 3121 ASSERT(*ppicmd == icmd); 3122 *ppicmd = (*ppicmd)->icmd_next; 3123 mutex_exit(&iport->iport_worker_lock); 3124 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) || 3125 (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) { 3126 /* Free the cmd */ 3127 fct_cmd_free(cmd); 3128 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) { 3129 fct_handle_sol_els_completion(iport, icmd); 3130 if (icmd->icmd_flags & ICMD_IMPLICIT) { 3131 if (IS_LOGO_ELS(icmd)) { 3132 /* IMPLICIT LOGO is special */ 3133 fct_cmd_free(cmd); 3134 } 3135 } 3136 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { 3137 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 3138 3139 /* Tell the caller that we are done */ 3140 atomic_or_32(&icmd->icmd_flags, 3141 ICMD_CMD_COMPLETE); 3142 if (fct_netbuf_to_value( 3143 ct->ct_req_payload + 8, 2) == NS_GID_PN) { 3144 fct_i_remote_port_t *irp; 3145 3146 rw_enter(&iport->iport_lock, RW_READER); 3147 irp = fct_lookup_irp_by_portwwn(iport, 3148 ct->ct_req_payload + 16); 3149 3150 if (irp) { 3151 atomic_and_32(&irp->irp_flags, 3152 ~IRP_RSCN_QUEUED); 3153 } 3154 rw_exit(&iport->iport_lock); 3155 } 3156 } else { 3157 ASSERT(0); 3158 } 3159 } else { 3160 clock_t timeout_ticks; 3161 if (port->port_fca_abort_timeout) 3162 timeout_ticks = drv_usectohz( 3163 port->port_fca_abort_timeout*1000); 3164 else 3165 /* 10 seconds by default */ 3166 timeout_ticks = drv_usectohz(10 * 1000000); 3167 if ((ddi_get_lbolt() > 3168 (icmd->icmd_start_time+timeout_ticks)) && 3169 iport->iport_state == FCT_STATE_ONLINE) { 3170 /* timeout, reset the port */ 3171 char cmd_type[10]; 3172 if (cmd->cmd_type == FCT_CMD_RCVD_ELS || 3173 cmd->cmd_type == FCT_CMD_SOL_ELS) { 3174 fct_els_t *els = cmd->cmd_specific; 3175 (void) snprintf(cmd_type, 3176 sizeof (cmd_type), "%x.%x", 3177 cmd->cmd_type, 3178 els->els_req_payload[0]); 3179 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { 3180 fct_sol_ct_t *ct = cmd->cmd_specific; 3181 (void) snprintf(cmd_type, 3182 sizeof (cmd_type), "%x.%02x%02x", 3183 cmd->cmd_type, 3184 ct->ct_req_payload[8], 3185 ct->ct_req_payload[9]); 3186 } else { 3187 cmd_type[0] = 0; 3188 } 3189 st = cmd->cmd_comp_status; /* gcc fix */ 3190 (void) snprintf(info, 80, "fct_cmd_terminator:" 3191 " iport-%p, cmd_type(0x%s)," 3192 " reason(%llx)", (void *)iport, cmd_type, 3193 st); 3194 info[79] = 0; 3195 (void) fct_port_shutdown(port, 3196 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, 3197 info); 3198 } 3199 ppicmd = &((*ppicmd)->icmd_next); 3200 } 3201 3202 if (ddi_get_lbolt() > endtime) { 3203 mutex_enter(&iport->iport_worker_lock); 3204 iport->iport_ppicmd_term = ppicmd; 3205 return (DISC_ACTION_DELAY_RESCAN); 3206 } 3207 } 3208 mutex_enter(&iport->iport_worker_lock); 3209 if (iport->iport_abort_queue) 3210 return (DISC_ACTION_DELAY_RESCAN); 3211 if (ret == DISC_ACTION_NO_WORK) 3212 return (DISC_ACTION_RESCAN); 3213 return (ret); 3214 } 3215 3216 /* 3217 * Send a syslog event for adapter port level events. 3218 */ 3219 void 3220 fct_log_local_port_event(fct_local_port_t *port, char *subclass) 3221 { 3222 nvlist_t *attr_list; 3223 int port_instance; 3224 3225 if (!fct_dip) 3226 return; 3227 port_instance = ddi_get_instance(fct_dip); 3228 3229 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 3230 KM_SLEEP) != DDI_SUCCESS) { 3231 goto alloc_failed; 3232 } 3233 3234 if (nvlist_add_uint32(attr_list, "instance", port_instance) 3235 != DDI_SUCCESS) { 3236 goto error; 3237 } 3238 3239 if (nvlist_add_byte_array(attr_list, "port-wwn", 3240 port->port_pwwn, 8) != DDI_SUCCESS) { 3241 goto error; 3242 } 3243 3244 (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC, 3245 subclass, attr_list, NULL, DDI_SLEEP); 3246 3247 nvlist_free(attr_list); 3248 return; 3249 3250 error: 3251 nvlist_free(attr_list); 3252 alloc_failed: 3253 stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias, 3254 "Unable to send %s event", subclass); 3255 } 3256 3257 void 3258 fct_log_remote_port_event(fct_local_port_t *port, char *subclass, 3259 uint8_t *rp_pwwn, uint32_t rp_id) 3260 { 3261 nvlist_t *attr_list; 3262 int port_instance; 3263 3264 if (!fct_dip) 3265 return; 3266 port_instance = ddi_get_instance(fct_dip); 3267 3268 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 3269 KM_SLEEP) != DDI_SUCCESS) { 3270 goto alloc_failed; 3271 } 3272 3273 if (nvlist_add_uint32(attr_list, "instance", port_instance) 3274 != DDI_SUCCESS) { 3275 goto error; 3276 } 3277 3278 if (nvlist_add_byte_array(attr_list, "port-wwn", 3279 port->port_pwwn, 8) != DDI_SUCCESS) { 3280 goto error; 3281 } 3282 3283 if (nvlist_add_byte_array(attr_list, "target-port-wwn", 3284 rp_pwwn, 8) != DDI_SUCCESS) { 3285 goto error; 3286 } 3287 3288 if (nvlist_add_uint32(attr_list, "target-port-id", 3289 rp_id) != DDI_SUCCESS) { 3290 goto error; 3291 } 3292 3293 (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC, 3294 subclass, attr_list, NULL, DDI_SLEEP); 3295 3296 nvlist_free(attr_list); 3297 return; 3298 3299 error: 3300 nvlist_free(attr_list); 3301 alloc_failed: 3302 stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias, 3303 "Unable to send %s event", subclass); 3304 } 3305 3306 uint64_t 3307 fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes) 3308 { 3309 uint64_t ret = 0; 3310 uint8_t idx = 0; 3311 3312 do { 3313 ret |= (buf[idx] << (8 * (nbytes -idx - 1))); 3314 } while (++idx < nbytes); 3315 3316 return (ret); 3317 } 3318 3319 void 3320 fct_value_to_netbuf(uint64_t value, uint8_t *buf, uint8_t nbytes) 3321 { 3322 uint8_t idx = 0; 3323 3324 for (idx = 0; idx < nbytes; idx++) { 3325 buf[idx] = 0xFF & (value >> (8 * (nbytes - idx - 1))); 3326 } 3327 } 3328 3329 /* 3330 * from_ptr: ptr to uchar_t array of size WWN_SIZE 3331 * to_ptr: char ptr to string of size WWN_SIZE*2+1 3332 */ 3333 void 3334 fct_wwn_to_str(char *to_ptr, const uint8_t *from_ptr) 3335 { 3336 ASSERT(to_ptr != NULL && from_ptr != NULL); 3337 3338 (void) sprintf(to_ptr, "%02x%02x%02x%02x%02x%02x%02x%02x", 3339 from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3], 3340 from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]); 3341 } 3342