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