1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-28 11:57:28 +00:00
freebsd/sys/dev/twa/tw_cl_init.c
Vinod Kashyap ff1625c61d twa corresponding to the 9.3.0.1 release on the 3ware website. This driver has
support for the 9xxxSX controllers, along with the earlier 9xxxS series
controllers.
2005-11-08 22:51:43 +00:00

1239 lines
38 KiB
C

/*
* Copyright (c) 2004-05 Applied Micro Circuits Corporation.
* Copyright (c) 2004-05 Vinod Kashyap
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* AMCC'S 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
/*
* Common Layer initialization functions.
*/
#include "tw_osl_share.h"
#include "tw_cl_share.h"
#include "tw_cl_fwif.h"
#include "tw_cl_ioctl.h"
#include "tw_cl.h"
#include "tw_cl_externs.h"
#include "tw_osl_ioctl.h"
/*
* Function name: tw_cl_ctlr_supported
* Description: Determines if a controller is supported.
*
* Input: vendor_id -- vendor id of the controller
* device_id -- device id of the controller
* Output: None
* Return value: TW_CL_TRUE-- controller supported
* TW_CL_FALSE-- controller not supported
*/
TW_INT32
tw_cl_ctlr_supported(TW_INT32 vendor_id, TW_INT32 device_id)
{
if ((vendor_id == TW_CL_VENDOR_ID) &&
((device_id == TW_CL_DEVICE_ID_9K) ||
(device_id == TW_CL_DEVICE_ID_9K_X)))
return(TW_CL_TRUE);
return(TW_CL_FALSE);
}
/*
* Function name: tw_cl_get_pci_bar_info
* Description: Returns PCI BAR info.
*
* Input: device_id -- device id of the controller
* bar_type -- type of PCI BAR in question
* Output: bar_num -- PCI BAR number corresponding to bar_type
* bar0_offset -- byte offset from BAR 0 (0x10 in
* PCI config space)
* bar_size -- size, in bytes, of the BAR in question
* Return value: 0 -- success
* non-zero -- failure
*/
TW_INT32
tw_cl_get_pci_bar_info(TW_INT32 device_id, TW_INT32 bar_type,
TW_INT32 *bar_num, TW_INT32 *bar0_offset, TW_INT32 *bar_size)
{
TW_INT32 error = TW_OSL_ESUCCESS;
switch(device_id) {
case TW_CL_DEVICE_ID_9K:
switch(bar_type) {
case TW_CL_BAR_TYPE_IO:
*bar_num = 0;
*bar0_offset = 0;
*bar_size = 4;
break;
case TW_CL_BAR_TYPE_MEM:
*bar_num = 1;
*bar0_offset = 0x4;
*bar_size = 8;
break;
case TW_CL_BAR_TYPE_SBUF:
*bar_num = 2;
*bar0_offset = 0xC;
*bar_size = 8;
break;
}
break;
case TW_CL_DEVICE_ID_9K_X:
switch(bar_type) {
case TW_CL_BAR_TYPE_IO:
*bar_num = 2;
*bar0_offset = 0x10;
*bar_size = 4;
break;
case TW_CL_BAR_TYPE_MEM:
*bar_num = 1;
*bar0_offset = 0x8;
*bar_size = 8;
break;
case TW_CL_BAR_TYPE_SBUF:
*bar_num = 0;
*bar0_offset = 0;
*bar_size = 8;
break;
}
break;
default:
error = TW_OSL_ENOTTY;
break;
}
return(error);
}
/*
* Function name: tw_cl_get_mem_requirements
* Description: Provides info about Common Layer requirements for a
* controller, given the controller type (in 'flags').
* Input: ctlr_handle -- controller handle
* flags -- more info passed by the OS Layer
* device_id -- device id of the controller
* max_simult_reqs -- maximum # of simultaneous
* requests that the OS Layer expects
* the Common Layer to support
* max_aens -- maximun # of AEN's needed to be supported
* Output: alignment -- alignment needed for all DMA'able
* buffers
* sg_size_factor -- every SG element should have a size
* that's a multiple of this number
* non_dma_mem_size -- # of bytes of memory needed for
* non-DMA purposes
* dma_mem_size -- # of bytes of DMA'able memory needed
* flash_dma_mem_size -- # of bytes of DMA'able memory
* needed for firmware flash, if applicable
* per_req_dma_mem_size -- # of bytes of DMA'able memory
* needed per request, if applicable
* per_req_non_dma_mem_size -- # of bytes of memory needed
* per request for non-DMA purposes,
* if applicable
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cl_get_mem_requirements(struct tw_cl_ctlr_handle *ctlr_handle,
TW_UINT32 flags, TW_INT32 device_id, TW_INT32 max_simult_reqs,
TW_INT32 max_aens, TW_UINT32 *alignment, TW_UINT32 *sg_size_factor,
TW_UINT32 *non_dma_mem_size, TW_UINT32 *dma_mem_size
#ifdef TW_OSL_FLASH_FIRMWARE
, TW_UINT32 *flash_dma_mem_size
#endif /* TW_OSL_FLASH_FIRMWARE */
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
, TW_UINT32 *per_req_dma_mem_size
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
, TW_UINT32 *per_req_non_dma_mem_size
#endif /* TW_OSL_N0N_DMA_MEM_ALLOC_PER_REQUEST */
)
{
if (device_id == 0)
device_id = TW_CL_DEVICE_ID_9K;
if (max_simult_reqs > TW_CL_MAX_SIMULTANEOUS_REQUESTS) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1000, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Too many simultaneous requests to support!",
"requested = %d, supported = %d, error = %d\n",
max_simult_reqs, TW_CL_MAX_SIMULTANEOUS_REQUESTS,
TW_OSL_EBIG);
return(TW_OSL_EBIG);
}
*alignment = TWA_ALIGNMENT(device_id);
*sg_size_factor = TWA_SG_ELEMENT_SIZE_FACTOR(device_id);
/*
* Total non-DMA memory needed is the sum total of memory needed for
* the controller context, request packets (including the 1 needed for
* CL internal requests), and event packets.
*/
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
*non_dma_mem_size = sizeof(struct tw_cli_ctlr_context) +
(sizeof(struct tw_cli_req_context)) +
(sizeof(struct tw_cl_event_packet) * max_aens);
*per_req_non_dma_mem_size = sizeof(struct tw_cli_req_context);
#else /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
*non_dma_mem_size = sizeof(struct tw_cli_ctlr_context) +
(sizeof(struct tw_cli_req_context) * (max_simult_reqs + 1)) +
(sizeof(struct tw_cl_event_packet) * max_aens);
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
/*
* Total DMA'able memory needed is the sum total of memory needed for
* all command packets (including the 1 needed for CL internal
* requests), and memory needed to hold the payload for internal
* requests.
*/
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
*dma_mem_size = sizeof(struct tw_cl_command_packet) +
TW_CLI_SECTOR_SIZE;
*per_req_dma_mem_size = sizeof(struct tw_cl_command_packet);
#else /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
*dma_mem_size = (sizeof(struct tw_cl_command_packet) *
(max_simult_reqs + 1)) + (TW_CLI_SECTOR_SIZE);
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
#ifdef TW_OSL_FLASH_FIRMWARE
/* Memory needed to hold the firmware image while flashing. */
*flash_dma_mem_size =
((tw_cli_fw_img_size / TW_CLI_NUM_FW_IMAGE_CHUNKS) +
511) & ~511;
/* (TWA_SG_ELEMENT_SIZE_FACTOR(device_id) - 1)) &
~(TWA_SG_ELEMENT_SIZE_FACTOR(device_id) - 1); */
#endif /* TW_OSL_FLASH_FIRMWARE */
return(0);
}
/*
* Function name: tw_cl_init_ctlr
* Description: Initializes driver data structures for the controller.
*
* Input: ctlr_handle -- controller handle
* flags -- more info passed by the OS Layer
* device_id -- device id of the controller
* max_simult_reqs -- maximum # of simultaneous requests
* that the OS Layer expects the Common
* Layer to support
* max_aens -- maximun # of AEN's needed to be supported
* non_dma_mem -- ptr to allocated non-DMA memory
* dma_mem -- ptr to allocated DMA'able memory
* dma_mem_phys -- physical address of dma_mem
* flash_dma_mem -- ptr to allocated DMA'able memory
* needed for firmware flash, if applicable
* flash_dma_mem_phys -- physical address of flash_dma_mem
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags,
TW_INT32 device_id, TW_INT32 max_simult_reqs, TW_INT32 max_aens,
TW_VOID *non_dma_mem, TW_VOID *dma_mem, TW_UINT64 dma_mem_phys
#ifdef TW_OSL_FLASH_FIRMWARE
, TW_VOID *flash_dma_mem,
TW_UINT64 flash_dma_mem_phys
#endif /* TW_OSL_FLASH_FIRMWARE */
)
{
struct tw_cli_ctlr_context *ctlr;
struct tw_cli_req_context *req;
TW_UINT8 *free_non_dma_mem;
TW_INT32 error = TW_OSL_ESUCCESS;
TW_INT32 i;
tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), "entered");
if (flags & TW_CL_START_CTLR_ONLY) {
ctlr = (struct tw_cli_ctlr_context *)
(ctlr_handle->cl_ctlr_ctxt);
goto start_ctlr;
}
if (max_simult_reqs > TW_CL_MAX_SIMULTANEOUS_REQUESTS) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1000, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Too many simultaneous requests to support!",
"requested = %d, supported = %d, error = %d\n",
max_simult_reqs, TW_CL_MAX_SIMULTANEOUS_REQUESTS,
TW_OSL_EBIG);
return(TW_OSL_EBIG);
}
if ((non_dma_mem == TW_CL_NULL) || (dma_mem == TW_CL_NULL)
#ifdef TW_OSL_FLASH_FIRMWARE
|| ((flags & TW_CL_FLASH_FIRMWARE) ?
(flash_dma_mem == TW_CL_NULL) : TW_CL_FALSE)
#endif /* TW_OSL_FLASH_FIRMWARE */
) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1001, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Insufficient memory for Common Layer's internal usage",
"error = %d\n", TW_OSL_ENOMEM);
return(TW_OSL_ENOMEM);
}
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
tw_osl_memzero(non_dma_mem, sizeof(struct tw_cli_ctlr_context) +
sizeof(struct tw_cli_req_context) +
(sizeof(struct tw_cl_event_packet) * max_aens));
#else /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_memzero(non_dma_mem, sizeof(struct tw_cli_ctlr_context) +
(sizeof(struct tw_cli_req_context) * (max_simult_reqs + 1)) +
(sizeof(struct tw_cl_event_packet) * max_aens));
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
tw_osl_memzero(dma_mem,
sizeof(struct tw_cl_command_packet) +
TW_CLI_SECTOR_SIZE);
#else /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_memzero(dma_mem,
(sizeof(struct tw_cl_command_packet) *
(max_simult_reqs + 1)) +
TW_CLI_SECTOR_SIZE);
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
free_non_dma_mem = (TW_UINT8 *)non_dma_mem;
ctlr = (struct tw_cli_ctlr_context *)free_non_dma_mem;
free_non_dma_mem += sizeof(struct tw_cli_ctlr_context);
ctlr_handle->cl_ctlr_ctxt = ctlr;
ctlr->ctlr_handle = ctlr_handle;
ctlr->device_id = (TW_UINT32)device_id;
ctlr->arch_id = TWA_ARCH_ID(device_id);
ctlr->flags = flags;
ctlr->sg_size_factor = TWA_SG_ELEMENT_SIZE_FACTOR(device_id);
ctlr->max_simult_reqs = max_simult_reqs + 1;
ctlr->max_aens_supported = max_aens;
#ifdef TW_OSL_FLASH_FIRMWARE
ctlr->flash_dma_mem = flash_dma_mem;
ctlr->flash_dma_mem_phys = flash_dma_mem_phys;
#endif /* TW_OSL_FLASH_FIRMWARE */
/* Initialize queues of CL internal request context packets. */
tw_cli_req_q_init(ctlr, TW_CLI_FREE_Q);
tw_cli_req_q_init(ctlr, TW_CLI_BUSY_Q);
tw_cli_req_q_init(ctlr, TW_CLI_PENDING_Q);
tw_cli_req_q_init(ctlr, TW_CLI_COMPLETE_Q);
/* Initialize all locks used by CL. */
ctlr->gen_lock = &(ctlr->gen_lock_handle);
tw_osl_init_lock(ctlr_handle, "tw_cl_gen_lock", ctlr->gen_lock);
ctlr->io_lock = &(ctlr->io_lock_handle);
tw_osl_init_lock(ctlr_handle, "tw_cl_io_lock", ctlr->io_lock);
/*
* If 64 bit cmd pkt addresses are used, we will need to serialize
* writes to the hardware (across registers), since existing (G66)
* hardware will get confused if, for example, we wrote the low 32 bits
* of the cmd pkt address, followed by a response interrupt mask to the
* control register, followed by the high 32 bits of the cmd pkt
* address. It will then interpret the value written to the control
* register as the low cmd pkt address. So, for this case, we will
* make a note that we will need to synchronize control register writes
* with command register writes.
*/
if ((ctlr->flags & TW_CL_64BIT_ADDRESSES) &&
(ctlr->device_id == TW_CL_DEVICE_ID_9K)) {
ctlr->state |= TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED;
ctlr->intr_lock = ctlr->io_lock;
} else {
ctlr->intr_lock = &(ctlr->intr_lock_handle);
tw_osl_init_lock(ctlr_handle, "tw_cl_intr_lock",
ctlr->intr_lock);
}
/* Initialize CL internal request context packets. */
ctlr->req_ctxt_buf = (struct tw_cli_req_context *)free_non_dma_mem;
free_non_dma_mem += (sizeof(struct tw_cli_req_context) *
(
#ifndef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
max_simult_reqs +
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
1));
ctlr->cmd_pkt_buf = (struct tw_cl_command_packet *)dma_mem;
ctlr->cmd_pkt_phys = dma_mem_phys;
ctlr->internal_req_data = (TW_UINT8 *)
(ctlr->cmd_pkt_buf +
(
#ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
max_simult_reqs +
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
1));
ctlr->internal_req_data_phys = ctlr->cmd_pkt_phys +
(sizeof(struct tw_cl_command_packet) *
(
#ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
max_simult_reqs +
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
1));
for (i = 0;
i < (
#ifndef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
max_simult_reqs +
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
1); i++) {
req = &(ctlr->req_ctxt_buf[i]);
#ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
req->cmd_pkt = &(ctlr->cmd_pkt_buf[i]);
req->cmd_pkt_phys = ctlr->cmd_pkt_phys +
(i * sizeof(struct tw_cl_command_packet));
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
req->request_id = i;
req->ctlr = ctlr;
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
/* Insert request into the free queue. */
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
}
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
ctlr->free_req_head = i - 1;
ctlr->free_req_tail = i - 1;
for (; i < (max_simult_reqs + 1); i++)
ctlr->free_req_ids[i - 1] = i;
ctlr->num_free_req_ids = max_simult_reqs;
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
/* Initialize the AEN queue. */
ctlr->aen_queue = (struct tw_cl_event_packet *)free_non_dma_mem;
start_ctlr:
/*
* Disable interrupts. Interrupts will be enabled in tw_cli_start_ctlr
* (only) if initialization succeeded.
*/
tw_cli_disable_interrupts(ctlr);
/* Initialize the controller. */
if ((error = tw_cli_start_ctlr(ctlr))) {
/* Soft reset the controller, and try one more time. */
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1002, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller initialization failed. Retrying...",
"error = %d\n", error);
if ((error = tw_cli_soft_reset(ctlr))) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1003, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller soft reset failed",
"error = %d\n", error);
return(error);
} else if ((error = tw_cli_start_ctlr(ctlr))) {
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1004, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Controller initialization retry failed",
"error = %d\n", error);
return(error);
}
}
/* Notify some info about the controller to the OSL. */
tw_cli_notify_ctlr_info(ctlr);
/* Mark the controller as active. */
ctlr->state |= TW_CLI_CTLR_STATE_ACTIVE;
return(error);
}
#ifdef TW_OSL_FLASH_FIRMWARE
/*
* Function name: tw_cli_flash_firmware
* Description: Flashes bundled firmware image onto controller.
*
* Input: ctlr -- ptr to per ctlr structure
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cli_flash_firmware(struct tw_cli_ctlr_context *ctlr)
{
struct tw_cli_req_context *req;
struct tw_cl_command_header *cmd_hdr;
struct tw_cl_command_download_firmware *cmd;
TW_UINT32 fw_img_chunk_size;
TW_UINT32 num_chunks;
TW_UINT32 this_chunk_size = 0;
TW_INT32 remaining_img_size = 0;
TW_INT32 hard_reset_needed = TW_CL_FALSE;
TW_INT32 error = TW_OSL_EGENFAILURE;
TW_UINT32 i;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
if ((req = tw_cli_get_request(ctlr
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
, TW_CL_NULL
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
)) == TW_CL_NULL) {
/* No free request packets available. Can't proceed. */
error = TW_OSL_EBUSY;
goto out;
}
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
req->cmd_pkt = ctlr->cmd_pkt_buf;
req->cmd_pkt_phys = ctlr->cmd_pkt_phys;
tw_osl_memzero(req->cmd_pkt,
sizeof(struct tw_cl_command_header) +
28 /* max bytes before sglist */);
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
/*
* Determine amount of memory needed to hold a chunk of the
* firmware image. As yet, the Download_Firmware command does not
* support SG elements that are ctlr->sg_size_factor multiples. It
* requires them to be 512-byte multiples.
*/
fw_img_chunk_size = ((tw_cli_fw_img_size / TW_CLI_NUM_FW_IMAGE_CHUNKS) +
511) & ~511;
/* (ctlr->sg_size_factor - 1)) &
~(ctlr->sg_size_factor - 1); */
/* Calculate the actual number of chunks needed. */
num_chunks = (tw_cli_fw_img_size / fw_img_chunk_size) +
((tw_cli_fw_img_size % fw_img_chunk_size) ? 1 : 0);
req->data = ctlr->flash_dma_mem;
req->data_phys = ctlr->flash_dma_mem_phys;
remaining_img_size = tw_cli_fw_img_size;
cmd_hdr = &(req->cmd_pkt->cmd_hdr);
cmd = &(req->cmd_pkt->command.cmd_pkt_7k.download_fw);
for (i = 0; i < num_chunks; i++) {
/* Build a cmd pkt for downloading firmware. */
tw_osl_memzero(req->cmd_pkt,
sizeof(struct tw_cl_command_packet));
cmd_hdr->header_desc.size_header = 128;
/* sgl_offset (offset in dwords, to sg list) is 2. */
cmd->sgl_off__opcode =
BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_DOWNLOAD_FIRMWARE);
cmd->request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id));
cmd->unit = 0;
cmd->status = 0;
cmd->flags = 0;
cmd->param = TW_CL_SWAP16(8); /* prom image */
if (i != (num_chunks - 1))
this_chunk_size = fw_img_chunk_size;
else /* last chunk */
this_chunk_size = remaining_img_size;
remaining_img_size -= this_chunk_size;
tw_osl_memcpy(req->data, tw_cli_fw_img + (i * fw_img_chunk_size),
this_chunk_size);
/*
* The next line will effect only the last chunk.
*/
req->length = (this_chunk_size + 511) & ~511;
/* (ctlr->sg_size_factor - 1)) &
~(ctlr->sg_size_factor - 1); */
if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
((struct tw_cl_sg_desc64 *)(cmd->sgl))[0].address =
TW_CL_SWAP64(req->data_phys);
((struct tw_cl_sg_desc64 *)(cmd->sgl))[0].length =
TW_CL_SWAP32(req->length);
cmd->size = 2 + 3;
} else {
((struct tw_cl_sg_desc32 *)(cmd->sgl))[0].address =
TW_CL_SWAP32(req->data_phys);
((struct tw_cl_sg_desc32 *)(cmd->sgl))[0].length =
TW_CL_SWAP32(req->length);
cmd->size = 2 + 2;
}
error = tw_cli_submit_and_poll_request(req,
TW_CLI_REQUEST_TIMEOUT_PERIOD);
if (error) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1005, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Firmware flash request could not be posted",
"error = %d\n", error);
if (error == TW_OSL_ETIMEDOUT)
/* clean-up done by tw_cli_submit_and_poll_request */
return(error);
break;
}
error = cmd->status;
if (((i == (num_chunks - 1)) && (error)) ||
((i != (num_chunks - 1)) &&
((error = cmd_hdr->status_block.error) !=
TWA_ERROR_MORE_DATA))) {
/*
* It's either that download of the last chunk
* failed, or the download of one of the earlier
* chunks failed with an error other than
* TWA_ERROR_MORE_DATA. Report the error.
*/
tw_cli_create_ctlr_event(ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
cmd_hdr);
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1006, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Firmware flash failed",
"cmd = 0x%x, chunk # %d, cmd status = %d",
GET_OPCODE(cmd->sgl_off__opcode),
i, cmd->status);
/*
* Make a note to hard reset the controller,
* so that it doesn't wait for the remaining
* chunks. Don't call the hard reset function
* right here, since we have committed to having
* only 1 active internal request at a time, and
* this request has not yet been freed.
*/
hard_reset_needed = TW_CL_TRUE;
break;
}
} /* for */
out:
if (req)
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
if (hard_reset_needed)
tw_cli_hard_reset(ctlr);
return(error);
}
/*
* Function name: tw_cli_hard_reset
* Description: Hard resets the controller.
*
* Input: ctlr -- ptr to per ctlr structure
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cli_hard_reset(struct tw_cli_ctlr_context *ctlr)
{
struct tw_cli_req_context *req;
struct tw_cl_command_reset_firmware *cmd;
TW_INT32 error;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
if ((req = tw_cli_get_request(ctlr
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
, TW_CL_NULL
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
)) == TW_CL_NULL)
return(TW_OSL_EBUSY);
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
req->cmd_pkt = ctlr->cmd_pkt_buf;
req->cmd_pkt_phys = ctlr->cmd_pkt_phys;
tw_osl_memzero(req->cmd_pkt,
sizeof(struct tw_cl_command_header) +
28 /* max bytes before sglist */);
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
/* Build a cmd pkt for sending down the hard reset command. */
req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
cmd = &(req->cmd_pkt->command.cmd_pkt_7k.reset_fw);
cmd->res1__opcode =
BUILD_RES__OPCODE(0, TWA_FW_CMD_HARD_RESET_FIRMWARE);
cmd->size = 2;
cmd->request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id));
cmd->unit = 0;
cmd->status = 0;
cmd->flags = 0;
cmd->param = 0; /* don't reload FPGA logic */
req->data = TW_CL_NULL;
req->length = 0;
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1017, 0x3, TW_CL_SEVERITY_INFO_STRING,
"Issuing hard (commanded) reset to the controller...",
" ");
error = tw_cli_submit_and_poll_request(req,
TW_CLI_REQUEST_TIMEOUT_PERIOD);
if (error) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1007, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Hard reset request could not be posted",
"error = %d", error);
if (error == TW_OSL_ETIMEDOUT)
/* clean-up done by tw_cli_submit_and_poll_request */
return(error);
goto out;
}
if ((error = cmd->status)) {
tw_cli_create_ctlr_event(ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
&(req->cmd_pkt->cmd_hdr));
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1008, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Hard reset request failed",
"error = %d", error);
}
if (ctlr->device_id == TW_CL_DEVICE_ID_9K_X) {
/*
* There's a hardware bug in the G133 ASIC, which can lead to
* PCI parity errors and hangs, if the host accesses any
* registers when the firmware is resetting the hardware, as
* part of a hard/soft reset. The window of time when the
* problem can occur is about 10 ms. Here, we will handshake
* with the firmware to find out when the firmware is pulling
* down the hardware reset pin, and wait for about 500 ms to
* make sure we don't access any hardware registers (for
* polling) during that window.
*/
ctlr->state |= TW_CLI_CTLR_STATE_RESET_PHASE1_IN_PROGRESS;
while (tw_cli_find_response(ctlr,
TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) != TW_OSL_ESUCCESS)
tw_osl_delay(10);
tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000);
ctlr->state &= ~TW_CLI_CTLR_STATE_RESET_PHASE1_IN_PROGRESS;
}
/* Wait for the MC_RDY bit to get set. */
if ((error = tw_cli_poll_status(ctlr, TWA_STATUS_MICROCONTROLLER_READY,
TW_CLI_RESET_TIMEOUT_PERIOD))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
0x1018, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Micro-ctlr not ready following hard reset",
"error = %d", error);
}
out:
if (req)
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return(error);
}
#endif /* TW_OSL_FLASH_FIRMWARE */
/*
* Function name: tw_cli_start_ctlr
* Description: Establishes a logical connection with the controller.
* If bundled with firmware, determines whether or not
* to flash firmware, based on arch_id, fw SRL (Spec.
* Revision Level), branch & build #'s. Also determines
* whether or not the driver is compatible with the
* firmware on the controller, before proceeding to work
* with it.
*
* Input: ctlr -- ptr to per ctlr structure
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cli_start_ctlr(struct tw_cli_ctlr_context *ctlr)
{
TW_UINT16 fw_on_ctlr_srl = 0;
TW_UINT16 fw_on_ctlr_arch_id = 0;
TW_UINT16 fw_on_ctlr_branch = 0;
TW_UINT16 fw_on_ctlr_build = 0;
TW_UINT32 init_connect_result = 0;
TW_INT32 error = TW_OSL_ESUCCESS;
#ifdef TW_OSL_FLASH_FIRMWARE
TW_INT8 fw_flashed = TW_CL_FALSE;
TW_INT8 fw_flash_failed = TW_CL_FALSE;
#endif /* TW_OSL_FLASH_FIRMWARE */
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/* Wait for the controller to become ready. */
if ((error = tw_cli_poll_status(ctlr,
TWA_STATUS_MICROCONTROLLER_READY,
TW_CLI_REQUEST_TIMEOUT_PERIOD))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1009, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Microcontroller not ready",
"error = %d", error);
return(error);
}
/* Drain the response queue. */
if ((error = tw_cli_drain_response_queue(ctlr))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100A, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Can't drain response queue",
"error = %d", error);
return(error);
}
/* Establish a logical connection with the controller. */
if ((error = tw_cli_init_connection(ctlr,
(TW_UINT16)(ctlr->max_simult_reqs),
TWA_EXTENDED_INIT_CONNECT, TWA_CURRENT_FW_SRL,
(TW_UINT16)(ctlr->arch_id),
TWA_CURRENT_FW_BRANCH(ctlr->arch_id),
TWA_CURRENT_FW_BUILD(ctlr->arch_id),
&fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
&fw_on_ctlr_branch, &fw_on_ctlr_build,
&init_connect_result))) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100B, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Can't initialize connection in current mode",
"error = %d", error);
return(error);
}
#ifdef TW_OSL_FLASH_FIRMWARE
if ((ctlr->flags & TW_CL_FLASH_FIRMWARE) &&
(init_connect_result & TWA_BUNDLED_FW_SAFE_TO_FLASH) &&
(init_connect_result & TWA_CTLR_FW_RECOMMENDS_FLASH)) {
/*
* The bundled firmware is safe to flash, and the firmware
* on the controller recommends a flash. So, flash!
*/
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100C, 0x3, TW_CL_SEVERITY_INFO_STRING,
"Flashing bundled firmware...",
" ");
if ((error = tw_cli_flash_firmware(ctlr))) {
fw_flash_failed = TW_CL_TRUE;
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100D, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Unable to flash bundled firmware. "
"Attempting to work with fw on ctlr...",
" ");
} else {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100E, 0x3, TW_CL_SEVERITY_INFO_STRING,
"Successfully flashed bundled firmware",
" ");
fw_flashed = TW_CL_TRUE;
}
}
if (fw_flashed) {
/* The firmware was flashed. Have the new image loaded */
error = tw_cli_hard_reset(ctlr);
if (error)
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x100F, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Could not reset controller after flash!",
" ");
else /* Go through initialization again. */
error = tw_cli_start_ctlr(ctlr);
/*
* If hard reset of controller failed, we need to return.
* Otherwise, the above recursive call to tw_cli_start_ctlr
* will have completed the rest of the initialization (starting
* from tw_cli_drain_aen_queue below). Don't do it again.
* Just return.
*/
return(error);
} else
#endif /* TW_OSL_FLASH_FIRMWARE */
{
/*
* Either we are not bundled with a firmware image, or
* the bundled firmware is not safe to flash,
* or flash failed for some reason. See if we can at
* least work with the firmware on the controller in the
* current mode.
*/
if (init_connect_result & TWA_CTLR_FW_COMPATIBLE) {
/* Yes, we can. Make note of the operating mode. */
if (init_connect_result & TWA_CTLR_FW_SAME_OR_NEWER) {
ctlr->working_srl = TWA_CURRENT_FW_SRL;
ctlr->working_branch =
TWA_CURRENT_FW_BRANCH(ctlr->arch_id);
ctlr->working_build =
TWA_CURRENT_FW_BUILD(ctlr->arch_id);
} else {
ctlr->working_srl = fw_on_ctlr_srl;
ctlr->working_branch = fw_on_ctlr_branch;
ctlr->working_build = fw_on_ctlr_build;
}
} else {
/*
* No, we can't. See if we can at least work with
* it in the base mode. We should never come here
* if firmware has just been flashed.
*/
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1010, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Driver/Firmware mismatch. "
"Negotiating for base level...",
" ");
if ((error = tw_cli_init_connection(ctlr,
(TW_UINT16)(ctlr->max_simult_reqs),
TWA_EXTENDED_INIT_CONNECT,
TWA_BASE_FW_SRL,
(TW_UINT16)(ctlr->arch_id),
TWA_BASE_FW_BRANCH, TWA_BASE_FW_BUILD,
&fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
&fw_on_ctlr_branch, &fw_on_ctlr_build,
&init_connect_result))) {
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1011, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Can't initialize connection in "
"base mode",
" ");
return(error);
}
if (!(init_connect_result & TWA_CTLR_FW_COMPATIBLE)) {
/*
* The firmware on the controller is not even
* compatible with our base mode. We cannot
* work with it. Bail...
*/
#ifdef TW_OSL_FLASH_FIRMWARE
if (fw_flash_failed)
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1012, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Incompatible firmware on controller"
"...and could not flash bundled "
"firmware",
" ");
else
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1013, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Incompatible firmware on controller"
"...and bundled firmware not safe to "
"flash",
" ");
#endif /* TW_OSL_FLASH_FIRMWARE */
return(1);
}
/*
* We can work with this firmware, but only in
* base mode.
*/
ctlr->working_srl = TWA_BASE_FW_SRL;
ctlr->working_branch = TWA_BASE_FW_BRANCH;
ctlr->working_build = TWA_BASE_FW_BUILD;
ctlr->operating_mode = TWA_BASE_MODE;
}
ctlr->fw_on_ctlr_srl = fw_on_ctlr_srl;
ctlr->fw_on_ctlr_branch = fw_on_ctlr_branch;
ctlr->fw_on_ctlr_build = fw_on_ctlr_build;
}
/* Drain the AEN queue */
if ((error = tw_cli_drain_aen_queue(ctlr)))
/*
* We will just print that we couldn't drain the AEN queue.
* There's no need to bail out.
*/
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1014, 0x2, TW_CL_SEVERITY_WARNING_STRING,
"Can't drain AEN queue",
"error = %d", error);
/* Enable interrupts. */
tw_cli_enable_interrupts(ctlr);
return(TW_OSL_ESUCCESS);
}
/*
* Function name: tw_cl_shutdown_ctlr
* Description: Closes logical connection with the controller.
*
* Input: ctlr -- ptr to per ctlr structure
* flags -- more info passed by the OS Layer
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cl_shutdown_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags)
{
struct tw_cli_ctlr_context *ctlr =
(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
TW_INT32 error;
tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), "entered");
/*
* Mark the controller as inactive, disable any further interrupts,
* and notify the controller that we are going down.
*/
ctlr->state &= ~TW_CLI_CTLR_STATE_ACTIVE;
tw_cli_disable_interrupts(ctlr);
/* Let the controller know that we are going down. */
if ((error = tw_cli_init_connection(ctlr, TWA_SHUTDOWN_MESSAGE_CREDITS,
0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL,
TW_CL_NULL, TW_CL_NULL)))
tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1015, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Can't close connection with controller",
"error = %d", error);
if (flags & TW_CL_STOP_CTLR_ONLY)
goto ret;
/* Destroy all locks used by CL. */
tw_osl_destroy_lock(ctlr_handle, ctlr->gen_lock);
tw_osl_destroy_lock(ctlr_handle, ctlr->io_lock);
if (!(ctlr->flags & TW_CL_64BIT_ADDRESSES))
tw_osl_destroy_lock(ctlr_handle, ctlr->intr_lock);
ret:
return(error);
}
/*
* Function name: tw_cli_init_connection
* Description: Sends init_connection cmd to firmware
*
* Input: ctlr -- ptr to per ctlr structure
* message_credits -- max # of requests that we might send
* down simultaneously. This will be
* typically set to 256 at init-time or
* after a reset, and to 1 at shutdown-time
* set_features -- indicates if we intend to use 64-bit
* sg, also indicates if we want to do a
* basic or an extended init_connection;
*
* Note: The following input/output parameters are valid, only in case of an
* extended init_connection:
*
* current_fw_srl -- srl of fw we are bundled
* with, if any; 0 otherwise
* current_fw_arch_id -- arch_id of fw we are bundled
* with, if any; 0 otherwise
* current_fw_branch -- branch # of fw we are bundled
* with, if any; 0 otherwise
* current_fw_build -- build # of fw we are bundled
* with, if any; 0 otherwise
* Output: fw_on_ctlr_srl -- srl of fw on ctlr
* fw_on_ctlr_arch_id -- arch_id of fw on ctlr
* fw_on_ctlr_branch -- branch # of fw on ctlr
* fw_on_ctlr_build -- build # of fw on ctlr
* init_connect_result -- result bitmap of fw response
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_cli_init_connection(struct tw_cli_ctlr_context *ctlr,
TW_UINT16 message_credits, TW_UINT32 set_features,
TW_UINT16 current_fw_srl, TW_UINT16 current_fw_arch_id,
TW_UINT16 current_fw_branch, TW_UINT16 current_fw_build,
TW_UINT16 *fw_on_ctlr_srl, TW_UINT16 *fw_on_ctlr_arch_id,
TW_UINT16 *fw_on_ctlr_branch, TW_UINT16 *fw_on_ctlr_build,
TW_UINT32 *init_connect_result)
{
struct tw_cli_req_context *req;
struct tw_cl_command_init_connect *init_connect;
TW_INT32 error = TW_OSL_EBUSY;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/* Get a request packet. */
if ((req = tw_cli_get_request(ctlr
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
, TW_CL_NULL
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
)) == TW_CL_NULL)
goto out;
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
req->cmd_pkt = ctlr->cmd_pkt_buf;
req->cmd_pkt_phys = ctlr->cmd_pkt_phys;
tw_osl_memzero(req->cmd_pkt,
sizeof(struct tw_cl_command_header) +
28 /* max bytes before sglist */);
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
/* Build the cmd pkt. */
init_connect = &(req->cmd_pkt->command.cmd_pkt_7k.init_connect);
req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
init_connect->res1__opcode =
BUILD_RES__OPCODE(0, TWA_FW_CMD_INIT_CONNECTION);
init_connect->request_id =
(TW_UINT8)(TW_CL_SWAP16(req->request_id));
init_connect->message_credits = TW_CL_SWAP16(message_credits);
init_connect->features = TW_CL_SWAP32(set_features);
if (ctlr->flags & TW_CL_64BIT_ADDRESSES)
init_connect->features |= TWA_64BIT_SG_ADDRESSES;
if (set_features & TWA_EXTENDED_INIT_CONNECT) {
/*
* Fill in the extra fields needed for an extended
* init_connect.
*/
init_connect->size = 6;
init_connect->fw_srl = TW_CL_SWAP16(current_fw_srl);
init_connect->fw_arch_id = TW_CL_SWAP16(current_fw_arch_id);
init_connect->fw_branch = TW_CL_SWAP16(current_fw_branch);
init_connect->fw_build = TW_CL_SWAP16(current_fw_build);
} else
init_connect->size = 3;
/* Submit the command, and wait for it to complete. */
error = tw_cli_submit_and_poll_request(req,
TW_CLI_REQUEST_TIMEOUT_PERIOD);
if (error == TW_OSL_ETIMEDOUT)
/* Clean-up done by tw_cli_submit_and_poll_request. */
return(error);
if (error)
goto out;
if ((error = init_connect->status)) {
tw_cli_create_ctlr_event(ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
&(req->cmd_pkt->cmd_hdr));
goto out;
}
if (set_features & TWA_EXTENDED_INIT_CONNECT) {
*fw_on_ctlr_srl = TW_CL_SWAP16(init_connect->fw_srl);
*fw_on_ctlr_arch_id = TW_CL_SWAP16(init_connect->fw_arch_id);
*fw_on_ctlr_branch = TW_CL_SWAP16(init_connect->fw_branch);
*fw_on_ctlr_build = TW_CL_SWAP16(init_connect->fw_build);
*init_connect_result = TW_CL_SWAP32(init_connect->result);
}
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return(error);
out:
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1016, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"init_connection failed",
"error = %d", error);
if (req)
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return(error);
}