Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] lpfc 8.3.0 : Fix multiple NPIV issues

- Fix lock up on rmmod with vports defined by having
lpfc_pci_remove_one() invoke fc_vport_terminate() to remove all the
vports before invoking fc_remove_host() for the physical port

- Fix echotest failure when NPIV is enabled

- Add the vport_disable function to the physical port's transport
template to make the vport disable attribute visible

- Set the vport state to DISABLE on create if the disable flag is
true

- Call lpfc_alloc_sysfs_attr() for vports so that statistical data
collection works on them

- Support setting a vport's symbolic name via sysfs by writing to
/sys/class/fc_vport/vportX/symbolic_name

- Fix create vport fails when link is down or in loop mode. Should be
able to be create vports any time NPIV is enabled

- Fix slow vport deletes when deleting multiple vports at once

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

James Smart and committed by
James Bottomley
eada272d 109f6ed0

+78 -35
-2
drivers/scsi/lpfc/lpfc.h
··· 354 354 uint8_t load_flag; 355 355 #define FC_LOADING 0x1 /* HBA in process of loading drvr */ 356 356 #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ 357 - char *vname; /* Application assigned name */ 358 - 359 357 /* Vport Config Parameters */ 360 358 uint32_t cfg_scan_down; 361 359 uint32_t cfg_lun_queue_depth;
+39 -8
drivers/scsi/lpfc/lpfc_attr.c
··· 3282 3282 int error; 3283 3283 3284 3284 error = sysfs_create_bin_file(&shost->shost_dev.kobj, 3285 + &sysfs_drvr_stat_data_attr); 3286 + 3287 + /* Virtual ports do not need ctrl_reg and mbox */ 3288 + if (error || vport->port_type == LPFC_NPIV_PORT) 3289 + goto out; 3290 + 3291 + error = sysfs_create_bin_file(&shost->shost_dev.kobj, 3285 3292 &sysfs_ctlreg_attr); 3286 3293 if (error) 3287 - goto out; 3294 + goto out_remove_stat_attr; 3288 3295 3289 3296 error = sysfs_create_bin_file(&shost->shost_dev.kobj, 3290 3297 &sysfs_mbox_attr); 3291 3298 if (error) 3292 3299 goto out_remove_ctlreg_attr; 3293 3300 3294 - error = sysfs_create_bin_file(&shost->shost_dev.kobj, 3295 - &sysfs_drvr_stat_data_attr); 3296 - if (error) 3297 - goto out_remove_mbox_attr; 3298 - 3299 3301 return 0; 3300 - out_remove_mbox_attr: 3301 - sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); 3302 3302 out_remove_ctlreg_attr: 3303 3303 sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); 3304 + out_remove_stat_attr: 3305 + sysfs_remove_bin_file(&shost->shost_dev.kobj, 3306 + &sysfs_drvr_stat_data_attr); 3304 3307 out: 3305 3308 return error; 3306 3309 } ··· 3318 3315 struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 3319 3316 sysfs_remove_bin_file(&shost->shost_dev.kobj, 3320 3317 &sysfs_drvr_stat_data_attr); 3318 + /* Virtual ports do not need ctrl_reg and mbox */ 3319 + if (vport->port_type == LPFC_NPIV_PORT) 3320 + return; 3321 3321 sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); 3322 3322 sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); 3323 3323 } ··· 3798 3792 lpfc_rport_show_function(field, format_string, sz, ) \ 3799 3793 static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL) 3800 3794 3795 + /** 3796 + * lpfc_set_vport_symbolic_name: Set the vport's symbolic name. 3797 + * @fc_vport: The fc_vport who's symbolic name has been changed. 3798 + * 3799 + * Description: 3800 + * This function is called by the transport after the @fc_vport's symbolic name 3801 + * has been changed. This function re-registers the symbolic name with the 3802 + * switch to propogate the change into the fabric if the vport is active. 3803 + **/ 3804 + static void 3805 + lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) 3806 + { 3807 + struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; 3808 + 3809 + if (vport->port_state == LPFC_VPORT_READY) 3810 + lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); 3811 + } 3801 3812 3802 3813 struct fc_function_template lpfc_transport_functions = { 3803 3814 /* fixed attributes the driver supports */ ··· 3824 3801 .show_host_supported_fc4s = 1, 3825 3802 .show_host_supported_speeds = 1, 3826 3803 .show_host_maxframe_size = 1, 3804 + .show_host_symbolic_name = 1, 3827 3805 3828 3806 /* dynamic attributes the driver supports */ 3829 3807 .get_host_port_id = lpfc_get_host_port_id, ··· 3874 3850 .terminate_rport_io = lpfc_terminate_rport_io, 3875 3851 3876 3852 .dd_fcvport_size = sizeof(struct lpfc_vport *), 3853 + 3854 + .vport_disable = lpfc_vport_disable, 3855 + 3856 + .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, 3877 3857 }; 3878 3858 3879 3859 struct fc_function_template lpfc_vport_transport_functions = { ··· 3888 3860 .show_host_supported_fc4s = 1, 3889 3861 .show_host_supported_speeds = 1, 3890 3862 .show_host_maxframe_size = 1, 3863 + .show_host_symbolic_name = 1, 3891 3864 3892 3865 /* dynamic attributes the driver supports */ 3893 3866 .get_host_port_id = lpfc_get_host_port_id, ··· 3937 3908 .terminate_rport_io = lpfc_terminate_rport_io, 3938 3909 3939 3910 .vport_disable = lpfc_vport_disable, 3911 + 3912 + .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, 3940 3913 }; 3941 3914 3942 3915 /**
+14 -3
drivers/scsi/lpfc/lpfc_ct.c
··· 560 560 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry); 561 561 562 562 /* Don't bother processing response if vport is being torn down. */ 563 - if (vport->load_flag & FC_UNLOADING) 563 + if (vport->load_flag & FC_UNLOADING) { 564 + if (vport->fc_flag & FC_RSCN_MODE) 565 + lpfc_els_flush_rscn(vport); 564 566 goto out; 567 + } 565 568 566 569 if (lpfc_els_chk_latt(vport)) { 567 570 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 568 571 "0216 Link event during NS query\n"); 572 + if (vport->fc_flag & FC_RSCN_MODE) 573 + lpfc_els_flush_rscn(vport); 569 574 lpfc_vport_set_state(vport, FC_VPORT_FAILED); 570 575 goto out; 571 576 } 572 577 if (lpfc_error_lost_link(irsp)) { 573 578 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 574 579 "0226 NS query failed due to link event\n"); 580 + if (vport->fc_flag & FC_RSCN_MODE) 581 + lpfc_els_flush_rscn(vport); 575 582 goto out; 576 583 } 577 584 if (irsp->ulpStatus) { ··· 594 587 if (rc == 0) 595 588 goto out; 596 589 } 590 + if (vport->fc_flag & FC_RSCN_MODE) 591 + lpfc_els_flush_rscn(vport); 597 592 lpfc_vport_set_state(vport, FC_VPORT_FAILED); 598 593 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, 599 594 "0257 GID_FT Query error: 0x%x 0x%x\n", ··· 1017 1008 if (n < size) 1018 1009 n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi); 1019 1010 1020 - if (n < size && vport->vname) 1021 - n += snprintf(symbol + n, size - n, " VName-%s", vport->vname); 1011 + if (n < size && 1012 + strlen(vport->fc_vport->symbolic_name)) 1013 + n += snprintf(symbol + n, size - n, " VName-%s", 1014 + vport->fc_vport->symbolic_name); 1022 1015 return n; 1023 1016 } 1024 1017
+5 -1
drivers/scsi/lpfc/lpfc_els.c
··· 221 221 /* For ELS_REQUEST64_CR, use the VPI by default */ 222 222 icmd->ulpContext = vport->vpi; 223 223 icmd->ulpCt_h = 0; 224 - icmd->ulpCt_l = 1; 224 + /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ 225 + if (elscmd == ELS_CMD_ECHO) 226 + icmd->ulpCt_l = 0; /* context = invalid RPI */ 227 + else 228 + icmd->ulpCt_l = 1; /* context = VPI */ 225 229 } 226 230 227 231 bpl = (struct ulp_bde64 *) pbuflist->virt;
+10 -3
drivers/scsi/lpfc/lpfc_init.c
··· 2041 2041 struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 2042 2042 struct lpfc_hba *phba = vport->phba; 2043 2043 2044 - kfree(vport->vname); 2045 - 2046 2044 lpfc_debugfs_terminate(vport); 2047 2045 fc_remove_host(shost); 2048 2046 scsi_remove_host(shost); ··· 2714 2716 { 2715 2717 struct Scsi_Host *shost = pci_get_drvdata(pdev); 2716 2718 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; 2719 + struct lpfc_vport **vports; 2717 2720 struct lpfc_hba *phba = vport->phba; 2721 + int i; 2718 2722 int bars = pci_select_bars(pdev, IORESOURCE_MEM); 2719 2723 2720 2724 spin_lock_irq(&phba->hbalock); 2721 2725 vport->load_flag |= FC_UNLOADING; 2722 2726 spin_unlock_irq(&phba->hbalock); 2723 2727 2724 - kfree(vport->vname); 2725 2728 lpfc_free_sysfs_attr(vport); 2726 2729 2727 2730 kthread_stop(phba->worker_thread); 2728 2731 2732 + /* Release all the vports against this physical port */ 2733 + vports = lpfc_create_vport_work_array(phba); 2734 + if (vports != NULL) 2735 + for (i = 1; i <= phba->max_vpi && vports[i] != NULL; i++) 2736 + fc_vport_terminate(vports[i]->fc_vport); 2737 + lpfc_destroy_vport_work_array(phba, vports); 2738 + 2739 + /* Remove FC host and then SCSI host with the physical port */ 2729 2740 fc_remove_host(shost); 2730 2741 scsi_remove_host(shost); 2731 2742 lpfc_cleanup(vport);
+10 -18
drivers/scsi/lpfc/lpfc_vport.c
··· 288 288 int vpi; 289 289 int rc = VPORT_ERROR; 290 290 int status; 291 - int size; 292 291 293 - if ((phba->sli_rev < 3) || 294 - !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { 292 + if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) { 295 293 lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, 296 294 "1808 Create VPORT failed: " 297 295 "NPIV is not enabled: SLImode:%d\n", ··· 349 351 350 352 memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); 351 353 memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); 352 - size = strnlen(fc_vport->symbolic_name, LPFC_VNAME_LEN); 353 - if (size) { 354 - vport->vname = kzalloc(size+1, GFP_KERNEL); 355 - if (!vport->vname) { 356 - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, 357 - "1814 Create VPORT failed. " 358 - "vname allocation failed.\n"); 359 - rc = VPORT_ERROR; 360 - lpfc_free_vpi(phba, vpi); 361 - destroy_port(vport); 362 - goto error_out; 363 - } 364 - memcpy(vport->vname, fc_vport->symbolic_name, size+1); 365 - } 366 354 if (fc_vport->node_name != 0) 367 355 u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); 368 356 if (fc_vport->port_name != 0) ··· 378 394 goto error_out; 379 395 } 380 396 397 + /* Create binary sysfs attribute for vport */ 398 + lpfc_alloc_sysfs_attr(vport); 399 + 381 400 *(struct lpfc_vport **)fc_vport->dd_data = vport; 382 401 vport->fc_vport = fc_vport; 383 402 ··· 392 405 } 393 406 394 407 if (disable) { 408 + lpfc_vport_set_state(vport, FC_VPORT_DISABLED); 395 409 rc = VPORT_OK; 396 410 goto out; 397 411 } ··· 575 587 spin_lock_irq(&phba->hbalock); 576 588 vport->load_flag |= FC_UNLOADING; 577 589 spin_unlock_irq(&phba->hbalock); 578 - kfree(vport->vname); 590 + 591 + lpfc_free_sysfs_attr(vport); 592 + 579 593 lpfc_debugfs_terminate(vport); 594 + 595 + /* Remove FC host and then SCSI host with the vport */ 580 596 fc_remove_host(lpfc_shost_from_vport(vport)); 581 597 scsi_remove_host(lpfc_shost_from_vport(vport)); 582 598