changeset 10733:b95259752377

6870501 qlt driver needs quiesce support in dev_ops for fast reboot 6880832 Implement WWN setting function
author Daniel Beauregard <Daniel.Beauregard@Sun.COM>
date Wed, 07 Oct 2009 14:30:51 -0700
parents 498ac26a63d5
children 0622a203d039
files usr/src/uts/common/io/comstar/port/qlt/qlt.c usr/src/uts/common/io/comstar/port/qlt/qlt.h usr/src/uts/common/io/comstar/port/qlt/qlt_open.h usr/src/uts/common/io/comstar/port/qlt/qlt_regs.h
diffstat 4 files changed, 271 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt.c	Wed Oct 07 14:16:17 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt.c	Wed Oct 07 14:30:51 2009 -0700
@@ -78,10 +78,6 @@
 static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
 static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp);
 static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp);
-static fct_status_t qlt_reset_chip_and_download_fw(qlt_state_t *qlt,
-    int reset_only);
-static fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
-    uint32_t word_count, uint32_t risc_addr);
 static fct_status_t qlt_read_nvram(qlt_state_t *qlt);
 static void qlt_verify_fw(qlt_state_t *qlt);
 static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp);
@@ -145,11 +141,22 @@
 static int qlt_validate_trace_desc(qlt_state_t *qlt);
 static char *qlt_find_trace_start(qlt_state_t *qlt);
 
+static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval);
+static int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val);
+static int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop,
+    char **prop_val);
+static int qlt_convert_string_to_ull(char *prop, int radix,
+    u_longlong_t *result);
+static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt);
+static int qlt_quiesce(dev_info_t *dip);
+
 #define	SETELSBIT(bmp, els)	(bmp)[((els) >> 3) & 0x1F] = \
 	(uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7))
 
 int qlt_enable_msix = 0;
 
+string_table_t prop_status_tbl[] = DDI_PROP_STATUS();
+
 /* Array to quickly calculate next free buf index to use */
 #if 0
 static int qlt_nfb[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
@@ -184,7 +191,8 @@
 	nodev,
 	&qlt_cb_ops,
 	NULL,
-	ddi_power
+	ddi_power,
+	qlt_quiesce
 };
 
 #ifndef	PORT_SPEED_10G
@@ -284,12 +292,6 @@
 	return (mod_info(&modlinkage, modinfop));
 }
 
-int
-qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval)
-{
-	return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip,
-	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval));
-}
 
 static int
 qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
@@ -377,7 +379,9 @@
 		    (unsigned long long)ret);
 		goto attach_fail_5;
 	}
-
+	if (qlt_wwn_overload_prop(qlt) == TRUE) {
+		EL(qlt, "wwnn overloaded.\n", instance);
+	}
 	if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP,
 	    0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
 		goto attach_fail_5;
@@ -581,6 +585,46 @@
 	return (DDI_SUCCESS);
 }
 
+/*
+ * qlt_quiesce	quiesce a device attached to the system.
+ */
+static int
+qlt_quiesce(dev_info_t *dip)
+{
+	qlt_state_t	*qlt;
+	uint32_t	timer;
+	uint32_t	stat;
+
+	qlt = ddi_get_soft_state(qlt_state, ddi_get_instance(dip));
+	if (qlt == NULL) {
+		/* Oh well.... */
+		return (DDI_SUCCESS);
+	}
+
+	REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_HOST_TO_RISC_INTR);
+	REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE);
+	REG_WR32(qlt, REG_HCCR, HCCR_CMD_SET_HOST_TO_RISC_INTR);
+	for (timer = 0; timer < 30000; timer++) {
+		stat = REG_RD32(qlt, REG_RISC_STATUS);
+		if (stat & RISC_HOST_INTR_REQUEST) {
+			if ((stat & FW_INTR_STATUS_MASK) < 0x12) {
+				REG_WR32(qlt, REG_HCCR,
+				    HCCR_CMD_CLEAR_RISC_PAUSE);
+				break;
+			}
+			REG_WR32(qlt, REG_HCCR,
+			    HCCR_CMD_CLEAR_HOST_TO_RISC_INTR);
+		}
+		drv_usecwait(100);
+	}
+	/* Reset the chip. */
+	REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL |
+	    PCI_X_XFER_CTRL);
+	drv_usecwait(100);
+
+	return (DDI_SUCCESS);
+}
+
 static void
 qlt_enable_intr(qlt_state_t *qlt)
 {
@@ -2447,7 +2491,6 @@
 qlt_isr(caddr_t arg, caddr_t arg2)
 {
 	qlt_state_t	*qlt = (qlt_state_t *)arg;
-	int		instance;
 	uint32_t	risc_status, intr_type;
 	int		i;
 	int		intr_loop_count;
@@ -2495,7 +2538,6 @@
 	 * but we did not service it either because of max iterations.
 	 * Maybe offload the intr on a different thread.
 	 */
-	instance = ddi_get_instance(qlt->dip);
 	intr_loop_count = 0;
 
 	REG_WR32(qlt, REG_INTR_CTRL, 0);
@@ -2506,7 +2548,7 @@
 	if (risc_status & BIT_8) {
 		EL(qlt, "Risc Pause status=%xh\n", risc_status);
 		cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x",
-		    instance, risc_status);
+		    qlt->instance, risc_status);
 		(void) snprintf(info, 80, "Risc Pause %08x", risc_status);
 		info[79] = 0;
 		(void) fct_port_shutdown(qlt->qlt_port,
@@ -2516,7 +2558,14 @@
 
 	/* First check for high performance path */
 	intr_type = risc_status & 0xff;
-	if (intr_type == 0x1C) {
+	if (intr_type == 0x1D) {
+		qlt->atio_ndx_from_fw = (uint16_t)
+		    REG_RD32(qlt, REG_ATIO_IN_PTR);
+		REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_RISC_TO_PCI_INTR);
+		qlt->resp_ndx_from_fw = risc_status >> 16;
+		qlt_handle_atio_queue_update(qlt);
+		qlt_handle_resp_queue_update(qlt);
+	} else if (intr_type == 0x1C) {
 		REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_RISC_TO_PCI_INTR);
 		qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16);
 		qlt_handle_atio_queue_update(qlt);
@@ -2524,14 +2573,6 @@
 		REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_RISC_TO_PCI_INTR);
 		qlt->resp_ndx_from_fw = risc_status >> 16;
 		qlt_handle_resp_queue_update(qlt);
-		/* XXX what about priority queue */
-	} else if (intr_type == 0x1D) {
-		qlt->atio_ndx_from_fw = (uint16_t)
-		    REG_RD32(qlt, REG_ATIO_IN_PTR);
-		REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_RISC_TO_PCI_INTR);
-		qlt->resp_ndx_from_fw = risc_status >> 16;
-		qlt_handle_atio_queue_update(qlt);
-		qlt_handle_resp_queue_update(qlt);
 	} else if (intr_type == 0x12) {
 		uint16_t code = (uint16_t)(risc_status >> 16);
 		uint16_t mbox1 = REG_RD16(qlt, REG_MBOX(1));
@@ -2546,8 +2587,8 @@
 		    " mb3=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, mbox3,
 		    mbox5, mbox6);
 		cmn_err(CE_NOTE, "!qlt(%d): Async event %x mb1=%x mb2=%x,"
-		    " mb3=%x, mb5=%x, mb6=%x", instance, code, mbox1, mbox2,
-		    mbox3, mbox5, mbox6);
+		    " mb3=%x, mb5=%x, mb6=%x", qlt->instance, code, mbox1,
+		    mbox2, mbox3, mbox5, mbox6);
 
 		if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) {
 			if (qlt->qlt_link_up) {
@@ -2635,7 +2676,7 @@
 		if (qlt->mbox_io_state != MBOX_STATE_CMD_RUNNING) {
 			cmn_err(CE_WARN, "qlt(%d): mailbox completion received"
 			    " when driver wasn't waiting for it %d",
-			    instance, qlt->mbox_io_state);
+			    qlt->instance, qlt->mbox_io_state);
 		} else {
 			for (i = 0; i < MAX_MBOXES; i++) {
 				if (qlt->mcp->from_fw_mask &
@@ -2651,7 +2692,7 @@
 		mutex_exit(&qlt->mbox_lock);
 	} else {
 		cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x",
-		    instance, intr_type);
+		    qlt->instance, intr_type);
 		REG_WR32(qlt, REG_HCCR, HCCR_CMD_CLEAR_RISC_TO_PCI_INTR);
 	}
 
@@ -5925,8 +5966,8 @@
 	    qlt->el_trace_desc->next;
 
 	/*
-	 * if the buffer has not wrapped next will point at a null so
-	 * start is the beginning of the buffer.  if next points at a char
+	 * If the buffer has not wrapped next will point at a null so
+	 * start is the beginning of the buffer.  If next points at a char
 	 * then we must traverse the buffer until a null is detected and
 	 * that will be the beginning of the oldest whole object in the buffer
 	 * which is the start.
@@ -5943,3 +5984,127 @@
 	}
 	return (trace_start);
 }
+
+
+static int
+qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval)
+{
+	return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval));
+}
+
+static int
+qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val)
+{
+	return (ddi_prop_lookup_string(DDI_DEV_T_ANY, qlt->dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, prop_val));
+}
+
+static int
+qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop, char **prop_val)
+{
+	char		instance_prop[256];
+
+	/* Get adapter instance specific parameter. */
+	(void) sprintf(instance_prop, "hba%d-%s", qlt->instance, prop);
+	return (qlt_read_string_prop(qlt, instance_prop, prop_val));
+}
+
+static int
+qlt_convert_string_to_ull(char *prop, int radix,
+    u_longlong_t *result)
+{
+	return (ddi_strtoull((const char *)prop, 0, radix, result));
+}
+
+static boolean_t
+qlt_wwn_overload_prop(qlt_state_t *qlt)
+{
+	char		*prop_val = 0;
+	int		rval;
+	int		radix;
+	u_longlong_t	wwnn = 0, wwpn = 0;
+	boolean_t	overloaded = FALSE;
+
+	radix = 16;
+
+	rval = qlt_read_string_instance_prop(qlt, "adapter-wwnn", &prop_val);
+	if (rval == DDI_PROP_SUCCESS) {
+		rval = qlt_convert_string_to_ull(prop_val, radix, &wwnn);
+	}
+	if (rval == DDI_PROP_SUCCESS) {
+		rval = qlt_read_string_instance_prop(qlt, "adapter-wwpn",
+		    &prop_val);
+		if (rval == DDI_PROP_SUCCESS) {
+			rval = qlt_convert_string_to_ull(prop_val, radix,
+			    &wwpn);
+		}
+	}
+	if (rval == DDI_PROP_SUCCESS) {
+		overloaded = TRUE;
+		/* Overload the current node/port name nvram copy */
+		bcopy((char *)&wwnn, qlt->nvram->node_name, 8);
+		BIG_ENDIAN_64(qlt->nvram->node_name);
+		bcopy((char *)&wwpn, qlt->nvram->port_name, 8);
+		BIG_ENDIAN_64(qlt->nvram->port_name);
+	}
+	return (overloaded);
+}
+
+/*
+ * prop_text - Return a pointer to a string describing the status
+ *
+ * Input:	prop_status = the return status from a property function.
+ * Returns:	pointer to a string.
+ * Context:	Kernel context.
+ */
+char *
+prop_text(int prop_status)
+{
+	string_table_t *entry = &prop_status_tbl[0];
+
+	return (value2string(entry, prop_status, 0xFFFF));
+}
+
+/*
+ * value2string	Return a pointer to a string associated with the value
+ *
+ * Input:	entry = the value to string table
+ *		value = the value
+ * Returns:	pointer to a string.
+ * Context:	Kernel context.
+ */
+char *
+value2string(string_table_t *entry, int value, int delimiter)
+{
+	for (; entry->value != delimiter; entry++) {
+		if (entry->value == value) {
+			break;
+		}
+	}
+	return (entry->string);
+}
+
+/*
+ * qlt_chg_endian Change endianess of byte array.
+ *
+ * Input:	buf = array pointer.
+ *		size = size of array in bytes.
+ *
+ * Context:	Interrupt or Kernel context.
+ */
+void
+qlt_chg_endian(uint8_t buf[], size_t size)
+{
+	uint8_t byte;
+	size_t  cnt1;
+	size_t  cnt;
+
+	cnt1 = size - 1;
+	for (cnt = 0; cnt < size / 2; cnt++) {
+		byte = buf[cnt1];
+		buf[cnt1] = buf[cnt];
+		buf[cnt] = byte;
+		cnt1--;
+	}
+}
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt.h	Wed Oct 07 14:16:17 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt.h	Wed Oct 07 14:30:51 2009 -0700
@@ -351,6 +351,71 @@
 	DMEM_WR32(qlt, addr, (data & 0xffffffff)), \
 	DMEM_WR32(qlt, (addr)+4, ((uint64_t)data) >> 32)
 
+/*
+ * Structure used to associate values with strings which describe them.
+ */
+typedef struct string_table_entry {
+	uint32_t value;
+	char    *string;
+} string_table_t;
+
+char *prop_text(int prop_status);
+char *value2string(string_table_t *entry, int value, int delimiter);
+
+#define	PROP_STATUS_DELIMITER	((uint32_t)0xFFFF)
+
+#define	DDI_PROP_STATUS()					\
+{								\
+	{DDI_PROP_SUCCESS, "DDI_PROP_SUCCESS"},			\
+	{DDI_PROP_NOT_FOUND, "DDI_PROP_NOT_FOUND"},		\
+	{DDI_PROP_UNDEFINED, "DDI_PROP_UNDEFINED"},		\
+	{DDI_PROP_NO_MEMORY, "DDI_PROP_NO_MEMORY"},		\
+	{DDI_PROP_INVAL_ARG, "DDI_PROP_INVAL_ARG"},		\
+	{DDI_PROP_BUF_TOO_SMALL, "DDI_PROP_BUF_TOO_SMALL"},	\
+	{DDI_PROP_CANNOT_DECODE, "DDI_PROP_CANNOT_DECODE"},	\
+	{DDI_PROP_CANNOT_ENCODE, "DDI_PROP_CANNOT_ENCODE"},	\
+	{DDI_PROP_END_OF_DATA, "DDI_PROP_END_OF_DATA"},		\
+	{PROP_STATUS_DELIMITER, "DDI_PROP_UNKNOWN"}		\
+}
+
+#ifndef TRUE
+#define	TRUE	B_TRUE
+#endif
+
+#ifndef FALSE
+#define	FALSE	B_FALSE
+#endif
+
+/* Little endian machine correction defines. */
+#ifdef _LITTLE_ENDIAN
+#define	LITTLE_ENDIAN_16(x)
+#define	LITTLE_ENDIAN_24(x)
+#define	LITTLE_ENDIAN_32(x)
+#define	LITTLE_ENDIAN_64(x)
+#define	LITTLE_ENDIAN(bp, bytes)
+#define	BIG_ENDIAN_16(x)	qlt_chg_endian((uint8_t *)x, 2)
+#define	BIG_ENDIAN_24(x)	qlt_chg_endian((uint8_t *)x, 3)
+#define	BIG_ENDIAN_32(x)	qlt_chg_endian((uint8_t *)x, 4)
+#define	BIG_ENDIAN_64(x)	qlt_chg_endian((uint8_t *)x, 8)
+#define	BIG_ENDIAN(bp, bytes)	qlt_chg_endian((uint8_t *)bp, bytes)
+#endif /* _LITTLE_ENDIAN */
+
+/* Big endian machine correction defines. */
+#ifdef _BIG_ENDIAN
+#define	LITTLE_ENDIAN_16(x)		qlt_chg_endian((uint8_t *)x, 2)
+#define	LITTLE_ENDIAN_24(x)		qlt_chg_endian((uint8_t *)x, 3)
+#define	LITTLE_ENDIAN_32(x)		qlt_chg_endian((uint8_t *)x, 4)
+#define	LITTLE_ENDIAN_64(x)		qlt_chg_endian((uint8_t *)x, 8)
+#define	LITTLE_ENDIAN(bp, bytes)	qlt_chg_endian((uint8_t *)bp, bytes)
+#define	BIG_ENDIAN_16(x)
+#define	BIG_ENDIAN_24(x)
+#define	BIG_ENDIAN_32(x)
+#define	BIG_ENDIAN_64(x)
+#define	BIG_ENDIAN(bp, bytes)
+#endif /* _BIG_ENDIAN */
+
+void	qlt_chg_endian(uint8_t *, size_t);
+
 void qlt_el_msg(qlt_state_t *qlt, const char *fn, int ce, ...);
 void qlt_dump_el_trace_buffer(qlt_state_t *qlt);
 #define	EL(qlt, ...) 	qlt_el_msg(qlt, __func__, CE_CONT, __VA_ARGS__);
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt_open.h	Wed Oct 07 14:16:17 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt_open.h	Wed Oct 07 14:30:51 2009 -0700
@@ -45,7 +45,7 @@
 #endif
 
 #ifndef QLT_VERSION
-#define	QLT_VERSION	"20090814-1.01"
+#define	QLT_VERSION	"20090922-1.02"
 #endif
 
 #ifndef	QLT_NAME
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt_regs.h	Wed Oct 07 14:16:17 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt_regs.h	Wed Oct 07 14:30:51 2009 -0700
@@ -93,6 +93,14 @@
 #define	RISC_INTR_REQUEST	BIT_3
 
 /*
+ * RISC_STATUS register
+ */
+#define	RISC_HOST_INTR_REQUEST	BIT_15
+#define	RISC_PAUSED		BIT_08
+#define	FW_INTR_STATUS_MASK	(BIT_7 | BIT_6 | BIT_5 | BIT_4 | \
+    BIT_3 | BIT_2 | BIT_1 | BIT_0)
+
+/*
  * HCCR commands
  */
 #define	HCCR_CMD_NOP				0
@@ -104,6 +112,8 @@
 #define	HCCR_CMD_CLEAR_HOST_TO_RISC_INTR	0x60000000
 #define	HCCR_CMD_CLEAR_RISC_TO_PCI_INTR		0xA0000000
 
+#define	MBC_STOP_FIRMWARE	0x14
+
 /*
  * Flash/NVRAM definitions
  */