[SCSI] lpfc 8.1.2: Add ERROR and WARM_START modes for diagnostic purposes.

Add ERROR and WARM_START modes for diagnostic purposes.

Signed-off-by: Jamie Wellnitz <Jamie.Wellnitz@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index c8fb43d..e7aca3c 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2005 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -149,6 +149,8 @@
 	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
 	int len = 0;
 	switch (phba->hba_state) {
+	case LPFC_STATE_UNKNOWN:
+	case LPFC_WARM_START:
 	case LPFC_INIT_START:
 	case LPFC_INIT_MBX_CMDS:
 	case LPFC_LINK_DOWN:
@@ -279,6 +281,58 @@
 }
 
 static ssize_t
+lpfc_board_mode_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+	char  * state;
+
+	if (phba->hba_state == LPFC_HBA_ERROR)
+		state = "error";
+	else if (phba->hba_state == LPFC_WARM_START)
+		state = "warm start";
+	else if (phba->hba_state == LPFC_INIT_START)
+		state = "offline";
+	else
+		state = "online";
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", state);
+}
+
+static ssize_t
+lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+	struct completion online_compl;
+	int status=0;
+
+	init_completion(&online_compl);
+
+	if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+		lpfc_workq_post_event(phba, &status, &online_compl,
+				      LPFC_EVT_ONLINE);
+	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+		lpfc_workq_post_event(phba, &status, &online_compl,
+				      LPFC_EVT_OFFLINE);
+	else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
+		lpfc_workq_post_event(phba, &status, &online_compl,
+				      LPFC_EVT_WARM_START);
+ 	else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+		lpfc_workq_post_event(phba, &status, &online_compl,
+				      LPFC_EVT_KILL);
+	else
+		return -EINVAL;
+
+	wait_for_completion(&online_compl);
+
+	if (!status)
+		return strlen(buf);
+	else
+		return -EIO;
+}
+
+static ssize_t
 lpfc_poll_show(struct class_device *cdev, char *buf)
 {
 	struct Scsi_Host *host = class_to_shost(cdev);
@@ -480,6 +534,8 @@
 			 NULL);
 static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
 			 lpfc_board_online_show, lpfc_board_online_store);
+static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
+			 lpfc_board_mode_show, lpfc_board_mode_store);
 
 static int lpfc_poll = 0;
 module_param(lpfc_poll, int, 0);
@@ -674,6 +730,7 @@
 	&class_device_attr_nport_evt_cnt,
 	&class_device_attr_management_version,
 	&class_device_attr_board_online,
+	&class_device_attr_board_mode,
 	&class_device_attr_lpfc_poll,
 	&class_device_attr_lpfc_poll_tmo,
 	NULL,
@@ -883,8 +940,11 @@
 		case MBX_DUMP_MEMORY:
 		case MBX_DOWN_LOAD:
 		case MBX_UPDATE_CFG:
+		case MBX_KILL_BOARD:
 		case MBX_LOAD_AREA:
 		case MBX_LOAD_EXP_ROM:
+		case MBX_BEACON:
+		case MBX_DEL_LD_ENTRY:
 			break;
 		case MBX_READ_SPARM64:
 		case MBX_READ_LA:
@@ -1042,6 +1102,8 @@
 		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
 	else {
 		switch (phba->hba_state) {
+		case LPFC_STATE_UNKNOWN:
+		case LPFC_WARM_START:
 		case LPFC_INIT_START:
 		case LPFC_INIT_MBX_CMDS:
 		case LPFC_LINK_DOWN: