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