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