return len;
 }
 
+/**
+ * lpfc_link_state_store - Transition the link_state on an HBA port
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: one or more lpfc_polling_flags values.
+ * @count: not used.
+ *
+ * Returns:
+ * -EINVAL if the buffer is not "up" or "down"
+ * return from link state change function if non-zero
+ * length of the buf on success
+ **/
+static ssize_t
+lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct Scsi_Host  *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct lpfc_hba   *phba = vport->phba;
+
+       int status = -EINVAL;
+
+       if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
+                       (phba->link_state == LPFC_LINK_DOWN))
+               status = phba->lpfc_hba_init_link(phba);
+       else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
+                       (phba->link_state >= LPFC_LINK_UP))
+               status = phba->lpfc_hba_down_link(phba);
+
+       if (status == 0)
+               return strlen(buf);
+       else
+               return status;
+}
+
 /**
  * lpfc_num_discovered_ports_show - Return sum of mapped and unmapped vports
  * @dev: class device that is converted into a Scsi_host.
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
        struct lpfc_hba   *phba = vport->phba;\
-       int val = 0;\
+       uint val = 0;\
        val = phba->cfg_##attr;\
        return snprintf(buf, PAGE_SIZE, "%d\n",\
                        phba->cfg_##attr);\
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
        struct lpfc_hba   *phba = vport->phba;\
-       int val = 0;\
+       uint val = 0;\
        val = phba->cfg_##attr;\
        return snprintf(buf, PAGE_SIZE, "%#x\n",\
                        phba->cfg_##attr);\
  **/
 #define lpfc_param_init(attr, default, minval, maxval) \
 static int \
-lpfc_##attr##_init(struct lpfc_hba *phba, int val) \
+lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
                phba->cfg_##attr = val;\
  **/
 #define lpfc_param_set(attr, default, minval, maxval)  \
 static int \
-lpfc_##attr##_set(struct lpfc_hba *phba, int val) \
+lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
                phba->cfg_##attr = val;\
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
        struct lpfc_hba   *phba = vport->phba;\
-       int val=0;\
+       uint val = 0;\
        if (!isdigit(buf[0]))\
                return -EINVAL;\
        if (sscanf(buf, "%i", &val) != 1)\
 { \
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
-       int val = 0;\
+       uint val = 0;\
        val = vport->cfg_##attr;\
        return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
 }
 { \
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
-       int val = 0;\
+       uint val = 0;\
        val = vport->cfg_##attr;\
        return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
 }
  **/
 #define lpfc_vport_param_init(attr, default, minval, maxval)   \
 static int \
-lpfc_##attr##_init(struct lpfc_vport *vport, int val) \
+lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
                vport->cfg_##attr = val;\
  **/
 #define lpfc_vport_param_set(attr, default, minval, maxval)    \
 static int \
-lpfc_##attr##_set(struct lpfc_vport *vport, int val) \
+lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
                vport->cfg_##attr = val;\
 { \
        struct Scsi_Host  *shost = class_to_shost(dev);\
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
-       int val=0;\
+       uint val = 0;\
        if (!isdigit(buf[0]))\
                return -EINVAL;\
        if (sscanf(buf, "%i", &val) != 1)\
 
 
 #define LPFC_ATTR(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_param_init(name, defval, minval, maxval)
 
 #define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_param_show(name)\
 lpfc_param_init(name, defval, minval, maxval)\
 static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
 
 #define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_param_show(name)\
 lpfc_param_init(name, defval, minval, maxval)\
                   lpfc_##name##_show, lpfc_##name##_store)
 
 #define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_param_hex_show(name)\
 lpfc_param_init(name, defval, minval, maxval)\
 static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
 
 #define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_param_hex_show(name)\
 lpfc_param_init(name, defval, minval, maxval)\
                   lpfc_##name##_show, lpfc_##name##_store)
 
 #define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_vport_param_init(name, defval, minval, maxval)
 
 #define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_vport_param_show(name)\
 lpfc_vport_param_init(name, defval, minval, maxval)\
 static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
 
 #define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_vport_param_show(name)\
 lpfc_vport_param_init(name, defval, minval, maxval)\
                   lpfc_##name##_show, lpfc_##name##_store)
 
 #define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_vport_param_hex_show(name)\
 lpfc_vport_param_init(name, defval, minval, maxval)\
 static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
 
 #define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
 MODULE_PARM_DESC(lpfc_##name, desc);\
 lpfc_vport_param_hex_show(name)\
 lpfc_vport_param_init(name, defval, minval, maxval)\
 static DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
 static DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
 static DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
-static DEVICE_ATTR(link_state, S_IRUGO, lpfc_link_state_show, NULL);
+static DEVICE_ATTR(link_state, S_IRUGO | S_IWUSR, lpfc_link_state_show,
+               lpfc_link_state_store);
 static DEVICE_ATTR(option_rom_version, S_IRUGO,
                   lpfc_option_rom_version_show, NULL);
 static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
 static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
                         lpfc_enable_npiv_show, NULL);
 
+/*
+# lpfc_suppress_link_up:  Bring link up at initialization
+#            0x0  = bring link up (issue MBX_INIT_LINK)
+#            0x1  = do NOT bring link up at initialization(MBX_INIT_LINK)
+#            0x2  = never bring up link
+# Default value is 0.
+*/
+LPFC_ATTR_R(suppress_link_up, 0, 0, 2, "Suppress Link Up at initialization");
+
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
 # until the timer expires. Value range is [0,255]. Default value is 30.
        &dev_attr_lpfc_prot_sg_seg_cnt,
        &dev_attr_lpfc_aer_support,
        &dev_attr_lpfc_aer_state_cleanup,
+       &dev_attr_lpfc_suppress_link_up,
        NULL,
 };
 
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
        lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
        lpfc_aer_support_init(phba, lpfc_aer_support);
-
+       lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
        return;
 }
 
 
                        mempool_free(pmb, phba->mbox_mem_pool);
                        return -EIO;
                }
-       } else {
+       } else if (phba->cfg_suppress_link_up == 0) {
                lpfc_init_link(phba, pmb, phba->cfg_topology,
                        phba->cfg_link_speed);
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        return 0;
 }
 
+/**
+ * lpfc_hba_init_link - Initialize the FC link
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine will issue the INIT_LINK mailbox command call.
+ * It is available to other drivers through the lpfc_hba data
+ * structure for use as a delayed link up mechanism with the
+ * module parameter lpfc_suppress_link_up.
+ *
+ * Return code
+ *             0 - success
+ *             Any other value - error
+ **/
+int
+lpfc_hba_init_link(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport = phba->pport;
+       LPFC_MBOXQ_t *pmb;
+       MAILBOX_t *mb;
+       int rc;
+
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return -ENOMEM;
+       }
+       mb = &pmb->u.mb;
+       pmb->vport = vport;
+
+       lpfc_init_link(phba, pmb, phba->cfg_topology,
+               phba->cfg_link_speed);
+       pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       lpfc_set_loopback_flag(phba);
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "0498 Adapter failed to init, mbxCmd x%x "
+                       "INIT_LINK, mbxStatus x%x\n",
+                       mb->mbxCommand, mb->mbxStatus);
+               /* Clear all interrupt enable conditions */
+               writel(0, phba->HCregaddr);
+               readl(phba->HCregaddr); /* flush */
+               /* Clear all pending interrupts */
+               writel(0xffffffff, phba->HAregaddr);
+               readl(phba->HAregaddr); /* flush */
+               phba->link_state = LPFC_HBA_ERROR;
+               if (rc != MBX_BUSY)
+                       mempool_free(pmb, phba->mbox_mem_pool);
+               return -EIO;
+       }
+       phba->cfg_suppress_link_up = 0;
+
+       return 0;
+}
+
+/**
+ * lpfc_hba_down_link - this routine downs the FC link
+ *
+ * This routine will issue the DOWN_LINK mailbox command call.
+ * It is available to other drivers through the lpfc_hba data
+ * structure for use to stop the link.
+ *
+ * Return code
+ *             0 - success
+ *             Any other value - error
+ **/
+int
+lpfc_hba_down_link(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *pmb;
+       int rc;
+
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return -ENOMEM;
+       }
+
+       lpfc_printf_log(phba,
+               KERN_ERR, LOG_INIT,
+               "0491 Adapter Link is disabled.\n");
+       lpfc_down_link(phba, pmb);
+       pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+       if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
+               lpfc_printf_log(phba,
+               KERN_ERR, LOG_INIT,
+               "2522 Adapter failed to issue DOWN_LINK"
+               " mbox command rc 0x%x\n", rc);
+
+               mempool_free(pmb, phba->mbox_mem_pool);
+               return -EIO;
+       }
+       return 0;
+}
+
 /**
  * lpfc_hba_down_prep - Perform lpfc uninitialization prior to HBA reset
  * @phba: pointer to lpfc HBA data structure.
 int
 lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
 {
+       phba->lpfc_hba_init_link = lpfc_hba_init_link;
+       phba->lpfc_hba_down_link = lpfc_hba_down_link;
        switch (dev_grp) {
        case LPFC_PCI_DEV_LP:
                phba->lpfc_hba_down_post = lpfc_hba_down_post_s3;