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