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