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