Mercurial > illumos > illumos-gate
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 */