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