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