aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2011-05-24 11:42:11 -0400
committerJames Bottomley <jbottomley@parallels.com>2011-05-26 23:49:36 -0400
commit912e3acde60b3b9ebf46c5ec5ae6bd01b80132c8 (patch)
tree2ca2593ff23e61580879e1deb405b2dfc8d92f83
parentc0c1151276aae83dffbe3f2837a3b1d893894115 (diff)
[SCSI] lpfc 8.3.24: Add SR-IOV control
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <jbottomley@parallels.com>
-rw-r--r--drivers/scsi/lpfc/lpfc.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c237
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h149
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c144
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h6
7 files changed, 536 insertions, 5 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3df2b39dd87a..9d0bfba5461e 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -660,6 +660,7 @@ struct lpfc_hba {
660 uint32_t cfg_hostmem_hgp; 660 uint32_t cfg_hostmem_hgp;
661 uint32_t cfg_log_verbose; 661 uint32_t cfg_log_verbose;
662 uint32_t cfg_aer_support; 662 uint32_t cfg_aer_support;
663 uint32_t cfg_sriov_nr_virtfn;
663 uint32_t cfg_iocb_cnt; 664 uint32_t cfg_iocb_cnt;
664 uint32_t cfg_suppress_link_up; 665 uint32_t cfg_suppress_link_up;
665#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ 666#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 44816be4d724..6ecd6daffc15 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1384,6 +1384,102 @@ lpfc_dss_show(struct device *dev, struct device_attribute *attr,
1384} 1384}
1385 1385
1386/** 1386/**
1387 * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions
1388 * @dev: class converted to a Scsi_host structure.
1389 * @attr: device attribute, not used.
1390 * @buf: on return contains the formatted support level.
1391 *
1392 * Description:
1393 * Returns the maximum number of virtual functions a physical function can
1394 * support, 0 will be returned if called on virtual function.
1395 *
1396 * Returns: size of formatted string.
1397 **/
1398static ssize_t
1399lpfc_sriov_hw_max_virtfn_show(struct device *dev,
1400 struct device_attribute *attr,
1401 char *buf)
1402{
1403 struct Scsi_Host *shost = class_to_shost(dev);
1404 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
1405 struct lpfc_hba *phba = vport->phba;
1406 struct pci_dev *pdev = phba->pcidev;
1407 union lpfc_sli4_cfg_shdr *shdr;
1408 uint32_t shdr_status, shdr_add_status;
1409 LPFC_MBOXQ_t *mboxq;
1410 struct lpfc_mbx_get_prof_cfg *get_prof_cfg;
1411 struct lpfc_rsrc_desc_pcie *desc;
1412 uint32_t max_nr_virtfn;
1413 uint32_t desc_count;
1414 int length, rc, i;
1415
1416 if ((phba->sli_rev < LPFC_SLI_REV4) ||
1417 (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
1418 LPFC_SLI_INTF_IF_TYPE_2))
1419 return -EPERM;
1420
1421 if (!pdev->is_physfn)
1422 return snprintf(buf, PAGE_SIZE, "%d\n", 0);
1423
1424 mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1425 if (!mboxq)
1426 return -ENOMEM;
1427
1428 /* get the maximum number of virtfn support by physfn */
1429 length = (sizeof(struct lpfc_mbx_get_prof_cfg) -
1430 sizeof(struct lpfc_sli4_cfg_mhdr));
1431 lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
1432 LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG,
1433 length, LPFC_SLI4_MBX_EMBED);
1434 shdr = (union lpfc_sli4_cfg_shdr *)
1435 &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
1436 bf_set(lpfc_mbox_hdr_pf_num, &shdr->request,
1437 phba->sli4_hba.iov.pf_number + 1);
1438
1439 get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg;
1440 bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request,
1441 LPFC_CFG_TYPE_CURRENT_ACTIVE);
1442
1443 rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
1444 lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
1445
1446 if (rc != MBX_TIMEOUT) {
1447 /* check return status */
1448 shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
1449 shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
1450 &shdr->response);
1451 if (shdr_status || shdr_add_status || rc)
1452 goto error_out;
1453
1454 } else
1455 goto error_out;
1456
1457 desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count;
1458
1459 for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
1460 desc = (struct lpfc_rsrc_desc_pcie *)
1461 &get_prof_cfg->u.response.prof_cfg.desc[i];
1462 if (LPFC_RSRC_DESC_TYPE_PCIE ==
1463 bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
1464 max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn,
1465 desc);
1466 break;
1467 }
1468 }
1469
1470 if (i < LPFC_RSRC_DESC_MAX_NUM) {
1471 if (rc != MBX_TIMEOUT)
1472 mempool_free(mboxq, phba->mbox_mem_pool);
1473 return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
1474 }
1475
1476error_out:
1477 if (rc != MBX_TIMEOUT)
1478 mempool_free(mboxq, phba->mbox_mem_pool);
1479 return -EIO;
1480}
1481
1482/**
1387 * lpfc_param_show - Return a cfg attribute value in decimal 1483 * lpfc_param_show - Return a cfg attribute value in decimal
1388 * 1484 *
1389 * Description: 1485 * Description:
@@ -1824,6 +1920,8 @@ static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL);
1824static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL); 1920static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL);
1825static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL); 1921static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL);
1826static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL); 1922static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL);
1923static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO,
1924 lpfc_sriov_hw_max_virtfn_show, NULL);
1827 1925
1828static char *lpfc_soft_wwn_key = "C99G71SL8032A"; 1926static char *lpfc_soft_wwn_key = "C99G71SL8032A";
1829 1927
@@ -3076,7 +3174,7 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
3076 * 3174 *
3077 * @dev: class device that is converted into a Scsi_host. 3175 * @dev: class device that is converted into a Scsi_host.
3078 * @attr: device attribute, not used. 3176 * @attr: device attribute, not used.
3079 * @buf: containing the string "selective". 3177 * @buf: containing enable or disable aer flag.
3080 * @count: unused variable. 3178 * @count: unused variable.
3081 * 3179 *
3082 * Description: 3180 * Description:
@@ -3160,7 +3258,7 @@ lpfc_param_show(aer_support)
3160/** 3258/**
3161 * lpfc_aer_support_init - Set the initial adapters aer support flag 3259 * lpfc_aer_support_init - Set the initial adapters aer support flag
3162 * @phba: lpfc_hba pointer. 3260 * @phba: lpfc_hba pointer.
3163 * @val: link speed value. 3261 * @val: enable aer or disable aer flag.
3164 * 3262 *
3165 * Description: 3263 * Description:
3166 * If val is in a valid range [0,1], then set the adapter's initial 3264 * If val is in a valid range [0,1], then set the adapter's initial
@@ -3199,7 +3297,7 @@ static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR,
3199 * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device 3297 * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device
3200 * @dev: class device that is converted into a Scsi_host. 3298 * @dev: class device that is converted into a Scsi_host.
3201 * @attr: device attribute, not used. 3299 * @attr: device attribute, not used.
3202 * @buf: containing the string "selective". 3300 * @buf: containing flag 1 for aer cleanup state.
3203 * @count: unused variable. 3301 * @count: unused variable.
3204 * 3302 *
3205 * Description: 3303 * Description:
@@ -3242,6 +3340,136 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
3242static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL, 3340static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL,
3243 lpfc_aer_cleanup_state); 3341 lpfc_aer_cleanup_state);
3244 3342
3343/**
3344 * lpfc_sriov_nr_virtfn_store - Enable the adapter for sr-iov virtual functions
3345 *
3346 * @dev: class device that is converted into a Scsi_host.
3347 * @attr: device attribute, not used.
3348 * @buf: containing the string the number of vfs to be enabled.
3349 * @count: unused variable.
3350 *
3351 * Description:
3352 * When this api is called either through user sysfs, the driver shall
3353 * try to enable or disable SR-IOV virtual functions according to the
3354 * following:
3355 *
3356 * If zero virtual function has been enabled to the physical function,
3357 * the driver shall invoke the pci enable virtual function api trying
3358 * to enable the virtual functions. If the nr_vfn provided is greater
3359 * than the maximum supported, the maximum virtual function number will
3360 * be used for invoking the api; otherwise, the nr_vfn provided shall
3361 * be used for invoking the api. If the api call returned success, the
3362 * actual number of virtual functions enabled will be set to the driver
3363 * cfg_sriov_nr_virtfn; otherwise, -EINVAL shall be returned and driver
3364 * cfg_sriov_nr_virtfn remains zero.
3365 *
3366 * If none-zero virtual functions have already been enabled to the
3367 * physical function, as reflected by the driver's cfg_sriov_nr_virtfn,
3368 * -EINVAL will be returned and the driver does nothing;
3369 *
3370 * If the nr_vfn provided is zero and none-zero virtual functions have
3371 * been enabled, as indicated by the driver's cfg_sriov_nr_virtfn, the
3372 * disabling virtual function api shall be invoded to disable all the
3373 * virtual functions and driver's cfg_sriov_nr_virtfn shall be set to
3374 * zero. Otherwise, if zero virtual function has been enabled, do
3375 * nothing.
3376 *
3377 * Returns:
3378 * length of the buf on success if val is in range the intended mode
3379 * is supported.
3380 * -EINVAL if val out of range or intended mode is not supported.
3381 **/
3382static ssize_t
3383lpfc_sriov_nr_virtfn_store(struct device *dev, struct device_attribute *attr,
3384 const char *buf, size_t count)
3385{
3386 struct Scsi_Host *shost = class_to_shost(dev);
3387 struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
3388 struct lpfc_hba *phba = vport->phba;
3389 struct pci_dev *pdev = phba->pcidev;
3390 int val = 0, rc = -EINVAL;
3391
3392 /* Sanity check on user data */
3393 if (!isdigit(buf[0]))
3394 return -EINVAL;
3395 if (sscanf(buf, "%i", &val) != 1)
3396 return -EINVAL;
3397 if (val < 0)
3398 return -EINVAL;
3399
3400 /* Request disabling virtual functions */
3401 if (val == 0) {
3402 if (phba->cfg_sriov_nr_virtfn > 0) {
3403 pci_disable_sriov(pdev);
3404 phba->cfg_sriov_nr_virtfn = 0;
3405 }
3406 return strlen(buf);
3407 }
3408
3409 /* Request enabling virtual functions */
3410 if (phba->cfg_sriov_nr_virtfn > 0) {
3411 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3412 "3018 There are %d virtual functions "
3413 "enabled on physical function.\n",
3414 phba->cfg_sriov_nr_virtfn);
3415 return -EEXIST;
3416 }
3417
3418 if (val <= LPFC_MAX_VFN_PER_PFN)
3419 phba->cfg_sriov_nr_virtfn = val;
3420 else {
3421 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3422 "3019 Enabling %d virtual functions is not "
3423 "allowed.\n", val);
3424 return -EINVAL;
3425 }
3426
3427 rc = lpfc_sli_probe_sriov_nr_virtfn(phba, phba->cfg_sriov_nr_virtfn);
3428 if (rc) {
3429 phba->cfg_sriov_nr_virtfn = 0;
3430 rc = -EPERM;
3431 } else
3432 rc = strlen(buf);
3433
3434 return rc;
3435}
3436
3437static int lpfc_sriov_nr_virtfn = LPFC_DEF_VFN_PER_PFN;
3438module_param(lpfc_sriov_nr_virtfn, int, S_IRUGO|S_IWUSR);
3439MODULE_PARM_DESC(lpfc_sriov_nr_virtfn, "Enable PCIe device SR-IOV virtual fn");
3440lpfc_param_show(sriov_nr_virtfn)
3441
3442/**
3443 * lpfc_sriov_nr_virtfn_init - Set the initial sr-iov virtual function enable
3444 * @phba: lpfc_hba pointer.
3445 * @val: link speed value.
3446 *
3447 * Description:
3448 * If val is in a valid range [0,255], then set the adapter's initial
3449 * cfg_sriov_nr_virtfn field. If it's greater than the maximum, the maximum
3450 * number shall be used instead. It will be up to the driver's probe_one
3451 * routine to determine whether the device's SR-IOV is supported or not.
3452 *
3453 * Returns:
3454 * zero if val saved.
3455 * -EINVAL val out of range
3456 **/
3457static int
3458lpfc_sriov_nr_virtfn_init(struct lpfc_hba *phba, int val)
3459{
3460 if (val >= 0 && val <= LPFC_MAX_VFN_PER_PFN) {
3461 phba->cfg_sriov_nr_virtfn = val;
3462 return 0;
3463 }
3464
3465 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3466 "3017 Enabling %d virtual functions is not "
3467 "allowed.\n", val);
3468 return -EINVAL;
3469}
3470static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR,
3471 lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store);
3472
3245/* 3473/*
3246# lpfc_fcp_class: Determines FC class to use for the FCP protocol. 3474# lpfc_fcp_class: Determines FC class to use for the FCP protocol.
3247# Value range is [2,3]. Default value is 3. 3475# Value range is [2,3]. Default value is 3.
@@ -3559,6 +3787,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
3559 &dev_attr_lpfc_prot_sg_seg_cnt, 3787 &dev_attr_lpfc_prot_sg_seg_cnt,
3560 &dev_attr_lpfc_aer_support, 3788 &dev_attr_lpfc_aer_support,
3561 &dev_attr_lpfc_aer_state_cleanup, 3789 &dev_attr_lpfc_aer_state_cleanup,
3790 &dev_attr_lpfc_sriov_nr_virtfn,
3562 &dev_attr_lpfc_suppress_link_up, 3791 &dev_attr_lpfc_suppress_link_up,
3563 &dev_attr_lpfc_iocb_cnt, 3792 &dev_attr_lpfc_iocb_cnt,
3564 &dev_attr_iocb_hw, 3793 &dev_attr_iocb_hw,
@@ -3567,6 +3796,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
3567 &dev_attr_lpfc_fips_level, 3796 &dev_attr_lpfc_fips_level,
3568 &dev_attr_lpfc_fips_rev, 3797 &dev_attr_lpfc_fips_rev,
3569 &dev_attr_lpfc_dss, 3798 &dev_attr_lpfc_dss,
3799 &dev_attr_lpfc_sriov_hw_max_virtfn,
3570 NULL, 3800 NULL,
3571}; 3801};
3572 3802
@@ -4767,6 +4997,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
4767 lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); 4997 lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
4768 lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); 4998 lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
4769 lpfc_aer_support_init(phba, lpfc_aer_support); 4999 lpfc_aer_support_init(phba, lpfc_aer_support);
5000 lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn);
4770 lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); 5001 lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
4771 lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); 5002 lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
4772 phba->cfg_enable_dss = 1; 5003 phba->cfg_enable_dss = 1;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index eb02016a21b5..3b9a6152b7f9 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -430,3 +430,5 @@ void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
430void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *); 430void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
431struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t, 431struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
432 uint32_t); 432 uint32_t);
433/* functions to support SR-IOV */
434int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 6aa53aca23e9..bb3af9fabd7e 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -903,6 +903,8 @@ struct RRQ { /* Structure is in Big Endian format */
903#define rrq_rxid_WORD rrq_exchg 903#define rrq_rxid_WORD rrq_exchg
904}; 904};
905 905
906#define LPFC_MAX_VFN_PER_PFN 255 /* Maximum VFs allowed per ARI */
907#define LPFC_DEF_VFN_PER_PFN 0 /* Default VFs due to platform limitation*/
906 908
907struct RTV_RSP { /* Structure is in Big Endian format */ 909struct RTV_RSP { /* Structure is in Big Endian format */
908 uint32_t ratov; 910 uint32_t ratov;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index ca7c1dd61938..115915d4a60a 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -758,6 +758,12 @@ union lpfc_sli4_cfg_shdr {
758#define lpfc_mbox_hdr_version_SHIFT 0 758#define lpfc_mbox_hdr_version_SHIFT 0
759#define lpfc_mbox_hdr_version_MASK 0x000000FF 759#define lpfc_mbox_hdr_version_MASK 0x000000FF
760#define lpfc_mbox_hdr_version_WORD word9 760#define lpfc_mbox_hdr_version_WORD word9
761#define lpfc_mbox_hdr_pf_num_SHIFT 16
762#define lpfc_mbox_hdr_pf_num_MASK 0x000000FF
763#define lpfc_mbox_hdr_pf_num_WORD word9
764#define lpfc_mbox_hdr_vh_num_SHIFT 24
765#define lpfc_mbox_hdr_vh_num_MASK 0x000000FF
766#define lpfc_mbox_hdr_vh_num_WORD word9
761#define LPFC_Q_CREATE_VERSION_2 2 767#define LPFC_Q_CREATE_VERSION_2 2
762#define LPFC_Q_CREATE_VERSION_1 1 768#define LPFC_Q_CREATE_VERSION_1 1
763#define LPFC_Q_CREATE_VERSION_0 0 769#define LPFC_Q_CREATE_VERSION_0 0
@@ -813,6 +819,8 @@ struct mbox_header {
813#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A 819#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A
814#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D 820#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D
815#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A 821#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A
822#define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0
823#define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4
816#define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5 824#define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5
817 825
818/* FCoE Opcodes */ 826/* FCoE Opcodes */
@@ -2217,6 +2225,145 @@ struct lpfc_mbx_get_sli4_parameters {
2217 struct lpfc_sli4_parameters sli4_parameters; 2225 struct lpfc_sli4_parameters sli4_parameters;
2218}; 2226};
2219 2227
2228struct lpfc_rscr_desc_generic {
2229#define LPFC_RSRC_DESC_WSIZE 18
2230 uint32_t desc[LPFC_RSRC_DESC_WSIZE];
2231};
2232
2233struct lpfc_rsrc_desc_pcie {
2234 uint32_t word0;
2235#define lpfc_rsrc_desc_pcie_type_SHIFT 0
2236#define lpfc_rsrc_desc_pcie_type_MASK 0x000000ff
2237#define lpfc_rsrc_desc_pcie_type_WORD word0
2238#define LPFC_RSRC_DESC_TYPE_PCIE 0x40
2239 uint32_t word1;
2240#define lpfc_rsrc_desc_pcie_pfnum_SHIFT 0
2241#define lpfc_rsrc_desc_pcie_pfnum_MASK 0x000000ff
2242#define lpfc_rsrc_desc_pcie_pfnum_WORD word1
2243 uint32_t reserved;
2244 uint32_t word3;
2245#define lpfc_rsrc_desc_pcie_sriov_sta_SHIFT 0
2246#define lpfc_rsrc_desc_pcie_sriov_sta_MASK 0x000000ff
2247#define lpfc_rsrc_desc_pcie_sriov_sta_WORD word3
2248#define lpfc_rsrc_desc_pcie_pf_sta_SHIFT 8
2249#define lpfc_rsrc_desc_pcie_pf_sta_MASK 0x000000ff
2250#define lpfc_rsrc_desc_pcie_pf_sta_WORD word3
2251#define lpfc_rsrc_desc_pcie_pf_type_SHIFT 16
2252#define lpfc_rsrc_desc_pcie_pf_type_MASK 0x000000ff
2253#define lpfc_rsrc_desc_pcie_pf_type_WORD word3
2254 uint32_t word4;
2255#define lpfc_rsrc_desc_pcie_nr_virtfn_SHIFT 0
2256#define lpfc_rsrc_desc_pcie_nr_virtfn_MASK 0x0000ffff
2257#define lpfc_rsrc_desc_pcie_nr_virtfn_WORD word4
2258};
2259
2260struct lpfc_rsrc_desc_fcfcoe {
2261 uint32_t word0;
2262#define lpfc_rsrc_desc_fcfcoe_type_SHIFT 0
2263#define lpfc_rsrc_desc_fcfcoe_type_MASK 0x000000ff
2264#define lpfc_rsrc_desc_fcfcoe_type_WORD word0
2265#define LPFC_RSRC_DESC_TYPE_FCFCOE 0x43
2266 uint32_t word1;
2267#define lpfc_rsrc_desc_fcfcoe_vfnum_SHIFT 0
2268#define lpfc_rsrc_desc_fcfcoe_vfnum_MASK 0x000000ff
2269#define lpfc_rsrc_desc_fcfcoe_vfnum_WORD word1
2270#define lpfc_rsrc_desc_fcfcoe_pfnum_SHIFT 16
2271#define lpfc_rsrc_desc_fcfcoe_pfnum_MASK 0x000007ff
2272#define lpfc_rsrc_desc_fcfcoe_pfnum_WORD word1
2273 uint32_t word2;
2274#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_SHIFT 0
2275#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_MASK 0x0000ffff
2276#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_WORD word2
2277#define lpfc_rsrc_desc_fcfcoe_xri_cnt_SHIFT 16
2278#define lpfc_rsrc_desc_fcfcoe_xri_cnt_MASK 0x0000ffff
2279#define lpfc_rsrc_desc_fcfcoe_xri_cnt_WORD word2
2280 uint32_t word3;
2281#define lpfc_rsrc_desc_fcfcoe_wq_cnt_SHIFT 0
2282#define lpfc_rsrc_desc_fcfcoe_wq_cnt_MASK 0x0000ffff
2283#define lpfc_rsrc_desc_fcfcoe_wq_cnt_WORD word3
2284#define lpfc_rsrc_desc_fcfcoe_rq_cnt_SHIFT 16
2285#define lpfc_rsrc_desc_fcfcoe_rq_cnt_MASK 0x0000ffff
2286#define lpfc_rsrc_desc_fcfcoe_rq_cnt_WORD word3
2287 uint32_t word4;
2288#define lpfc_rsrc_desc_fcfcoe_cq_cnt_SHIFT 0
2289#define lpfc_rsrc_desc_fcfcoe_cq_cnt_MASK 0x0000ffff
2290#define lpfc_rsrc_desc_fcfcoe_cq_cnt_WORD word4
2291#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_SHIFT 16
2292#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_MASK 0x0000ffff
2293#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_WORD word4
2294 uint32_t word5;
2295#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_SHIFT 0
2296#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_MASK 0x0000ffff
2297#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_WORD word5
2298#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_SHIFT 16
2299#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_MASK 0x0000ffff
2300#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_WORD word5
2301 uint32_t word6;
2302 uint32_t word7;
2303 uint32_t word8;
2304 uint32_t word9;
2305 uint32_t word10;
2306 uint32_t word11;
2307 uint32_t word12;
2308 uint32_t word13;
2309#define lpfc_rsrc_desc_fcfcoe_lnk_nr_SHIFT 0
2310#define lpfc_rsrc_desc_fcfcoe_lnk_nr_MASK 0x0000003f
2311#define lpfc_rsrc_desc_fcfcoe_lnk_nr_WORD word13
2312#define lpfc_rsrc_desc_fcfcoe_lnk_tp_SHIFT 6
2313#define lpfc_rsrc_desc_fcfcoe_lnk_tp_MASK 0x00000003
2314#define lpfc_rsrc_desc_fcfcoe_lnk_tp_WORD word13
2315#define lpfc_rsrc_desc_fcfcoe_lmc_SHIFT 8
2316#define lpfc_rsrc_desc_fcfcoe_lmc_MASK 0x00000001
2317#define lpfc_rsrc_desc_fcfcoe_lmc_WORD word13
2318#define lpfc_rsrc_desc_fcfcoe_lld_SHIFT 9
2319#define lpfc_rsrc_desc_fcfcoe_lld_MASK 0x00000001
2320#define lpfc_rsrc_desc_fcfcoe_lld_WORD word13
2321#define lpfc_rsrc_desc_fcfcoe_eq_cnt_SHIFT 16
2322#define lpfc_rsrc_desc_fcfcoe_eq_cnt_MASK 0x0000ffff
2323#define lpfc_rsrc_desc_fcfcoe_eq_cnt_WORD word13
2324};
2325
2326struct lpfc_func_cfg {
2327#define LPFC_RSRC_DESC_MAX_NUM 2
2328 uint32_t rsrc_desc_count;
2329 struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM];
2330};
2331
2332struct lpfc_mbx_get_func_cfg {
2333 struct mbox_header header;
2334#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE 0x0
2335#define LPFC_CFG_TYPE_FACTURY_DEFAULT 0x1
2336#define LPFC_CFG_TYPE_CURRENT_ACTIVE 0x2
2337 struct lpfc_func_cfg func_cfg;
2338};
2339
2340struct lpfc_prof_cfg {
2341#define LPFC_RSRC_DESC_MAX_NUM 2
2342 uint32_t rsrc_desc_count;
2343 struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM];
2344};
2345
2346struct lpfc_mbx_get_prof_cfg {
2347 struct mbox_header header;
2348#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE 0x0
2349#define LPFC_CFG_TYPE_FACTURY_DEFAULT 0x1
2350#define LPFC_CFG_TYPE_CURRENT_ACTIVE 0x2
2351 union {
2352 struct {
2353 uint32_t word10;
2354#define lpfc_mbx_get_prof_cfg_prof_id_SHIFT 0
2355#define lpfc_mbx_get_prof_cfg_prof_id_MASK 0x000000ff
2356#define lpfc_mbx_get_prof_cfg_prof_id_WORD word10
2357#define lpfc_mbx_get_prof_cfg_prof_tp_SHIFT 8
2358#define lpfc_mbx_get_prof_cfg_prof_tp_MASK 0x00000003
2359#define lpfc_mbx_get_prof_cfg_prof_tp_WORD word10
2360 } request;
2361 struct {
2362 struct lpfc_prof_cfg prof_cfg;
2363 } response;
2364 } u;
2365};
2366
2220/* Mailbox Completion Queue Error Messages */ 2367/* Mailbox Completion Queue Error Messages */
2221#define MB_CQE_STATUS_SUCCESS 0x0 2368#define MB_CQE_STATUS_SUCCESS 0x0
2222#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1 2369#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1
@@ -2271,6 +2418,8 @@ struct lpfc_mqe {
2271 struct lpfc_mbx_supp_pages supp_pages; 2418 struct lpfc_mbx_supp_pages supp_pages;
2272 struct lpfc_mbx_pc_sli4_params sli4_params; 2419 struct lpfc_mbx_pc_sli4_params sli4_params;
2273 struct lpfc_mbx_get_sli4_parameters get_sli4_parameters; 2420 struct lpfc_mbx_get_sli4_parameters get_sli4_parameters;
2421 struct lpfc_mbx_get_func_cfg get_func_cfg;
2422 struct lpfc_mbx_get_prof_cfg get_prof_cfg;
2274 struct lpfc_mbx_nop nop; 2423 struct lpfc_mbx_nop nop;
2275 } un; 2424 } un;
2276}; 2425};
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 16b4da4530b1..e81912cd257e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -4034,6 +4034,36 @@ lpfc_reset_hba(struct lpfc_hba *phba)
4034} 4034}
4035 4035
4036/** 4036/**
4037 * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions
4038 * @phba: pointer to lpfc hba data structure.
4039 * @nr_vfn: number of virtual functions to be enabled.
4040 *
4041 * This function enables the PCI SR-IOV virtual functions to a physical
4042 * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to
4043 * enable the number of virtual functions to the physical function. As
4044 * not all devices support SR-IOV, the return code from the pci_enable_sriov()
4045 * API call does not considered as an error condition for most of the device.
4046 **/
4047int
4048lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)
4049{
4050 struct pci_dev *pdev = phba->pcidev;
4051 int rc;
4052
4053 rc = pci_enable_sriov(pdev, nr_vfn);
4054 if (rc) {
4055 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
4056 "2806 Failed to enable sriov on this device "
4057 "with vfn number nr_vf:%d, rc:%d\n",
4058 nr_vfn, rc);
4059 } else
4060 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
4061 "2807 Successful enable sriov on this device "
4062 "with vfn number nr_vf:%d\n", nr_vfn);
4063 return rc;
4064}
4065
4066/**
4037 * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev. 4067 * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev.
4038 * @phba: pointer to lpfc hba data structure. 4068 * @phba: pointer to lpfc hba data structure.
4039 * 4069 *
@@ -4048,6 +4078,7 @@ static int
4048lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) 4078lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
4049{ 4079{
4050 struct lpfc_sli *psli; 4080 struct lpfc_sli *psli;
4081 int rc;
4051 4082
4052 /* 4083 /*
4053 * Initialize timers used by driver 4084 * Initialize timers used by driver
@@ -4122,6 +4153,23 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
4122 if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ)) 4153 if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ))
4123 return -ENOMEM; 4154 return -ENOMEM;
4124 4155
4156 /*
4157 * Enable sr-iov virtual functions if supported and configured
4158 * through the module parameter.
4159 */
4160 if (phba->cfg_sriov_nr_virtfn > 0) {
4161 rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
4162 phba->cfg_sriov_nr_virtfn);
4163 if (rc) {
4164 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
4165 "2808 Requested number of SR-IOV "
4166 "virtual functions (%d) is not "
4167 "supported\n",
4168 phba->cfg_sriov_nr_virtfn);
4169 phba->cfg_sriov_nr_virtfn = 0;
4170 }
4171 }
4172
4125 return 0; 4173 return 0;
4126} 4174}
4127 4175
@@ -4427,6 +4475,23 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
4427 goto out_free_fcp_eq_hdl; 4475 goto out_free_fcp_eq_hdl;
4428 } 4476 }
4429 4477
4478 /*
4479 * Enable sr-iov virtual functions if supported and configured
4480 * through the module parameter.
4481 */
4482 if (phba->cfg_sriov_nr_virtfn > 0) {
4483 rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
4484 phba->cfg_sriov_nr_virtfn);
4485 if (rc) {
4486 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
4487 "3020 Requested number of SR-IOV "
4488 "virtual functions (%d) is not "
4489 "supported\n",
4490 phba->cfg_sriov_nr_virtfn);
4491 phba->cfg_sriov_nr_virtfn = 0;
4492 }
4493 }
4494
4430 return rc; 4495 return rc;
4431 4496
4432out_free_fcp_eq_hdl: 4497out_free_fcp_eq_hdl:
@@ -5780,7 +5845,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
5780{ 5845{
5781 LPFC_MBOXQ_t *pmb; 5846 LPFC_MBOXQ_t *pmb;
5782 struct lpfc_mbx_read_config *rd_config; 5847 struct lpfc_mbx_read_config *rd_config;
5783 uint32_t rc = 0; 5848 union lpfc_sli4_cfg_shdr *shdr;
5849 uint32_t shdr_status, shdr_add_status;
5850 struct lpfc_mbx_get_func_cfg *get_func_cfg;
5851 struct lpfc_rsrc_desc_fcfcoe *desc;
5852 uint32_t desc_count;
5853 int length, i, rc = 0;
5784 5854
5785 pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 5855 pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
5786 if (!pmb) { 5856 if (!pmb) {
@@ -5855,7 +5925,9 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
5855 phba->sli4_hba.max_cfg_param.fcfi_base, 5925 phba->sli4_hba.max_cfg_param.fcfi_base,
5856 phba->sli4_hba.max_cfg_param.max_fcfi); 5926 phba->sli4_hba.max_cfg_param.max_fcfi);
5857 } 5927 }
5858 mempool_free(pmb, phba->mbox_mem_pool); 5928
5929 if (rc)
5930 goto read_cfg_out;
5859 5931
5860 /* Reset the DFT_HBA_Q_DEPTH to the max xri */ 5932 /* Reset the DFT_HBA_Q_DEPTH to the max xri */
5861 if (phba->cfg_hba_queue_depth > 5933 if (phba->cfg_hba_queue_depth >
@@ -5864,6 +5936,65 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
5864 phba->cfg_hba_queue_depth = 5936 phba->cfg_hba_queue_depth =
5865 phba->sli4_hba.max_cfg_param.max_xri - 5937 phba->sli4_hba.max_cfg_param.max_xri -
5866 lpfc_sli4_get_els_iocb_cnt(phba); 5938 lpfc_sli4_get_els_iocb_cnt(phba);
5939
5940 if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
5941 LPFC_SLI_INTF_IF_TYPE_2)
5942 goto read_cfg_out;
5943
5944 /* get the pf# and vf# for SLI4 if_type 2 port */
5945 length = (sizeof(struct lpfc_mbx_get_func_cfg) -
5946 sizeof(struct lpfc_sli4_cfg_mhdr));
5947 lpfc_sli4_config(phba, pmb, LPFC_MBOX_SUBSYSTEM_COMMON,
5948 LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG,
5949 length, LPFC_SLI4_MBX_EMBED);
5950
5951 rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
5952 shdr = (union lpfc_sli4_cfg_shdr *)
5953 &pmb->u.mqe.un.sli4_config.header.cfg_shdr;
5954 shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
5955 shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
5956 if (rc || shdr_status || shdr_add_status) {
5957 lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
5958 "3026 Mailbox failed , mbxCmd x%x "
5959 "GET_FUNCTION_CONFIG, mbxStatus x%x\n",
5960 bf_get(lpfc_mqe_command, &pmb->u.mqe),
5961 bf_get(lpfc_mqe_status, &pmb->u.mqe));
5962 rc = -EIO;
5963 goto read_cfg_out;
5964 }
5965
5966 /* search for fc_fcoe resrouce descriptor */
5967 get_func_cfg = &pmb->u.mqe.un.get_func_cfg;
5968 desc_count = get_func_cfg->func_cfg.rsrc_desc_count;
5969
5970 for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
5971 desc = (struct lpfc_rsrc_desc_fcfcoe *)
5972 &get_func_cfg->func_cfg.desc[i];
5973 if (LPFC_RSRC_DESC_TYPE_FCFCOE ==
5974 bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
5975 phba->sli4_hba.iov.pf_number =
5976 bf_get(lpfc_rsrc_desc_fcfcoe_pfnum, desc);
5977 phba->sli4_hba.iov.vf_number =
5978 bf_get(lpfc_rsrc_desc_fcfcoe_vfnum, desc);
5979 break;
5980 }
5981 }
5982
5983 if (i < LPFC_RSRC_DESC_MAX_NUM)
5984 lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
5985 "3027 GET_FUNCTION_CONFIG: pf_number:%d, "
5986 "vf_number:%d\n", phba->sli4_hba.iov.pf_number,
5987 phba->sli4_hba.iov.vf_number);
5988 else {
5989 lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
5990 "3028 GET_FUNCTION_CONFIG: failed to find "
5991 "Resrouce Descriptor:x%x\n",
5992 LPFC_RSRC_DESC_TYPE_FCFCOE);
5993 rc = -EIO;
5994 }
5995
5996read_cfg_out:
5997 mempool_free(pmb, phba->mbox_mem_pool);
5867 return rc; 5998 return rc;
5868} 5999}
5869 6000
@@ -7825,6 +7956,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
7825{ 7956{
7826 int wait_cnt = 0; 7957 int wait_cnt = 0;
7827 LPFC_MBOXQ_t *mboxq; 7958 LPFC_MBOXQ_t *mboxq;
7959 struct pci_dev *pdev = phba->pcidev;
7828 7960
7829 lpfc_stop_hba_timers(phba); 7961 lpfc_stop_hba_timers(phba);
7830 phba->sli4_hba.intr_enable = 0; 7962 phba->sli4_hba.intr_enable = 0;
@@ -7864,6 +7996,10 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
7864 /* Disable PCI subsystem interrupt */ 7996 /* Disable PCI subsystem interrupt */
7865 lpfc_sli4_disable_intr(phba); 7997 lpfc_sli4_disable_intr(phba);
7866 7998
7999 /* Disable SR-IOV if enabled */
8000 if (phba->cfg_sriov_nr_virtfn)
8001 pci_disable_sriov(pdev);
8002
7867 /* Stop kthread signal shall trigger work_done one more time */ 8003 /* Stop kthread signal shall trigger work_done one more time */
7868 kthread_stop(phba->worker_thread); 8004 kthread_stop(phba->worker_thread);
7869 8005
@@ -8243,6 +8379,10 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
8243 8379
8244 lpfc_debugfs_terminate(vport); 8380 lpfc_debugfs_terminate(vport);
8245 8381
8382 /* Disable SR-IOV if enabled */
8383 if (phba->cfg_sriov_nr_virtfn)
8384 pci_disable_sriov(pdev);
8385
8246 /* Disable interrupt */ 8386 /* Disable interrupt */
8247 lpfc_sli_disable_intr(phba); 8387 lpfc_sli_disable_intr(phba);
8248 8388
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 1a3cbf88f2ce..03d25a9d3bf6 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -365,6 +365,11 @@ struct lpfc_pc_sli4_params {
365 uint8_t rqv; 365 uint8_t rqv;
366}; 366};
367 367
368struct lpfc_iov {
369 uint32_t pf_number;
370 uint32_t vf_number;
371};
372
368/* SLI4 HBA data structure entries */ 373/* SLI4 HBA data structure entries */
369struct lpfc_sli4_hba { 374struct lpfc_sli4_hba {
370 void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for 375 void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
@@ -467,6 +472,7 @@ struct lpfc_sli4_hba {
467 struct list_head sp_els_xri_aborted_work_queue; 472 struct list_head sp_els_xri_aborted_work_queue;
468 struct list_head sp_unsol_work_queue; 473 struct list_head sp_unsol_work_queue;
469 struct lpfc_sli4_link link_state; 474 struct lpfc_sli4_link link_state;
475 struct lpfc_iov iov;
470 spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ 476 spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */
471 spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */ 477 spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */
472}; 478};