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